@Test public void testSuperClassConstructorParameters() throws InvalidProxyDescriptionException { @ProxyFor(superClass = "java.io.FileOutputStream", constructorParameterTypes = { "java.io.File" }) class Subject extends BasicSubject { } IProxyBuildPlan bp = ProxyBuildPlanImpl.create(Subject.class, "myname", ProxyBuildPlanImplTest.class.getClassLoader()); assertThat(bp.getConstructorParameterTypes().size(), equalTo(1)); assertThat(bp.getConstructorParameterTypes().get(0).getName(), equalTo("java.io.File")); }
/** * After the proxy class has been generated and injected, the static fields storing the * delegation targets have to be injected. This is done by this method. * * @param plan * the buildplan used for building the proxy * @param methodFields * the map mapping the proxied methods to their field names. * @param proxyClass * the generated and loaded proxy class. */ private void injectDelegationTargetFields(IProxyBuildPlan plan, Map<IMethodBuildPlan, String> methodFields, Class<?> proxyClass) { try { for (IMethodBuildPlan mplan : plan.getMethods()) { Field f = proxyClass.getDeclaredField(methodFields.get(mplan)); f.setAccessible(true); f.set(null, mplan.getTargetMethod()); } } catch (Exception e) { throw new RuntimeException(e); } }
/** * {@inheritDoc} */ @Override public IProxyClassInfo createProxyClass(IProxyBuildPlan plan) { String internalName = AsmUtil.getAsmInternalName(plan.getProxyClassName()); Type proxyType = Type.getObjectType(internalName); String[] interfaces = getInternalNames(plan.getImplementedInterfaces()); String superClass = Type.getInternalName(plan.getSuperClass()); // generate a new class for the proxy with the defined interfaces and superclass ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS); cw.visit(V1_5, ACC_PUBLIC, internalName, null, superClass, interfaces); // create the subject field cw.visitField(ACC_PUBLIC, SUBJECT_FIELD, IInstrumenterConstant.OBJECT_TYPE.getDescriptor(), null, null).visitEnd(); // create the fields for the delegation-target methods // The result map maps the proxied methods to their generated field's names Map<IMethodBuildPlan, String> methodFields = generateDelegationMethodTargetFields(plan, cw); generateConstructor(plan, proxyType, cw); // create the proxied methods for (Entry<IMethodBuildPlan, String> entry : methodFields.entrySet()) { createDelegationMethod(proxyType, entry.getKey(), entry.getValue(), cw); } cw.visitEnd(); byte[] bytecode = cw.toByteArray(); Class<?> cl = loadClass(bytecode, plan.getProxyClassName(), plan.getTargetClassLoader()); // inject the method fields injectDelegationTargetFields(plan, methodFields, cl); return new ASMProxyClassInfo(cl); }
paramTypes.addAll(plan.getConstructorParameterTypes()); Method superConstructor = new Method(IInstrumenterConstant.CONSTRUCTOR_INTERNAL_NAME, Type.VOID_TYPE, getTypes(plan.getConstructorParameterTypes())); GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, constructor, null, getTypes(plan.getConstructorExceptions()), cw); mg.loadArgs(1, plan.getConstructorParameterTypes().size()); mg.invokeConstructor(Type.getType(plan.getSuperClass()), superConstructor);
@Test public void testCorrectSuperClassAndInterfaces() throws InvalidProxyDescriptionException { @ProxyFor(superClass = "java.io.OutputStream", implementedInterfaces = { "java.lang.Runnable", "java.lang.Readable" }) class Subject extends BasicSubject { @ProxyMethod public void run() { } @ProxyMethod public int read(CharBuffer buf) { return 0; } @ProxyMethod public void write(int value) { } } IProxyBuildPlan bp = ProxyBuildPlanImpl.create(Subject.class, "myname", ProxyBuildPlanImplTest.class.getClassLoader()); assertThat(bp.getSuperClass().getName(), equalTo("java.io.OutputStream")); assertThat(bp.getImplementedInterfaces(), containsInAnyOrder(new Class<?>[] { java.lang.Runnable.class, java.lang.Readable.class })); }
@Test public void testDefaultSuperClass() throws InvalidProxyDescriptionException { @ProxyFor(implementedInterfaces = { "java.io.Closeable" }) class Subject extends BasicSubject { @ProxyMethod public void close() { } } IProxyBuildPlan bp = ProxyBuildPlanImpl.create(Subject.class, "myname", ProxyBuildPlanImplTest.class.getClassLoader()); assertThat(bp.getSuperClass().getName(), equalTo(Object.class.getName())); }
ClassLoader target = plan.getTargetClassLoader(); try { Class<?> proxyClazz = Class.forName(name, false, target);
/** * Generates the static fields of type java.lang.reflection.Method which store the delegation * targets. * * @param plan * the plan of the proxy to build. * @param cw * the classwriter to use. * @return a map mapping the individual proxied methods to their corresponding field names. */ private Map<IMethodBuildPlan, String> generateDelegationMethodTargetFields(IProxyBuildPlan plan, ClassWriter cw) { if (CollectionUtils.isEmpty(plan.getMethods())) { return Collections.emptyMap(); } Map<IMethodBuildPlan, String> methodFields = new HashMap<IMethodBuildPlan, String>(); int counter = 1; for (IMethodBuildPlan mplan : plan.getMethods()) { String name = METHOD_FIELD_PREFIX + counter; cw.visitField(ACC_STATIC, name, IInstrumenterConstant.REFLECTION_METHOD_TYPE.getDescriptor(), null, null).visitEnd(); methodFields.put(mplan, name); counter++; } return methodFields; }
@Test public void testMethodRenaming() throws InvalidProxyDescriptionException { @ProxyFor class Subject extends BasicSubject { @ProxyMethod(methodName = "equals") public boolean thisActuallyisEquals(Object other) { return false; } } IProxyBuildPlan bp = ProxyBuildPlanImpl.create(Subject.class, "myname", ProxyBuildPlanImplTest.class.getClassLoader()); assertThat(bp.getMethods().size(), equalTo(1)); assertThat(bp.getMethods().get(0).getMethodName(), equalTo("equals")); }
@Test public void testOptionalMethod() throws InvalidProxyDescriptionException { @ProxyFor class Subject extends BasicSubject { @ProxyMethod(parameterTypes = { "this.does.not.Exist" }, isOptional = true) public void methodWithMissingParameterType(Object param) { } } IProxyBuildPlan bp = ProxyBuildPlanImpl.create(Subject.class, "myname", ProxyBuildPlanImplTest.class.getClassLoader()); assertThat(bp.getMethods().size(), equalTo(0)); } }
@Test public void testReturnTypeCorrectCasting() throws InvalidProxyDescriptionException { @ProxyFor() class Subject extends BasicSubject { @ProxyMethod(returnType = "java.io.File") public Object castMe() { return null; } } IProxyBuildPlan bp = ProxyBuildPlanImpl.create(Subject.class, "myname", ProxyBuildPlanImplTest.class.getClassLoader()); assertThat(bp.getMethods().size(), equalTo(1)); assertThat(bp.getMethods().get(0).getReturnType().getName(), equalTo("java.io.File")); }
@Test public void testParameterCorrectCasting() throws InvalidProxyDescriptionException { @ProxyFor() class Subject extends BasicSubject { @ProxyMethod(parameterTypes = { "java.io.File" }) public void castMe(Object thisIsActuallyAFile) { } } IProxyBuildPlan bp = ProxyBuildPlanImpl.create(Subject.class, "myname", ProxyBuildPlanImplTest.class.getClassLoader()); assertThat(bp.getMethods().size(), equalTo(1)); assertThat(bp.getMethods().get(0).getParameterTypes().size(), equalTo(1)); assertThat(bp.getMethods().get(0).getParameterTypes().get(0).getName(), equalTo("java.io.File")); }