J'essaye d'employer ASM dans un javaagent to change the class that is being constructed (sun/misc/URLClassPath
) à un autre (fommil/URLClassPath
) qui hérite de lui et remplace toutes les méthodes. Je sais que la classe cible (java/net/URLClassLoader
), que je suis retransforming
, est la seule chose qui crée sun/misc/URLClassPath
s et seulement dans son constructeur.comment instancier une classe différente par l'instrumentation/ASM
L'idée de base est quelque chose comme ceci:
@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);
}
}
};
}
Je peux mettre un constructeur de println
dans fommil/URLClassPath
et le voir en cours de construction!
Cependant, aucune des méthodes de fommil.URLClassPath
sont appelés. Seules les méthodes de la super classe sont appelées.
Même si je change le code ci-dessus afin que non seulement invokespecial
/<init>
, mais tous les appels à URLClassPath
sont réécrites afin que leurs invokevirtual
points ma classe, mes méthodes sont encore jamais appelés. J'ai même essayé de le faire pour toutes les classes internes de URLClassLoader
.
Alors, pourquoi le invokevirtual
ne trouve-t-il pas les méthodes de remplacement, même quand elles sont retransformées? Est-ce que ce que je fais - changer le type de la chose en cours de construction - n'est fondamentalement pas possible? Si oui, quelqu'un peut-il expliquer pourquoi? Je suis conscient que l'instrumentation des classes JDK de base est assez mauvaise, mais franchement, je n'ai pas vraiment d'alternative. La seule chose qui reste à essayer est d'instrumenter toutes les classes qui essayent d'instancier URLClassLoader
et de les faire piquer dans le champ interne ucp
et de le remplacer par mon implémentation.
Vous utilisez invokespecial qui est pour les constructeurs (ce qui est correct) et non invokevirtual qui est pour les méthodes qui pourraient être surchargées. –
@PeterLawrey a encore lu le code, je suis au courant de ce que vous dites. Ce n'est pas le problème. – fommil
Je n'ai pas dit c'est ce qui explique pourquoi j'ai commenté. Je suppose que le URLCLassLoader est appelé avant que votre transformation puisse démarrer. Quelque chose doit charger les classes utilisées par votre transformateur. –