Estoy usando la biblioteca ASM Java para reemplazar algunas reflexiones. Genero el cuerpo de este método:unboxing usando la biblioteca ASM Java
void set(Object object, int fieldIndex, Object value);
Con este método generado, puedo establecer campos en un objeto en tiempo de ejecución sin necesidad de utilizar la reflexión. Funciona muy bien. Sin embargo, encontré que falla para los campos primitivos. Aquí está la parte relevante de mi método de configuración:
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);
}
Este código está generando etiquetas de casos para una selección. Funciona muy bien para los objetos primitivos pero para me sale este error:
Expecting to find float on stack
Ok, eso tiene sentido, tengo que hacer el unboxing mí mismo. He implementado el siguiente:
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);
}
he trazado a través y que sin duda pone en el "caso Type.FLOAT" para el campo apropiado, sin embargo, me sale este error:
Expecting to find object/array on stack
Aquí es donde estoy atrapado. Por mi vida no puedo entender por qué el unboxing no funciona. El "ALOAD, 3" está poniendo el tercer parámetro del método set en la pila, que debería ser un Float. ¿Algunas ideas?
Encontré que la biblioteca asm-commons tiene una clase GeneratorAdapter que tiene un método unbox. Sin embargo, realmente no quiero incluir otro JAR para algo que debería ser tan simple. Miré la fuente GeneratorAdapter y está haciendo algo muy similar. Traté de modificar mi código para usar GeneratorAdapter, solo para ver si funcionaba, pero no lo encontré para nada fácil de convertir.
Gracias, pero no quería una dependencia en los asm-commons adicionales que JAR necesitaba para usar GeneratorAdapter. – NateS