2012-03-01 11 views
8

私はasmライブラリを使用して、いくつかのJavaバイトコードの変更を実行しています。具体的には、クラスを変更して新しいインタフェースと関連メソッドを実装することです。私の現在のアプローチは、javaagentを介してコアのasm APIを使用しています。私は静的に.classファイルを変更するのではなく、この動的なアプローチを維持したいと思います。Asmコード内からInstrumentation.retransformClasses()を正しく使用するにはどうすればよいですか?

私の問題は、Bから拡張されたクラスAを変更する場合、Bも変更する必要があるということです。(クラスがJVMでどのようにロードされるのか理解しているので、 Bは常にクラスAの前にトランスフォーマーに渡されます(私が間違っていれば私を修正してください)。その前提を前提に、私は戻って行く必要があると考えています。retransform 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を変換するのに興味があるとしましょう。私が期待しているのは、**1**にスーパークラス(B)の名前が印刷されているのがわかります。私が**2**になったら、AのスーパークラスがBであることを発見すると、私はBを再変換しようとしているはずです。この時点で、このメソッドは(inst.retransformClasses()を介して)もう一度呼び出されることを期待しています。私はBが**1**に印刷されるのを見るだろう。しかし、私はしません。 (私は印刷ステートメントを追加して、再変換呼び出しに到達していることを確認しました。また、Instrumentation.isRetransformClassesSupported()Instrumentation.isModifiableClass(c)の両方がtrueを返すことも確認しました)。

私はエージェントを正しくセットアップしたと信じています。マニフェストでCan-Retransform-ClassesとCan-Redefine-Classesを両方ともtrueに設定します。私はここで間違ってやっているものになどの任意の洞察力

public static void premain(String agentArgs, Instrumentation inst) { 
    inst.addTransformer(new PyClassFileTransformer(inst), true); 
} 

:私はエージェントのpremain方法で計測する変圧器を追加するときも、私はこれを行いますか?ありがとう。

+1

あなたは問題を解決しましたか? @Jens私はいくつかのアドバイスを与えるために[ここ](http://stackoverflow.com/questions/18657095/got-unsupportedoperationexception-when-try-to-retransformclasses)行くことができますか? –

答えて

1

バイトコード計測戦略を変更することができます。そのため、クラスBをロードすると、クラスBをすべて変更する必要がある場合はそのサブクラスをすべて見つけてその時点で決定します。これは、クラスメタデータリポジトリまたはキャッシュをメモリ内に維持すること(つまり、クラス階層に関する情報)によって最適化することができるため、毎回メタデータをロードする必要はありません。

関連する問題