classPool.get(className) throws RuntimeException cannot find class

769 views Asked by At

I am trying to write a simple instrumentation agent using Javassist.

public class Agent implements ClassFileTransformer {

    protected Instrumentation instrumentation;
    protected ClassPool classPool;

    public Agent(Instrumentation instrumentation){

        this.instrumentation = instrumentation;
        this.classPool = ClassPool.getDefault();
        this.instrumentation.addTransformer(this);
    }

    public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

        try {

            System.out.printf("%s.transform: %s\n", this.getClass().getCanonicalName(), className);

            classPool.insertClassPath(new ByteArrayClassPath(className, classfileBuffer));

            CtClass ctClass = classPool.get(className);  /* <- throws error */
        }
        catch (Exception ex){
            System.out.println(ex);
            return null;
        }
    }
}

But I get the following errors:

java.lang.RuntimeException: cannot find java/lang/invoke/MethodHandleImpl: java.lang.invoke.MethodHandleImpl found in java/lang/invoke/MethodHandleImpl.class

The only class that doesn't throw this exception is the one in my project in the IDE (IntelliJ IDEA).

I tried to add the paths from the classpath manually, but that didn't help either. i.e.

String[] cpEntries = System.getProperty("java.class.path").split(File.pathSeparator);
for (String cpEntry : classpathEntries)
    classPool.insertClassPath(cpEntry);

What am I missing? Thanks!

1

There are 1 answers

0
isapir On BEST ANSWER

The problem is that className's separator is a /, while classPool.get(className) expects the . delimiter, so the fix is to replace those characters, i.e.:

String classNameDotted = className.replace('/', '.');
CtClass ctClass = classPool.get(classNameDotted);