MimicCreator { public void mimicMethods(CtClass src, CtClass dst, MimicMode defaultMimicMode, MimicMethod[] mimicMethods) throws MimicException, CannotCompileException, NotFoundException { HashMap<String, MimicMode> mapNameToMimicMode = buildMimicModeMethodMap(mimicMethods); HashMap<String, String> mapNameToInsertionMethod = buildInsertionMethodMap(mimicMethods); for (final CtMethod method : src.getDeclaredMethods()) { log.fine("Mimic method " + method.getName()); boolean destHasSameMethod = false; for (CtMethod methodInDest : dst.getDeclaredMethods()) { String signature = method.getSignature() + method.getName(); String signatureInDest = methodInDest.getSignature() + methodInDest.getName(); if (signatureInDest.equals(signature)) { destHasSameMethod = true; log.fine("Forwarding " + method.getName()); String key = this.key == null ? "" : (this.key + "_"); final String copiedMethodName = "_copy_" + key + method.getName(); dst.addMethod(CtNewMethod.copy(method, copiedMethodName, dst, null)); CtMethod insertionMethod = null; MimicMode mimicMode = defaultMimicMode; if (mapNameToMimicMode.containsKey(method.getName())) { mimicMode = mapNameToMimicMode.get(method.getName()); String insertionMethodName = mapNameToInsertionMethod.get(method.getName()); insertionMethod = findMethod(dst, insertionMethod, insertionMethodName); } log.fine("Mimic mode " + mimicMode); switch (mimicMode) { case AT_BEGINNING: methodInDest.insertBefore(createInvocation(methodInDest, copiedMethodName)); break; case BEFORE_RETURN: String returnString = method.getReturnType() == null ? "" : "return "; methodInDest.insertAfter(returnString + createInvocation(methodInDest, copiedMethodName)); break; case BEFORE: case AFTER: ReplaceExprEditor editor = new ReplaceExprEditor(copiedMethodName, method, insertionMethod, mimicMode); methodInDest.instrument(editor); if (!editor.isSuccessful()) { throw new MimicException("No replacement for method:" + method.getName() + " with insertion AFTER " + (insertionMethod == null ? "insertion method is null" : insertionMethod.getName())); } break; case BEFORE_SUPER: case AFTER_SUPER: case REPLACE_SUPER: ReplaceExprEditor editor2 = new ReplaceExprEditor(copiedMethodName, method, mimicMode); methodInDest.instrument(editor2); if (!editor2.isSuccessful()) { throw new MimicException("No replacement for method:" + method.getName() + " with insertion REPLACE_SUPER "); } break; default: break; } } } if (!destHasSameMethod) { log.fine("Copying " + method.getName()); dst.addMethod(CtNewMethod.copy(method, dst, null)); } } } MimicCreator();  MimicCreator(String key); boolean hasField(CtClass clazz, CtField field); boolean hasInterface(CtClass dst, CtClass interfazz); void mimicClass(CtClass src, CtClass dst, MimicMode defaultMimicMode, MimicMethod[] mimicMethods); void mimicConstructors(CtClass src, CtClass dst); void mimicFields(CtClass src, CtClass dst); void mimicInterfaces(CtClass src, CtClass dst); void mimicMethods(CtClass src, CtClass dst, MimicMode defaultMimicMode, MimicMethod[] mimicMethods);  }
@Test(expected=MimicException.class) public void testMimicMethods_with_same_methods_with_before_super_but_not_calling_super() throws Exception { src.addField(new CtField(CtClass.intType, "foo", src)); src.addMethod(CtNewMethod.make("public boolean foo() { foo = 2; return false ; }", src)); CtClass dstAncestor = ClassPool.getDefault().makeClass("DstAncestor" + TestCounter.testCounter); CtField field = new CtField(CtClass.intType, "foo", dstAncestor); field.setModifiers(Modifier.PUBLIC); dstAncestor.addField(field); dstAncestor.addMethod(CtNewMethod.make("public boolean foo(int a) { foo *= 2; return true; }", dstAncestor)); dstAncestor.addConstructor(CtNewConstructor.make("public " + dstAncestor.getName() + "() {}", dstAncestor)); dst.setSuperclass(dstAncestor); dst.addMethod(CtNewMethod.make("public boolean foo() { foo = 1; return foo(1);}", dst)); dstAncestor.toClass(); mimicCreator.mimicMethods(src, dst, MimicMode.BEFORE_SUPER, new MimicMethod[0]); Class<?> dstClass = dst.toClass(); assertHasFooField(dst); Object dstInstance = dstClass.newInstance(); invokeFoo(dstInstance); assertHasFooField(dstInstance, 2); assertHasFooMethod(dst, dstClass); }
@Test public void testMimicMethods_with_same_methods_with_after_super() throws Exception { src.addField(new CtField(CtClass.intType, "foo", src)); src.addMethod(CtNewMethod.make("public void foo() { foo = 3; }", src)); CtClass dstAncestor = ClassPool.getDefault().makeClass("DstAncestor" + TestCounter.testCounter); CtField field = new CtField(CtClass.intType, "foo", dstAncestor); field.setModifiers(Modifier.PUBLIC); dstAncestor.addField(field); dstAncestor.addMethod(CtNewMethod.make("protected void foo() { foo *=2; }", dstAncestor)); dstAncestor.addConstructor(CtNewConstructor.make("public " + dstAncestor.getName() + "() {}", dstAncestor)); dst.setSuperclass(dstAncestor); dst.addMethod(CtNewMethod.make("public void foo() { foo = 2; super.foo(); }", dst)); dstAncestor.toClass(); mimicCreator.mimicMethods(src, dst, MimicMode.AFTER_SUPER, new MimicMethod[0]); Class<?> dstClass = dst.toClass(); assertHasFooField(dst); Object dstInstance = dstClass.newInstance(); invokeFoo(dstInstance); assertHasFooField(dstInstance, 3); }
@Test(expected=MimicException.class) public void testMimicMethods_with_same_methods_with_after_super_but_not_calling_super() throws Exception { src.addField(new CtField(CtClass.intType, "foo", src)); src.addMethod(CtNewMethod.make("public void foo() { foo = 3; }", src)); CtClass dstAncestor = ClassPool.getDefault().makeClass("DstAncestor" + TestCounter.testCounter); CtField field = new CtField(CtClass.intType, "foo", dstAncestor); field.setModifiers(Modifier.PUBLIC); dstAncestor.addField(field); dstAncestor.addMethod(CtNewMethod.make("protected void foo(int a) { foo *=2; }", dstAncestor)); dstAncestor.addConstructor(CtNewConstructor.make("public " + dstAncestor.getName() + "() {}", dstAncestor)); dst.setSuperclass(dstAncestor); dst.addMethod(CtNewMethod.make("public void foo() { foo = 2; foo(1); }", dst)); dstAncestor.toClass(); mimicCreator.mimicMethods(src, dst, MimicMode.AFTER_SUPER, new MimicMethod[0]); Class<?> dstClass = dst.toClass(); assertHasFooField(dst); Object dstInstance = dstClass.newInstance(); invokeFoo(dstInstance); assertHasFooField(dstInstance, 4); }
@Test public void testMimicMethods_with_same_methods_with_after() throws Exception { src.addField(new CtField(CtClass.intType, "foo", src)); src.addMethod(CtNewMethod.make("public void foo() { foo = 4; }", src)); dst.addField(new CtField(CtClass.intType, "foo", dst)); dst.addMethod(CtNewMethod.make("public void bar() { foo = 3; }", dst)); dst.addMethod(CtNewMethod.make("public void foo() { foo = 2; bar(); }", dst)); MimicMethod mimicMethod = createMimicMethod(MimicMode.AFTER, "foo", "bar"); mimicCreator.mimicMethods(src, dst, MimicMode.AFTER, new MimicMethod[] { mimicMethod }); Class<?> dstClass = dst.toClass(); assertHasFooField(dst); Object dstInstance = dstClass.newInstance(); invokeFoo(dstInstance); assertHasFooField(dstInstance, 4); }
@Test public void testMimicMethods_with_same_methods_with_before() throws Exception { src.addField(new CtField(CtClass.intType, "foo", src)); src.addMethod(CtNewMethod.make("public void foo() { foo = 4; }", src)); dst.addField(new CtField(CtClass.intType, "foo", dst)); dst.addMethod(CtNewMethod.make("public void bar() { foo *= 2 ; }", dst)); dst.addMethod(CtNewMethod.make("public void foo() { foo = 2; bar(); }", dst)); MimicMethod mimicMethod = createMimicMethod(MimicMode.BEFORE, "foo", "bar"); mimicCreator.mimicMethods(src, dst, MimicMode.BEFORE, new MimicMethod[] { mimicMethod }); Class<?> dstClass = dst.toClass(); assertHasFooField(dst); Object dstInstance = dstClass.newInstance(); invokeFoo(dstInstance); assertHasFooField(dstInstance, 8); }
@Test public void testMimicMethods_with_same_methods_in_super_class_with_before() throws Exception { src.addField(new CtField(CtClass.intType, "foo", src)); src.addMethod(CtNewMethod.make("public void foo() { foo = 4; }", src)); CtClass dstAncestor = ClassPool.getDefault().makeClass("DstAncestor" + TestCounter.testCounter); CtField field = new CtField(CtClass.intType, "foo", dstAncestor); field.setModifiers(Modifier.PUBLIC); dstAncestor.addField(field); dstAncestor.addMethod(CtNewMethod.make("public void bar() {}", dstAncestor)); dstAncestor.addConstructor(CtNewConstructor.make("public " + dstAncestor.getName() + "() {}", dstAncestor)); dst.setSuperclass(dstAncestor); dst.addField(new CtField(CtClass.intType, "foo", dst)); dst.addMethod(CtNewMethod.make("public void foo() { foo = 2; bar(); }", dst)); MimicMethod mimicMethod = createMimicMethod(MimicMode.BEFORE, "foo", "bar"); mimicCreator.mimicMethods(src, dst, MimicMode.BEFORE, new MimicMethod[] { mimicMethod }); dstAncestor.toClass(); Class<?> dstClass = dst.toClass(); assertHasFooField(dst); Object dstInstance = dstClass.newInstance(); invokeFoo(dstInstance); assertHasFooField(dstInstance, 4); }
@Test public void testMimicMethods_with_same_methods_with_at_beginning() throws Exception { src.addField(new CtField(CtClass.intType, "foo", src)); src.addMethod(CtNewMethod.make("public void foo() { foo = 3; }", src)); CtField field = new CtField(CtClass.intType, "foo", dst); dst.addField(field); dst.addMethod(CtNewMethod.make("public void foo() { foo *= 2; }", dst)); mimicCreator.mimicMethods(src, dst, MimicMode.AT_BEGINNING, new MimicMethod[0]); Class<?> dstClass = dst.toClass(); assertHasFooField(dst); Object dstInstance = dstClass.newInstance(); invokeFoo(dstInstance); assertHasFooField(dstInstance, 6); }
@Test public void testMimicMethods_with_key() throws Exception { mimicCreator = new MimicCreator("bar"); src.addMethod(CtNewMethod.make("public boolean foo() { return true;}", src)); dst.addMethod(CtNewMethod.make("public boolean foo() { return true;}", dst)); mimicCreator.mimicMethods(src, dst, MimicMode.BEFORE_RETURN, new MimicMethod[0]); assertHasMethod(dst.toClass(), "_copy_bar_foo", null); }
@Test(expected=MimicException.class) public void testMimicMethods_with_empty_after() throws Exception { mimicCreator = new MimicCreator("bar"); src.addMethod(CtNewMethod.make("public boolean foo() { return true;}", src)); dst.addMethod(CtNewMethod.make("public boolean foo() { return true;}", dst)); mimicCreator.mimicMethods(src, dst, MimicMode.AFTER, new MimicMethod[0]); }
@Test public void testMimicMethods() throws Exception { src.addMethod(CtNewMethod.make("public boolean foo() { return true;}", src)); mimicCreator.mimicMethods(src, dst, MimicMode.AFTER_SUPER, new MimicMethod[0]); Class<?> dstClass = dst.toClass(); assertHasFooMethod(dst, dstClass); }
@Test public void testMimicMethods_with_same_methods_with_before_super() throws Exception { src.addField(new CtField(CtClass.intType, "foo", src)); src.addMethod(CtNewMethod.make("public boolean foo() { foo = 2; return false ; }", src)); CtClass dstAncestor = ClassPool.getDefault().makeClass("DstAncestor" + TestCounter.testCounter); CtField field = new CtField(CtClass.intType, "foo", dstAncestor); field.setModifiers(Modifier.PUBLIC); dstAncestor.addField(field); dstAncestor.addMethod(CtNewMethod.make("public boolean foo() { foo *= 2; return true; }", dstAncestor)); dstAncestor.addConstructor(CtNewConstructor.make("public " + dstAncestor.getName() + "() {}", dstAncestor)); dst.setSuperclass(dstAncestor); dst.addMethod(CtNewMethod.make("public boolean foo() { foo = 1; return super.foo();}", dst)); dstAncestor.toClass(); mimicCreator.mimicMethods(src, dst, MimicMode.BEFORE_SUPER, new MimicMethod[0]); Class<?> dstClass = dst.toClass(); assertHasFooField(dst); Object dstInstance = dstClass.newInstance(); invokeFoo(dstInstance); assertHasFooField(dstInstance, 4); assertHasFooMethod(dst, dstClass); }