mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-11 04:40:12 +08:00
support targetMethod parameter of TestableInject annotation
This commit is contained in:
parent
64227f1ed0
commit
c869caa0c9
@ -39,7 +39,7 @@ public class SourceClassHandler extends BaseClassHandler {
|
|||||||
for (MethodNode m : cn.methods) {
|
for (MethodNode m : cn.methods) {
|
||||||
// record all member method names
|
// record all member method names
|
||||||
if (!ConstPool.CONSTRUCTOR.equals(m.name)) {
|
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
|
// member methods which has injection stub
|
||||||
@ -59,18 +59,23 @@ public class SourceClassHandler extends BaseClassHandler {
|
|||||||
private void transformMethod(ClassNode cn, MethodNode mn, Set<MethodInfo> memberInjectMethods,
|
private void transformMethod(ClassNode cn, MethodNode mn, Set<MethodInfo> memberInjectMethods,
|
||||||
Set<MethodInfo> newOperatorInjectMethods) {
|
Set<MethodInfo> newOperatorInjectMethods) {
|
||||||
AbstractInsnNode[] instructions = mn.instructions.toArray();
|
AbstractInsnNode[] instructions = mn.instructions.toArray();
|
||||||
|
List<MethodInfo> memberInjectMethodList = new ArrayList<MethodInfo>(memberInjectMethods);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
do {
|
do {
|
||||||
if (invokeOps.contains(instructions[i].getOpcode())) {
|
if (invokeOps.contains(instructions[i].getOpcode())) {
|
||||||
MethodInsnNode node = (MethodInsnNode)instructions[i];
|
MethodInsnNode node = (MethodInsnNode)instructions[i];
|
||||||
if (memberInjectMethods.contains(new MethodInfo(node.owner, node.name, node.desc))) {
|
int index = memberInjectMethodList.indexOf(new MethodInfo(node.owner, node.name, null, node.desc));
|
||||||
// it's a member method of current class and an inject method for it exist
|
if (index >= 0) {
|
||||||
|
// it's a member method and an inject method for it exist
|
||||||
int rangeStart = getMemberMethodStart(instructions, i);
|
int rangeStart = getMemberMethodStart(instructions, i);
|
||||||
if (rangeStart >= 0) {
|
if (rangeStart >= 0) {
|
||||||
if (cn.name.equals(node.owner)) {
|
if (cn.name.equals(node.owner)) {
|
||||||
|
// member method of current class
|
||||||
instructions = replaceMemberCallOps(cn, mn, instructions, rangeStart, i);
|
instructions = replaceMemberCallOps(cn, mn, instructions, rangeStart, i);
|
||||||
} else {
|
} 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;
|
i = rangeStart;
|
||||||
}
|
}
|
||||||
@ -168,14 +173,14 @@ public class SourceClassHandler extends BaseClassHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AbstractInsnNode[] replaceCommonCallOps(ClassNode cn, MethodNode mn, AbstractInsnNode[] instructions,
|
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++;
|
mn.maxStack++;
|
||||||
MethodInsnNode method = (MethodInsnNode)instructions[end];
|
MethodInsnNode method = (MethodInsnNode)instructions[end];
|
||||||
String testClassName = ClassUtil.getTestClassName(cn.name);
|
String testClassName = ClassUtil.getTestClassName(cn.name);
|
||||||
mn.instructions.insertBefore(instructions[start], new FieldInsnNode(GETSTATIC, testClassName,
|
mn.instructions.insertBefore(instructions[start], new FieldInsnNode(GETSTATIC, testClassName,
|
||||||
ConstPool.TESTABLE_INJECT_REF, ClassUtil.toByteCodeClassName(testClassName)));
|
ConstPool.TESTABLE_INJECT_REF, ClassUtil.toByteCodeClassName(testClassName)));
|
||||||
mn.instructions.insertBefore(instructions[end], new MethodInsnNode(INVOKEVIRTUAL, 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]);
|
mn.instructions.remove(instructions[end]);
|
||||||
return mn.instructions.toArray();
|
return mn.instructions.toArray();
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,28 @@ package com.alibaba.testable.agent.model;
|
|||||||
*/
|
*/
|
||||||
public class MethodInfo {
|
public class MethodInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* name of the class this method belongs to
|
||||||
|
*/
|
||||||
private final String clazz;
|
private final String clazz;
|
||||||
|
/**
|
||||||
|
* name of the method
|
||||||
|
*/
|
||||||
private final String name;
|
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;
|
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.clazz = clazz;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.substitutionMethod = substitutionMethod;
|
||||||
this.desc = desc;
|
this.desc = desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,6 +38,10 @@ public class MethodInfo {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSubstitutionMethod() {
|
||||||
|
return substitutionMethod;
|
||||||
|
}
|
||||||
|
|
||||||
public String getDesc() {
|
public String getDesc() {
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
@ -86,12 +86,15 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
String targetClass = getAnnotationParameter(an, TARGET_CLASS, sourceClassName);
|
String targetClass = getAnnotationParameter(an, TARGET_CLASS, sourceClassName);
|
||||||
String targetMethod = getAnnotationParameter(an, TARGET_METHOD, mn.name);
|
String targetMethod = getAnnotationParameter(an, TARGET_METHOD, mn.name);
|
||||||
if (sourceClassName.equals(targetClass)) {
|
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 {
|
} else {
|
||||||
|
// member method of a common class
|
||||||
ImmutablePair<String, String> methodDescPair = extractFirstParameter(mn.desc);
|
ImmutablePair<String, String> methodDescPair = extractFirstParameter(mn.desc);
|
||||||
if (methodDescPair != null && methodDescPair.left.equals(ClassUtil.toByteCodeClassName(targetClass))) {
|
if (methodDescPair != null && methodDescPair.left.equals(ClassUtil.toByteCodeClassName(targetClass))) {
|
||||||
methodInfos.add(new MethodInfo(
|
methodInfos.add(new MethodInfo(
|
||||||
toSlashSeparatedName(targetClass), targetMethod, methodDescPair.right));
|
toSlashSeparatedName(targetClass), targetMethod, mn.name, methodDescPair.right));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user