2009-10-14 5 views
7

일부 반사를 대체하기 위해 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를 사용하기 위해 코드를 수정하려고했지만 코드가 제대로 작동하는지 알아보기 위해 노력했지만 변환하기 쉽지 않았습니다.

답변

7

위에서 언 박싱이 바뀌 었음을 알 수 있습니다. 나는 그것을 Object로 반환하기 전에 결과를 boxing하지 않는 코드를 가지고있다. 더 간단한 시험을하지 않는 것에 대한 나의 잘못! 다른 사람이 그것을 필요로하는 경우에

, 여기에 복싱에 대한 적절한 코드 :

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; 
} 
1

사용 GeneratorAdapter의 청소기 MethodVisitor보다 더해야하고 오른쪽 primitive.valueOf을 (호출) 방법을 iniserts 언 박스()를 가지고 요구.

+0

감사합니다.하지만 GeneratorAdapter를 사용하기 위해 필요한 추가 asm-commons JAR에 대한 종속성을 원하지 않았습니다. – NateS

관련 문제