I am trying to use ASM in a javaagent to change the class that is being constructed (sun/misc/URLClassPath) to another one (fommil/URLClassPath) that inherits from it and overrides all the methods. I know that the target class (java/net/URLClassLoader), which I am retransforming, is the only thing that creates sun/misc/URLClassPaths and only in its constructor.
The basic idea is something like this:
@Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor visitor = super.visitMethod(access, name, desc, signature, exceptions); return new MethodVisitor(Opcodes.ASM5, visitor) { @Override public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { if (opcode == Opcodes.INVOKESPECIAL && "sun/misc/URLClassPath".equals(owner) && "<init>".equals(name)) { super.visitMethodInsn(opcode, "fommil/URLClassPath", name, desc, itf); } else { super.visitMethodInsn(opcode, owner, name, desc, itf); } } }; } I can put a println in fommil/URLClassPath's constructor and see it being constructed!
However, none of fommil.URLClassPath's methods are being called. Only the methods on the super class are ever called.
Even if I change the above code so that not only invokespecial / <init>, but all calls to URLClassPath are rewritten so that their invokevirtual points to my class, my methods are still never called. I've even tried doing this for all of the inner classes of URLClassLoader.
So why are the invokevirtuals not finding the override methods, even when they are retransformed? Is what I'm doing - changing the type of the thing being constructed - just fundamentally not possible? If so, can somebody please explain why?
I am aware that instrumenting core JDK classes is pretty evil, but frankly I don't really have much of an alternative.
The only thing left to try is to instrument all classes that try to instantiate URLClassLoader and have them poke into the internal ucp field and replace it with my implementation.