在 java.lang.Class 中找不到错误 getMethod(java.lang.String,java.lang.Class,java.lang.Class)
Error getMethod(java.lang.String,java.lang.Class,java.lang.Class) not found in java.lang.Class
我卡在了 Javassisst 中。我想将代码放在其他 class 中的方法中。我有 "no method" 异常。当我自己启动 Test2 class 时,它启动正常,没有任何错误。我认为 Classloader 中存在问题,因为我正在尝试从 SUTTest class 调用方法以进行断言,并且我正在尝试使用相同的反射(Javassist)对 Class1 进行断言。也许两个 classloader 相互冲突,我不知道。我该如何解决这个错误?
Class1 - Javassist
ClassPool pool = ClassPool.getDefault();
CtClass ctAgent = pool.get("Test2");
CtMethod method = ctAgent.getDeclaredMethod("runTestSamples");
method.insertAfter("targetClass.getMethod(\"setData\", int.class, int.class).invoke(targetInstance, 9, 2);");
// method.insertAt(58, "memoryClassLoader.addDefinition(targetName, instrumented);
memoryClassLoader = new MemoryClassLoader();
targetClass = memoryClassLoader.loadClass(targetName);
targetClass.getMethod(\"setData\", int.class, int.class).invoke(targetInstance, 9, 2);");
ctAgent.toClass();
new Test2().execute();
Class2 - Test2
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.jacoco.agent.AgentJar;
import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IClassCoverage;
import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.data.SessionInfoStore;
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.runtime.IRuntime;
import org.jacoco.core.runtime.LoggerRuntime;
import org.jacoco.core.runtime.RuntimeData;
public class Test2 {
private Runnable targetInstance;
public Class<? extends Runnable> targetClass;
private static HashMap<Integer, String> testSamples;
private static HashMap<String, Integer> coverageData;
public String targetName;
public IRuntime runtime;
public Instrumenter instr;
public InputStream original;
public byte[] instrumented;
public RuntimeData data;
public MemoryClassLoader memoryClassLoader;
static Test2 t2 = new Test2();
int a;
public static void main(String[] args) throws Exception {
testSamples = new HashMap<Integer, String>();
coverageData = new HashMap<String, Integer>();
try {
t2.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
public void execute() throws Exception {
testSamples = new HashMap<Integer, String>();
coverageData = new HashMap<String, Integer>();
targetName = SUTClass.class.getName();
runtime = new LoggerRuntime();
instr = new Instrumenter(runtime);
original = getTargetClass(targetName);
instrumented = instr.instrument(original, targetName);
original.close();
data = new RuntimeData();
runtime.startup(data);
memoryClassLoader = new MemoryClassLoader();
memoryClassLoader.addDefinition(targetName, instrumented);
targetClass = (Class<? extends Runnable>) memoryClassLoader.loadClass(targetName);
targetClass.getMethod("f", int.class, int.class).invoke(targetInstance, 2, 9);
runTestSamples(targetClass);
targetInstance = (Runnable) targetClass.newInstance();
// Test samples
targetInstance.run();
final ExecutionDataStore executionData = new ExecutionDataStore();
final SessionInfoStore sessionInfos = new SessionInfoStore();
data.collect(executionData, sessionInfos, false);
runtime.shutdown();
final CoverageBuilder coverageBuilder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executionData, coverageBuilder);
original = getTargetClass(targetName);
analyzer.analyzeClass(original, targetName);
original.close();
for (final IClassCoverage cc : coverageBuilder.getClasses()) {
coverageData.put("coveredInstructions", cc.getInstructionCounter().getCoveredCount());
}
System.out.println(coverageData.get("coveredInstructions"));
System.out.println(a);
}
public static class MemoryClassLoader extends ClassLoader {
private final Map<String, byte[]> definitions = new HashMap<String, byte[]>();
public void addDefinition(final String name, final byte[] bytes) {
definitions.put(name, bytes);
}
@Override
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
final byte[] bytes = definitions.get(name);
if (bytes != null) {
return defineClass(name, bytes, 0, bytes.length);
}
return super.loadClass(name, resolve);
}
}
private InputStream getTargetClass(final String name) {
final String resource = '/' + name.replace('.', '/') + ".class";
return getClass().getResourceAsStream(resource);
}
public void runTestSamples(Class<? extends Runnable> target)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
SecurityException, ClassNotFoundException {
targetClass.getMethod("f", int.class, int.class).invoke(targetInstance, 2, 9);
// testSamples.put(1, "targetClass.getMethod(\"f\", int.class,
// int.class).invoke(targetInstance, 2, 9)");
// testSamples.put(2, "targetClass.getMethod(\"d\", int.class,
// int.class).invoke(targetInstance, 2, 9)");
}
}
异常
javassist.CannotCompileException: [source error] getMethod(java.lang.String,java.lang.Class,java.lang.Class) not found in java.lang.Class
at javassist.CtBehavior.insertAfter(CtBehavior.java:909)
at javassist.CtBehavior.insertAfter(CtBehavior.java:824)
at Agent3$IdleBehavior.action(Agent3.java:202)
at jade.core.behaviours.Behaviour.actionWrapper(Behaviour.java:344)
at jade.core.Agent$ActiveLifeCycle.execute(Agent.java:1585)
at jade.core.Agent.run(Agent.java:1524)
at java.lang.Thread.run(Unknown Source)
Caused by: compile error: getMethod(java.lang.String,java.lang.Class,java.lang.Class) not found in java.lang.Class
at javassist.compiler.TypeChecker.atMethodCallCore(TypeChecker.java:777)
at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:723)
at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:170)
at javassist.compiler.ast.CallExpr.accept(CallExpr.java:49)
at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:693)
at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:170)
at javassist.compiler.ast.CallExpr.accept(CallExpr.java:49)
at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:266)
at javassist.compiler.CodeGen.atStmnt(CodeGen.java:360)
at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
at javassist.compiler.Javac.compileStmnt(Javac.java:578)
at javassist.CtBehavior.insertAfterAdvice(CtBehavior.java:924)
at javassist.CtBehavior.insertAfter(CtBehavior.java:883)
... 6 more
更新
解决后method.insertAfter("targetClass.getMethod(\"setData\", new Class[] { int.class, int.class }).invoke(targetInstance, new Object[] { 9, 2 });");
我遇到了新问题:
java.lang.VerifyError: Bad type on operand stack
Exception Details:
Location:
Test2.runTestSamples()V @148: aastore
Reason:
Type integer (current frame, stack[5]) is not assignable to 'java/lang/Object'
Current Frame:
bci: @148
flags: { }
locals: { 'Test2', top, null }
stack: { 'java/lang/reflect/Method', 'java/lang/Runnable', '[Ljava/lang/Object;', '[Ljava/lang/Object;', integer, integer }
Bytecode:
0x0000000: 2ab4 002e 12eb 05bd 005d 5903 b200 ed53
0x0000010: 5904 b200 ed53 b600 f02a b400 2c05 bd00
0x0000020: 0359 0305 b800 cd53 5904 1009 b800 cd53
0x0000030: b600 f457 2ab4 002e 1301 3005 bd00 5d59
0x0000040: 03b2 00ed 5359 04b2 00ed 53b6 00f0 2ab4
0x0000050: 002c 05bd 0003 5903 1009 b800 cd53 5904
0x0000060: 05b8 00cd 53b6 00f4 57a7 0003 014d 2ab4
0x0000070: 002e 1301 3005 bd00 5d59 03b2 00ed 5359
0x0000080: 04b2 00ed 53b6 00f0 2ab4 002c 05bd 0003
0x0000090: 5903 1009 5359 0405 53b6 00f4 57b1
Stackmap Table:
same_frame_extended(@108)
请注意异常状态
Caused by: compile error: getMethod(java.lang.String,java.lang.Class,java.lang.Class) not found in java.lang.Class
...
at javassist.CtBehavior.insertAfter(CtBehavior.java:883)
根据 documentation of java.lang.Class indeed there is no method with such signature, the only method with name getMethod
具有以下签名:
getMethod(String name, Class<?>... parameterTypes)
引用 http://www.javassist.org/tutorial/tutorial3.html#varargs :
Currently, Javassist does not directly support varargs.
...
public int length(int... args) { return args.length; }
...
To call this method in the source code compiled by the compiler embedded in Javassist, you must write:
length(new int[] { 1, 2, 3 });
instead of this method call using the varargs mechanism:
length(1, 2, 3);
同样signature of method invoke
from documentation of class java.lang.Method:
invoke(Object obj, Object... args)
也引用 http://www.javassist.org/tutorial/tutorial3.html#boxing :
Boxing and unboxing in Java are syntactic sugar. There is no bytecode for boxing or unboxing. So the compiler of Javassist does not support them. For example, the following statement is valid in Java:
Integer i = 3;
since boxing is implicitly performed. For Javassist, however, you must explicitly convert a value type from int to Integer:
Integer i = new Integer(3);
综上所述,我认为
method.insertAfter("targetClass.getMethod(\"setData\", int.class, int.class).invoke(targetInstance, 9, 2);");
应该在
上更改
method.insertAfter("targetClass"
+ ".getMethod(\"setData\", new Class[] { int.class, int.class })"
+ ".invoke(targetInstance, new Object[] { new Integer(9), new Integer(2) };");
我卡在了 Javassisst 中。我想将代码放在其他 class 中的方法中。我有 "no method" 异常。当我自己启动 Test2 class 时,它启动正常,没有任何错误。我认为 Classloader 中存在问题,因为我正在尝试从 SUTTest class 调用方法以进行断言,并且我正在尝试使用相同的反射(Javassist)对 Class1 进行断言。也许两个 classloader 相互冲突,我不知道。我该如何解决这个错误?
Class1 - Javassist
ClassPool pool = ClassPool.getDefault();
CtClass ctAgent = pool.get("Test2");
CtMethod method = ctAgent.getDeclaredMethod("runTestSamples");
method.insertAfter("targetClass.getMethod(\"setData\", int.class, int.class).invoke(targetInstance, 9, 2);");
// method.insertAt(58, "memoryClassLoader.addDefinition(targetName, instrumented);
memoryClassLoader = new MemoryClassLoader();
targetClass = memoryClassLoader.loadClass(targetName);
targetClass.getMethod(\"setData\", int.class, int.class).invoke(targetInstance, 9, 2);");
ctAgent.toClass();
new Test2().execute();
Class2 - Test2
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import org.jacoco.agent.AgentJar;
import org.jacoco.core.analysis.Analyzer;
import org.jacoco.core.analysis.CoverageBuilder;
import org.jacoco.core.analysis.IClassCoverage;
import org.jacoco.core.data.ExecutionDataStore;
import org.jacoco.core.data.SessionInfoStore;
import org.jacoco.core.instr.Instrumenter;
import org.jacoco.core.runtime.IRuntime;
import org.jacoco.core.runtime.LoggerRuntime;
import org.jacoco.core.runtime.RuntimeData;
public class Test2 {
private Runnable targetInstance;
public Class<? extends Runnable> targetClass;
private static HashMap<Integer, String> testSamples;
private static HashMap<String, Integer> coverageData;
public String targetName;
public IRuntime runtime;
public Instrumenter instr;
public InputStream original;
public byte[] instrumented;
public RuntimeData data;
public MemoryClassLoader memoryClassLoader;
static Test2 t2 = new Test2();
int a;
public static void main(String[] args) throws Exception {
testSamples = new HashMap<Integer, String>();
coverageData = new HashMap<String, Integer>();
try {
t2.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
public void execute() throws Exception {
testSamples = new HashMap<Integer, String>();
coverageData = new HashMap<String, Integer>();
targetName = SUTClass.class.getName();
runtime = new LoggerRuntime();
instr = new Instrumenter(runtime);
original = getTargetClass(targetName);
instrumented = instr.instrument(original, targetName);
original.close();
data = new RuntimeData();
runtime.startup(data);
memoryClassLoader = new MemoryClassLoader();
memoryClassLoader.addDefinition(targetName, instrumented);
targetClass = (Class<? extends Runnable>) memoryClassLoader.loadClass(targetName);
targetClass.getMethod("f", int.class, int.class).invoke(targetInstance, 2, 9);
runTestSamples(targetClass);
targetInstance = (Runnable) targetClass.newInstance();
// Test samples
targetInstance.run();
final ExecutionDataStore executionData = new ExecutionDataStore();
final SessionInfoStore sessionInfos = new SessionInfoStore();
data.collect(executionData, sessionInfos, false);
runtime.shutdown();
final CoverageBuilder coverageBuilder = new CoverageBuilder();
final Analyzer analyzer = new Analyzer(executionData, coverageBuilder);
original = getTargetClass(targetName);
analyzer.analyzeClass(original, targetName);
original.close();
for (final IClassCoverage cc : coverageBuilder.getClasses()) {
coverageData.put("coveredInstructions", cc.getInstructionCounter().getCoveredCount());
}
System.out.println(coverageData.get("coveredInstructions"));
System.out.println(a);
}
public static class MemoryClassLoader extends ClassLoader {
private final Map<String, byte[]> definitions = new HashMap<String, byte[]>();
public void addDefinition(final String name, final byte[] bytes) {
definitions.put(name, bytes);
}
@Override
protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException {
final byte[] bytes = definitions.get(name);
if (bytes != null) {
return defineClass(name, bytes, 0, bytes.length);
}
return super.loadClass(name, resolve);
}
}
private InputStream getTargetClass(final String name) {
final String resource = '/' + name.replace('.', '/') + ".class";
return getClass().getResourceAsStream(resource);
}
public void runTestSamples(Class<? extends Runnable> target)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException,
SecurityException, ClassNotFoundException {
targetClass.getMethod("f", int.class, int.class).invoke(targetInstance, 2, 9);
// testSamples.put(1, "targetClass.getMethod(\"f\", int.class,
// int.class).invoke(targetInstance, 2, 9)");
// testSamples.put(2, "targetClass.getMethod(\"d\", int.class,
// int.class).invoke(targetInstance, 2, 9)");
}
}
异常
javassist.CannotCompileException: [source error] getMethod(java.lang.String,java.lang.Class,java.lang.Class) not found in java.lang.Class
at javassist.CtBehavior.insertAfter(CtBehavior.java:909)
at javassist.CtBehavior.insertAfter(CtBehavior.java:824)
at Agent3$IdleBehavior.action(Agent3.java:202)
at jade.core.behaviours.Behaviour.actionWrapper(Behaviour.java:344)
at jade.core.Agent$ActiveLifeCycle.execute(Agent.java:1585)
at jade.core.Agent.run(Agent.java:1524)
at java.lang.Thread.run(Unknown Source)
Caused by: compile error: getMethod(java.lang.String,java.lang.Class,java.lang.Class) not found in java.lang.Class
at javassist.compiler.TypeChecker.atMethodCallCore(TypeChecker.java:777)
at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:723)
at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:170)
at javassist.compiler.ast.CallExpr.accept(CallExpr.java:49)
at javassist.compiler.TypeChecker.atCallExpr(TypeChecker.java:693)
at javassist.compiler.JvstTypeChecker.atCallExpr(JvstTypeChecker.java:170)
at javassist.compiler.ast.CallExpr.accept(CallExpr.java:49)
at javassist.compiler.CodeGen.doTypeCheck(CodeGen.java:266)
at javassist.compiler.CodeGen.atStmnt(CodeGen.java:360)
at javassist.compiler.ast.Stmnt.accept(Stmnt.java:53)
at javassist.compiler.Javac.compileStmnt(Javac.java:578)
at javassist.CtBehavior.insertAfterAdvice(CtBehavior.java:924)
at javassist.CtBehavior.insertAfter(CtBehavior.java:883)
... 6 more
更新
解决后method.insertAfter("targetClass.getMethod(\"setData\", new Class[] { int.class, int.class }).invoke(targetInstance, new Object[] { 9, 2 });");
我遇到了新问题:
java.lang.VerifyError: Bad type on operand stack
Exception Details:
Location:
Test2.runTestSamples()V @148: aastore
Reason:
Type integer (current frame, stack[5]) is not assignable to 'java/lang/Object'
Current Frame:
bci: @148
flags: { }
locals: { 'Test2', top, null }
stack: { 'java/lang/reflect/Method', 'java/lang/Runnable', '[Ljava/lang/Object;', '[Ljava/lang/Object;', integer, integer }
Bytecode:
0x0000000: 2ab4 002e 12eb 05bd 005d 5903 b200 ed53
0x0000010: 5904 b200 ed53 b600 f02a b400 2c05 bd00
0x0000020: 0359 0305 b800 cd53 5904 1009 b800 cd53
0x0000030: b600 f457 2ab4 002e 1301 3005 bd00 5d59
0x0000040: 03b2 00ed 5359 04b2 00ed 53b6 00f0 2ab4
0x0000050: 002c 05bd 0003 5903 1009 b800 cd53 5904
0x0000060: 05b8 00cd 53b6 00f4 57a7 0003 014d 2ab4
0x0000070: 002e 1301 3005 bd00 5d59 03b2 00ed 5359
0x0000080: 04b2 00ed 53b6 00f0 2ab4 002c 05bd 0003
0x0000090: 5903 1009 5359 0405 53b6 00f4 57b1
Stackmap Table:
same_frame_extended(@108)
请注意异常状态
Caused by: compile error: getMethod(java.lang.String,java.lang.Class,java.lang.Class) not found in java.lang.Class ... at javassist.CtBehavior.insertAfter(CtBehavior.java:883)
根据 documentation of java.lang.Class indeed there is no method with such signature, the only method with name getMethod
具有以下签名:
getMethod(String name, Class<?>... parameterTypes)
引用 http://www.javassist.org/tutorial/tutorial3.html#varargs :
Currently, Javassist does not directly support varargs. ...
public int length(int... args) { return args.length; }
... To call this method in the source code compiled by the compiler embedded in Javassist, you must write:
length(new int[] { 1, 2, 3 });
instead of this method call using the varargs mechanism:
length(1, 2, 3);
同样signature of method invoke
from documentation of class java.lang.Method:
invoke(Object obj, Object... args)
也引用 http://www.javassist.org/tutorial/tutorial3.html#boxing :
Boxing and unboxing in Java are syntactic sugar. There is no bytecode for boxing or unboxing. So the compiler of Javassist does not support them. For example, the following statement is valid in Java:
Integer i = 3;
since boxing is implicitly performed. For Javassist, however, you must explicitly convert a value type from int to Integer:
Integer i = new Integer(3);
综上所述,我认为
method.insertAfter("targetClass.getMethod(\"setData\", int.class, int.class).invoke(targetInstance, 9, 2);");
应该在
上更改method.insertAfter("targetClass"
+ ".getMethod(\"setData\", new Class[] { int.class, int.class })"
+ ".invoke(targetInstance, new Object[] { new Integer(9), new Integer(2) };");