У меня возникают трудности с использованием библиотеки байт-кода ASM для создания прокси-методов.
Я хочу преобразовать следующий код:
public ReturnType doSomething( ParameterOne parameterOne,
ParameterTwo parameterTwo ){
ReturnType returnType = new ReturnType();
returnType.setDataOne( parameterOne.getDataOne() );
returnType.setDataTwo( parameterTwo.getDataTwo() );
return returnType;
}
to:
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() для создания нового замещающего метода doSomething() с нуля, который вызывает метод copyOff_doSomething().
Возможно, ASM не соответствует моей стратегии, и мне следует действовать по-другому?
Возможно, мне нужно изменить код, созданный ASMfier для замены метода doSomething(). Мое понимание сгенерированного кода не так уж хорошо.
Я использую JDK 1.7 и ASM 4.0. Я использовал ASMfier, чтобы посмотреть, какие инструкции байт-кода ASM использовать для генерации замещающего метода doSomething().
Если кто-нибудь знает ASM, ваша помощь будет высоко оценена?
Ваше здоровье
Джон
doSomething
и посмотреть, что находится по смещению 3. Скорее всего, там инструкцияinvokevirtual
. Проверьте, подается ли он с правильными аргументами. - person Alexei Kaigorodov   schedule 06.11.2012