Frage

Ich bin mit der ASM-Java-Bibliothek einige Überlegungen zu ersetzen. Ich erzeugen, um den Körper dieser Methode:

void set(Object object, int fieldIndex, Object value);

Mit dieser Methode erzeugt, kann ich Felder auf ein Objekt zur Laufzeit ohne Reflexion verwendet wird. Es funktioniert großartig. Allerdings fand ich es für primitive Felder ausfällt. Hier ist der relevante Teil meiner Set-Methode:

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

Dieser Code generiert Fall Etiketten für eine ausgewählte. Es funktioniert gut für Objekte, sondern für Primitive ich diesen Fehler:

  

Expecting Schwimmer auf Stapel finden

Ok, der Sinn macht, muß ich die Unboxing selbst tun. Ich implementiert die folgenden:

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

Ich habe verfolgt durch und es geht auf jeden Fall in den „Fall Type.FLOAT“ für das entsprechende Feld, aber ich diesen Fehler:

  

Expecting Objekt / Array auf dem Stapel finden

Dies ist, wo ich bin stecken. Für das Leben von mir kann ich nicht herausfinden, warum das Unboxing funktioniert nicht. Die „ALOAD, 3“ setzt den dritten Parameter des Satzes Methode auf dem Stapel, der ein Schwimmer sein sollte. Irgendwelche Ideen?

Ich fand die asm-Commons-Bibliothek eine GeneratorAdapter Klasse hat, die eine unbox Methode hat. Aber ich will nicht wirklich enthalten noch eine weitere JAR für etwas, das so einfach sein sollte. Ich schaute auf die GeneratorAdapter Quelle und es ist etwas sehr ähnlich tut. Ich habe versucht, meinen Code zu modifizieren GeneratorAdapter zu verwenden, nur um zu sehen, ob es funktioniert, aber habe es gar nicht so einfach finden zu konvertieren.

War es hilfreich?

Lösung

Stellt sich heraus, das Unboxing oben war richtig funktioniert. Ich hatte Code, der eine get tat und nicht das Ergebnis Boxen bevor Sie es als Objekt zurück. Meine Schuld für nicht einfachen Test mit!

Falls jemand anderes braucht es, hier ist der richtige Code für den Boxsport:

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

Andere Tipps

Mit GeneratorAdapter deren Most sauberer als MethodVisitor und hat eine unbox (), die das Recht invoke primitive.valueOf () -Methode iniserts.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top