diff --git a/agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java b/agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java index 359ff78..6a7629e 100644 --- a/agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java +++ b/agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java @@ -39,7 +39,7 @@ public class SourceClassHandler extends BaseClassHandler { for (MethodNode m : cn.methods) { // record all member method names if (!ConstPool.CONSTRUCTOR.equals(m.name)) { - methods.add(new MethodInfo(cn.name, m.name, m.desc)); + methods.add(new MethodInfo(cn.name, m.name, null, m.desc)); } } // member methods which has injection stub @@ -59,18 +59,23 @@ public class SourceClassHandler extends BaseClassHandler { private void transformMethod(ClassNode cn, MethodNode mn, Set memberInjectMethods, Set newOperatorInjectMethods) { AbstractInsnNode[] instructions = mn.instructions.toArray(); + List memberInjectMethodList = new ArrayList(memberInjectMethods); int i = 0; do { if (invokeOps.contains(instructions[i].getOpcode())) { MethodInsnNode node = (MethodInsnNode)instructions[i]; - if (memberInjectMethods.contains(new MethodInfo(node.owner, node.name, node.desc))) { - // it's a member method of current class and an inject method for it exist + int index = memberInjectMethodList.indexOf(new MethodInfo(node.owner, node.name, null, node.desc)); + if (index >= 0) { + // it's a member method and an inject method for it exist int rangeStart = getMemberMethodStart(instructions, i); if (rangeStart >= 0) { if (cn.name.equals(node.owner)) { + // member method of current class instructions = replaceMemberCallOps(cn, mn, instructions, rangeStart, i); } else { - instructions = replaceCommonCallOps(cn, mn, instructions, node.owner, rangeStart, i); + // member method of other class + String method = memberInjectMethodList.get(index).getSubstitutionMethod(); + instructions = replaceCommonCallOps(cn, mn, instructions, node.owner, method, rangeStart, i); } i = rangeStart; } @@ -168,14 +173,14 @@ public class SourceClassHandler extends BaseClassHandler { } private AbstractInsnNode[] replaceCommonCallOps(ClassNode cn, MethodNode mn, AbstractInsnNode[] instructions, - String ownerClass, int start, int end) { + String ownerClass, String substitutionMethod, int start, int end) { mn.maxStack++; MethodInsnNode method = (MethodInsnNode)instructions[end]; String testClassName = ClassUtil.getTestClassName(cn.name); mn.instructions.insertBefore(instructions[start], new FieldInsnNode(GETSTATIC, testClassName, ConstPool.TESTABLE_INJECT_REF, ClassUtil.toByteCodeClassName(testClassName))); mn.instructions.insertBefore(instructions[end], new MethodInsnNode(INVOKEVIRTUAL, testClassName, - method.name, addFirstParameter(method.desc, ownerClass), false)); + substitutionMethod, addFirstParameter(method.desc, ownerClass), false)); mn.instructions.remove(instructions[end]); return mn.instructions.toArray(); } diff --git a/agent/src/main/java/com/alibaba/testable/agent/model/MethodInfo.java b/agent/src/main/java/com/alibaba/testable/agent/model/MethodInfo.java index 8906e94..68acfe1 100644 --- a/agent/src/main/java/com/alibaba/testable/agent/model/MethodInfo.java +++ b/agent/src/main/java/com/alibaba/testable/agent/model/MethodInfo.java @@ -5,13 +5,28 @@ package com.alibaba.testable.agent.model; */ public class MethodInfo { + /** + * name of the class this method belongs to + */ private final String clazz; + /** + * name of the method + */ private final String name; + /** + * name of the substitution method + * Note: this field do NOT join the `equals()` or `hashCode()` calculation + */ + private final String substitutionMethod; + /** + * parameter and return value of the method + */ private final String desc; - public MethodInfo(String clazz, String name, String desc) { + public MethodInfo(String clazz, String name, String substitutionMethod, String desc) { this.clazz = clazz; this.name = name; + this.substitutionMethod = substitutionMethod; this.desc = desc; } @@ -23,6 +38,10 @@ public class MethodInfo { return name; } + public String getSubstitutionMethod() { + return substitutionMethod; + } + public String getDesc() { return desc; } diff --git a/agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java b/agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java index c1b9df6..2f3086d 100644 --- a/agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java +++ b/agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java @@ -86,12 +86,15 @@ public class TestableClassTransformer implements ClassFileTransformer { String targetClass = getAnnotationParameter(an, TARGET_CLASS, sourceClassName); String targetMethod = getAnnotationParameter(an, TARGET_METHOD, mn.name); if (sourceClassName.equals(targetClass)) { - methodInfos.add(new MethodInfo(toSlashSeparatedName(targetClass), targetMethod, mn.desc)); + // member method of the source class + methodInfos.add(new MethodInfo( + toSlashSeparatedName(targetClass), targetMethod, null, mn.desc)); } else { + // member method of a common class ImmutablePair methodDescPair = extractFirstParameter(mn.desc); if (methodDescPair != null && methodDescPair.left.equals(ClassUtil.toByteCodeClassName(targetClass))) { methodInfos.add(new MethodInfo( - toSlashSeparatedName(targetClass), targetMethod, methodDescPair.right)); + toSlashSeparatedName(targetClass), targetMethod, mn.name, methodDescPair.right)); } } break;