私はasmライブラリを使用して、Javaバイトコードの変更を実行しています。具体的には、クラスを変更して、新しいインターフェイスと関連するメソッドを実装しています。私の現在のアプローチは、javaagentを介してコアasmAPIを使用しています。.classファイルを静的に変更するのではなく、この動的なアプローチを維持したいと思います。
より高いレベルでは、私の問題は、Bから拡張するクラスAを変更することを選択した場合、Bも変更する必要があることです(クラスがJVMにロードされる方法を理解していると、クラスBは常にクラスAの前にトランスフォーマーに渡されます(間違っている場合は修正してください)。その仮定を前提として、Bに戻って再トランスフォームする必要があると考えています。私のアプローチは次のコードに含まれています。
public byte[] transform(ClassLoader l, String name, Class<?> clazz, ProtectionDomain d, byte[] b) {
throws IllegalClassFormatException {
// **1**
System.out.println("--->>> " + name);
if (interestingClass(name)) {
try {
ClassReader cr = new ClassReader(b);
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
PyClassVisitorAdapter pv = new PyClassVisitorAdapter(cw, name);
cr.accept(pv, 0);
// **2** Retrieve the superclass and try to transform that
if (! "Ljava/lang/Object;".equals(pv.getSuperName())) {
String cName = classJvmToCanonical(pv.getSuperName());
Class[] classes = inst.getAllLoadedClasses();
for (Class c : classes) {
if (c.getName().equals(cName)) {
inst.retransformClasses(c);
break;
}
}
}
// Dump the transformed class
ClassReader cr2 = new ClassReader(cw.toByteArray());
ClassWriter cw2 = new ClassWriter(cr2, 0);
TraceClassVisitor tcv = new TraceClassVisitor(cw2, new PrintWriter(System.out));
cr2.accept(tcv, 0);
return cw2.toByteArray();
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
} else {
return b;
}
}
(コンストラクターで渡されるinst
ハンドルです)Instrumentation
私が苦労しているのは、コメントでマークされているブロック**2**
です。AがBを拡張し、Aの変換に「興味がある」ともう一度言いましょう。私が期待しているのは、スーパークラス(B)の名前が印刷されていること**1**
です(ただし、私は考えていないため、変換されません)最初のパスで興味深いです)そして、**2**
AのスーパークラスがBであることがわかったら、Bを再変換しようとする必要があります。この時点で、このメソッドが(を介してinst.retransformClasses()
)再度呼び出されることを期待しています。 Bがで印刷されるのを参照してください**1**
。しかし、私はしません。(printステートメントを追加し、retransform呼び出しに到達していることを確認しました。これも確認しInstrumentation.isRetransformClassesSupported()
、Instrumentation.isModifiableClass(c)
両方ともtrueを返します)。
エージェントを正しく設定したと思います。マニフェストでCan-Retransform-ClassesとCan-Redefine-Classesの両方をtrueに設定します。また、エージェントのpremain
メソッドでインストルメンテーションにトランスフォーマーを追加すると、次のようになります。
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new PyClassFileTransformer(inst), true);
}
私がここで間違っていることについての洞察はありますか?ありがとう。