在java.lang.Class中找不到错误getMethod(java.lang.String、java.lang.Class、java.lang.Class)

在java.lang.Class中找不到错误getMethod(java.lang.String、java.lang.Class、java.lang.Class),java,reflection,classloader,bytecode,javassist,Java,Reflection,Classloader,Bytecode,Javassist,我被困在Javassist中。我想把代码放在另一个类中的方法中。我有“没有方法”的例外。当我自己启动Test2类时,它启动正常,没有任何错误。我认为Classloader中存在问题,因为我试图从SUTTest类调用方法以执行断言,并且我试图使用相同的反射(Javassist)对Class1执行此操作。也许两个类加载器相互冲突,我不知道。如何修复此错误 Class1-Javassist ClassPool pool = ClassPool.getDefault(); CtClass ctAgent

我被困在Javassist中。我想把代码放在另一个类中的方法中。我有“没有方法”的例外。当我自己启动Test2类时,它启动正常,没有任何错误。我认为Classloader中存在问题,因为我试图从SUTTest类调用方法以执行断言,并且我试图使用相同的反射(Javassist)对Class1执行此操作。也许两个类加载器相互冲突,我不知道。如何修复此错误

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)");
    }
}
更新

在解决方案
method.insertAfter(“targetClass.getMethod(\“setData\”,新类[]{int.Class,int.Class})之后调用(targetInstance,新对象[]{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)

请注意,异常状态

根据事实,没有此类签名的方法,具有以下签名:

getMethod(String name, Class<?>... parameterTypes)
。。。 要在Javassist中嵌入的编译器编译的源代码中调用此方法,必须编写:

length(new int[] { 1, 2, 3 });
使用varargs机制代替此方法调用:

length(1, 2, 3);
同样地:

还引述:

Java中的装箱和拆箱是语法上的糖分。装箱或拆箱没有字节码。因此Javassist的编译器不支持它们。例如,以下语句在Java中有效:

Integer i = 3;
因为装箱是隐式执行的。但是,对于Javassist,必须将值类型从int显式转换为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) };");

非常感谢。它帮助我在解决问题方面取得了进步。现在我有了新的错误:
***Class1***java.lang的未捕获异常。VerifyError:操作数堆栈异常详细信息上的错误类型:位置:Test2.runTestSamples()V@43:aastore原因:类型整数(当前帧,堆栈[5])不可分配给“java/lang/Object”当前帧:bci:@43标志:{}locals:{'Test2',top,null}堆栈:{'java/lang/reflect/Method','java/lang/Runnable','[Ljava/lang/Integer;','[Ljava/lang/Integer;',Integer,Integer}
请参阅更新的答案。现在让我停止进一步讨论,并防止复制粘贴所有Javassist文档,IMO的答案已经足够完整-解决了初始问题,并清楚地指出了应该仔细研究的文档。欢迎SamSimon!作为一些一般性建议,不鼓励编辑您的问题基本上,在你已经有了一个有效的答案后再问一个不同的问题。你可以问一个新的问题,并将帮助你的当前答案标记为已被接受。
Integer i = 3;
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) };");