Search code examples
javaclassloaderbytecodejava-bytecode-asmbytecode-manipulation

Java ASM ClassReader fails with java.io.IOException: Class not found


I am trying to instrument OkHttpClient builder class. However, I am not able to create ClassReader in the first place.

import org.objectweb.asm.ClassReader;
...
// this works meaning dependency from gradle is satisfied
okhttp3.OkHttpClient.Builder test = new okhttp3.OkHttpClient.Builder();
...
// but this fails with java.io.IOException: Class not found
ClassReader cr = new ClassReader("okhttp3.OkHttpClient.Builder");

Assuming this is even possible, is there a way to achieve this? My intention is to insert an interceptor to the build() method of Builer class.


Solution

  • The argument to ClassReader is in dollarized syntax.

    This is a weirdo, hybrid JVM/java syntax where you use dots as separator between the package, and a dot between package and class, but then dollars for inner class separation. Builder is an inner class of OkHttpClient (the capitalization gives it away: OkHttpClient is the first capitalized thing, so that's a class, and thus Builder is an inner class of that), thus, you end up at okhttp3.OkHttpClient$Builder.

    I'd replace that code with:

    ClassReader cr = new ClassReader(okhttp3.OkHttpClient.Builder.class.getName());
    

    This gets you the right (with dollars for inners) name and ensures you can't typo that thing (or rather, that you get a compile/write time error if you do, instead of figuring it out later at runtime).