일부 반사를 대체하기 위해 ASM Java 라이브러리를 사용하고 있습니다. 이 메서드의 본문을 생성합니다 :ASM Java 라이브러리를 사용하여 언 박싱
void set(Object object, int fieldIndex, Object value);
이 생성 된 메서드를 사용하면 런타임에 리플렉션을 사용하지 않고 개체의 필드를 설정할 수 있습니다. 그것은 위대한 작품. 그러나 원시 필드에 대해서는 실패한 것으로 나타났습니다. 다음은 내 설정 방법의 관련 부분입니다.
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);
}
이 코드는 select에 대한 사례 라벨을 생성합니다. 객체에 대해서는 훌륭하게 작동하지만 프리미티브에 대해서는 다음과 같은 오류가 발생합니다.
Expecting to find float on stack
그래, 나 자신을 언 박싱해야합니다. 해당 필드에 대해 내가 통해 추적하고 그것을 확실히 "경우 Type.FLOAT"로 전환
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);
}
그러나, 나는이 오류를 얻을 : 나는이 다음 구현
Expecting to find object/array on stack
이것은을 I 붙어있어. 내 인생에서 나는 언 박싱이 효과가없는 이유를 알 수 없다. "ALOAD, 3"은 set 메소드의 세 번째 매개 변수를 스택에 넣습니다.이 메서드는 Float이어야합니다. 어떤 아이디어?
asm-commons 라이브러리에 unbox 메소드가있는 GeneratorAdapter 클래스가 있음을 발견했습니다. 그러나, 나는 정말 단순해야만하는 또 다른 JAR 파일을 포함하고 싶지 않습니다. GeneratorAdapter 소스를 살펴본 결과 매우 비슷한 것을하고 있습니다. GeneratorAdapter를 사용하기 위해 코드를 수정하려고했지만 코드가 제대로 작동하는지 알아보기 위해 노력했지만 변환하기 쉽지 않았습니다.
감사합니다.하지만 GeneratorAdapter를 사용하기 위해 필요한 추가 asm-commons JAR에 대한 종속성을 원하지 않았습니다. – NateS