Nat*_*teS 8 java bytecode bytecode-manipulation java-bytecode-asm
我正在使用ASM Java库来替换一些反射.我生成了这个方法的主体:
void set(Object object, int fieldIndex, Object value);
Run Code Online (Sandbox Code Playgroud)
使用此生成的方法,我可以在运行时在不使用反射的情况下在对象上设置字段.它很棒.但是,我发现原始字段失败了.这是我的set方法的相关部分:
for (int i = 0, n = cachedFields.length; i < n; i++) {
mv.visitLabel(labels[i]);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, targetClassName);
mv.visitVarInsn(ALOAD, 3);
Field field = cachedFields[i].field;
Type fieldType = Type.getType(field.getType());
mv.visitFieldInsn(PUTFIELD, targetClassName, field.getName(), fieldType.getDescriptor());
mv.visitInsn(RETURN);
}
Run Code Online (Sandbox Code Playgroud)
此代码为选择生成案例标签.它适用于对象,但对于原语,我收到此错误:
期待在堆栈上找到浮动
好的,这是有道理的,我需要自己进行拆箱.我实现了以下内容:
for (int i = 0, n = cachedFields.length; i < n; i++) {
mv.visitLabel(labels[i]);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, targetClassName);
mv.visitVarInsn(ALOAD, 3);
Field field = cachedFields[i].field;
Type fieldType = Type.getType(field.getType());
switch (fieldType.getSort()) {
case Type.BOOLEAN:
mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
break;
case Type.BYTE:
mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
break;
case Type.CHAR:
mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
break;
case Type.SHORT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
break;
case Type.INT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
break;
case Type.FLOAT:
mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
break;
case Type.LONG:
mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
break;
case Type.DOUBLE:
mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
break;
case Type.ARRAY:
mv.visitTypeInsn(CHECKCAST, fieldType.getDescriptor());
break;
case Type.OBJECT:
mv.visitTypeInsn(CHECKCAST, fieldType.getInternalName());
break;
}
mv.visitFieldInsn(PUTFIELD, targetClassName, field.getName(), fieldType.getDescriptor());
mv.visitInsn(RETURN);
}
Run Code Online (Sandbox Code Playgroud)
我已经跟踪了它,它肯定会进入相应字段的"case Type.FLOAT",但是,我收到此错误:
期望在堆栈上找到对象/数组
这就是我被困住的地方.对于我的生活,我无法弄清楚为什么拆箱不起作用."ALOAD,3"将set方法的第三个参数放在堆栈上,该参数应该是Float.有任何想法吗?
我发现asm-commons库有一个具有unbox方法的GeneratorAdapter类.但是,我真的不想将另一个JAR包含在应该如此简单的东西中.我查看了GeneratorAdapter源代码,它正在做一些非常相似的事情.我试图修改我的代码以使用GeneratorAdapter,只是为了查看它是否有效,但是根本没有找到它很容易转换.
事实证明上面的拆箱工作正常.在尝试将其作为Object返回之前,我有一些代码正在执行get而不是装箱结果.我的错是没有更简单的测试!
如果其他人需要它,这里是正确的拳击代码:
Type fieldType = Type.getType(...);
switch (fieldType.getSort()) {
case Type.BOOLEAN:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
break;
case Type.BYTE:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
break;
case Type.CHAR:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
break;
case Type.SHORT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
break;
case Type.INT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
break;
case Type.FLOAT:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
break;
case Type.LONG:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
break;
case Type.DOUBLE:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
break;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2759 次 |
最近记录: |