我使用javassist重写一个名为compile
的方法(它将一个String数组作为参数):我创建了一个新签名为compile
方法的方法(它是一个副本原始的一个),将实际的compile
方法重命名为compile$Impl
并添加一些调用我的类。
副本以这种方式完成:
CtMethod interceptMethod = CtNewMethod.copy(method, methodName, ctClass, null);
javassist重写代码:
try {
com.company.CustomClass.instance().preintercept(this);
boolean result = compile$impl($$);
result = com.company.CustomClass.instance().dointercept(result, new Object[] { this , $1 });
return result;
} finally {
com.company.CustomClass.instance().postintercept(this);
}
代码用一个名为body
的StringBuffer变量编写,后一个变量的内容写成新compile
方法的主体,如下所示:
interceptMethod.setBody(body.toString());
ctClass.addMethod(interceptMethod);
我的com.company.CustomClass
拥有新compile
方法调用的方法:
public Object dointercept(boolean retval, Object.. args) {
return (Boolean)returned;
}
public static synchronized CustomClass instance() {
// _instance is already instanciated when this method is called
return _instance;
}
public void preintercept(Object arg) {
// some stuff before
}
public void postintercept(Object arg) {
// some stuff after
}
执行代码时,我得到了verifyError:
java.lang.VerifyError: (class: org/eclipse/jdt/internal/compiler/batch/Main, method: compile signature: ([Ljava/lang/String;)Z) Expecting to find integer on stack
我已将修改过的类的字节码写入磁盘,试图发现问题。以下是我对新compile
方法的了解:
public boolean compile(java.lang.String[] arg0) {
try {
0 invokestatic 2130; /* com.company.CustomClass.instance() */
3 aload_0;
4 invokevirtual 2134; /* void preintercept(java.lang.Object arg0) */
7 aload_0;
8 aload_1;
9 invokevirtual 2136; /* boolean compile$impl(java.lang.String[] arg0) */
12 istore_2;
13 invokestatic 2130; /* com.company.CustomClass.instance() */
16 iload_2;
17 iconst_2;
18 anewarray 4; /* new java.lang.Object[] */
21 dup;
22 iconst_0;
23 aload_0;
24 aastore;
25 dup;
26 iconst_1;
27 aload_1;
28 aastore;
29 invokevirtual 2140; /* java.lang.Object dointercept(boolean arg0, java.lang.Object[] arg1) */
32 istore_2;
33 iload_2;
34 istore_3;
35 goto 17;
38 iload_3;
39 ireturn;
}
finally { /* covers bytes 0 to 40 */
40 astore 4;
42 invokestatic 2130; /* com.company.CustomClass.instance() */
45 aload_0;
46 invokevirtual 2143; /* void postintercept(java.lang.Object arg0) */
49 aload 4;
51 athrow;
52 invokestatic 2130; /* com.company.CustomClass.instance() */
55 aload_0;
56 invokevirtual 2143; /* void postintercept(java.lang.Object arg0) */
59 goto -21;
}
}
当我对类的字节码进行类型分析时,错误发生在第32行istore_2
指令处。这是分析:
Type based analysis: compile([Ljava/lang/String;)Z
Offset Bytecode Stack before Stack after
----------------------------------------------------------------------------
0 invokestatic <empty> L
3 aload_0 L L, L
4 invokevirtual L, L <empty>
7 aload_0 <empty> L
8 aload_1 L L, L
9 invokevirtual L, L I
12 istore_2 I <empty>
13 invokestatic <empty> L
16 iload_2 L L, I
17 iconst_2 L, I L, I, I
18 anewarray L, I, I L, I, L
21 dup L, I, L L, I, L, L
22 iconst_0 L, I, L, L L, I, L, L, I
23 aload_0 L, I, L, L, I L, I, L, L, I, L
24 aastore L, I, L, L, I, L L, I, L
25 dup L, I, L L, I, L, L
26 iconst_1 L, I, L, L L, I, L, L, I
27 aload_1 L, I, L, L, I L, I, L, L, I, L
28 aastore L, I, L, L, I, L L, I, L
29 invokevirtual L, I, L L
32 istore_2 L <empty>
Error: Expecting to find I on stack, type on stack L.
33 iload_2 <empty> I
34 istore_3 I <empty>
35 goto <empty> <empty>
38 iload_3 <empty> I
39 ireturn I <empty>
40 astore L <empty>
42 invokestatic <empty> L
45 aload_0 L L, L
46 invokevirtual L, L <empty>
49 aload <empty> L
51 athrow L L
52 invokestatic <empty> L
55 aload_0 L L, L
56 invokevirtual L, L <empty>
59 goto <empty> <empty>
----------------------------------------------------------------------------
但我知道这一点,我无法理解为什么存储int存在问题 我不会使用任何整数(我肯定会遗漏一些东西)。
由于
答案 0 :(得分:2)
这是因为doIntercept
正在返回Boolean
Object
,并将其存储为指向对象的指针(即出现在29的L
)。然后,它将该值存储到原始boolean
中,即原始整数I
。
如果您使用显式广播,或在结尾添加.booleanValue()
com.company.CustomClass.instance().dointercept(result, new Object[] { this , $1 }).booleanValue();
它可能有用吗?
问题是它没有编译自动拆箱&#39;对象到基元。
https://docs.oracle.com/javase/tutorial/java/data/autoboxing.html