2

ASM バイト コード ライブラリを使用してプロキシ メソッドを作成するのに問題があります。

次のコードを変換したい:

public ReturnType doSomething( ParameterOne parameterOne, 
    ParameterTwo parameterTwo ){

    ReturnType returnType = new ReturnType();
    returnType.setDataOne( parameterOne.getDataOne() );
    returnType.setDataTwo( parameterTwo.getDataTwo() );
    return returnType;
}

に:

public ReturnType copyOff_doSomething( ParameterOne parameterOne, 
    ParameterTwo parameterTwo ){

    ReturnType returnType = new ReturnType();
    returnType.setDataOne( parameterOne.getDataOne() );
    returnType.setDataTwo( parameterTwo.getDataTwo() );
    return returnType;
}

public ReturnType doSomething( ParameterOne parameterOne, 
    ParameterTwo parameterTwo ){

    return copyOff_doSomething( parameterOne, parameterTwo );
}

copyOff_doSomething() メソッドを作成するために、次のコードを使用しています。

public MethodVisitor visitMethod( int access, String name, String desc, 
    String signature, String[] exceptions ) {

    System.out.println(
        "access= " + access + ", name = " + name + ", desc = " +
                  desc + ", signature = " + signature );

    if ( name.equals( "doSomething" ) ){

        MethodVisitor methodVisitor =
            super.visitMethod( access, "copyOff_" + name, desc, 
                signature, exceptions );

        return methodVisitor;
    }
    else {
        return super.visitMethod( access, name, desc, signature, exceptions );
    }
}

上記のコードは、元の doSomething() メソッドを効果的に削除し、コード本体とともに copyOff_doSomething() にコピーします。

私の問題は、代わりの doSomething() メソッドを生成しているときに発生します。

@Override
public void visitEnd() {

    MethodVisitor mv = super.visitMethod( ACC_PUBLIC, "doSomething", 
        "(Lcom/javaspeak/classloader/tests/proxymethod/ParameterOne;" + 
        "Lcom/javaspeak/classloader/tests/proxymethod/ParameterTwo;)" + 
        "Lcom/javaspeak/classloader/tests/proxymethod/ReturnType;", 
            null, null );

    mv.visitCode();
    Label l0 = new Label();
    mv.visitLabel( l0 );
    mv.visitLineNumber( 18, l0 );
    mv.visitVarInsn( ALOAD, 0 );
    mv.visitVarInsn( ALOAD, 1 );
    mv.visitVarInsn( ALOAD, 2 );

    mv.visitMethodInsn( INVOKEVIRTUAL, 
        "com/javaspeak/classloader/tests/proxymethod/FinalMethod", 
           "copyOff_doSomething", 
               "(Lcom/javaspeak/classloader/tests/proxymethod/ParameterOne;" +        
               "Lcom/javaspeak/classloader/tests/proxymethod/ParameterTwo;)" + 
               "Lcom/javaspeak/classloader/tests/proxymethod/ReturnType;");

    mv.visitInsn( ARETURN );
    Label l1 = new Label();
    mv.visitLabel( l1 );

    mv.visitLocalVariable( "this", 
       "Lcom/javaspeak/classloader/tests/proxymethod/FinalMethod;", 
           null, l0, l1, 0 );

    mv.visitLocalVariable( "parameterOne", 
        "Lcom/javaspeak/classloader/tests/proxymethod/ParameterOne;", 
            null, l0, l1, 1 );

    mv.visitLocalVariable( "parameterTwo", 
        "Lcom/javaspeak/classloader/tests/proxymethod/ParameterTwo;", 
            null, l0, l1, 2 );

    mv.visitMaxs( 3, 3 );
    mv.visitEnd();
    super.visitEnd();
}

問題は、次のエラーが発生することです。

java.lang.VerifyError: Bad type on operand stack in method 
com.javaspeak.classloader.tests.proxymethod.ProxyMethod.doSomething(
Lcom/javaspeak/classloader/tests/proxymethod/ParameterOne;
Lcom/javaspeak/classloader/tests/proxymethod/ParameterTwo;)
Lcom/javaspeak/classloader/tests/proxymethod/ReturnType; at offset 3

エラーの意味とエラーの修正方法がわかりません。前述のように、ASMfier を使用して doSomething() メソッドを置き換えるコードを生成しました。

私の戦略は、visitMethod メソッドを使用して doSomething() の名前を copyOff_doSomething() に変更し、次に visitEnd() メソッドを使用して、copyOff_doSomething() メソッドを呼び出す新しい代替 doSomething() メソッドを最初から生成することでした。

おそらく、ASM は私の戦略に対応していないので、別の方法で行う必要がありますか?

おそらく、ASMfier が代替 doSomething() メソッド用に生成したコードを変更する必要があります。生成されたコードに対する私の理解はあまりよくありません。

JDK 1.7 と ASM 4.0 を使用しています。ASMfier を使用して、代替の doSomething() メソッドを生成するために使用する ASM バイト コード命令を確認しました。

誰かが ASM を知っているなら、あなたの助けは大歓迎です?

乾杯

ジョン

4

1 に答える 1

0

ほとんどの場合、ownerパラメーター (このcom/javaspeak/classloader/tests/proxymethod/FinalMethod例ではハードコードされています) が の実際の型と一致しませんthis。したがって、アダプターは呼び出しnameからの値を使用する必要がありClassVisitor.visit(..)ます。

私のAOSD'07論文「ASM フレームワークを使用して一般的なバイトコード変換パターンを実装する」の「Replace Method Body」セクションも参照してください。

于 2012-11-07T15:58:47.093 に答える