ASM Javaライブラリを使用してアンボクシング
-
21-09-2019 - |
質問
私はいくつかの反射を置き換えるために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);
}
このコードは、選択のためのケースラベルを生成しています。これは、オブジェクトのための素晴らしい作品が、プリミティブのために、私はこのエラーを取得します:
スタック上のフロートを見つけることを期待します。
[OK]を、理にかなっている、私は自分自身アンボクシングを行う必要があります。私は次のように実装:
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);
}
私はを通じてトレースしていると、それは間違いなく、適切なフィールドの「ケースType.FLOAT」に入り、しかし、私はこのエラーを取得します:
私がこだわっている。ここで、スタック上のオブジェクト/配列を見つけることを期待します。
このです。アンボクシングが動作しない理由は、私の人生のために私は理解することはできません。 「ALOAD、3は」フロートであるべきであるスタックに設定方法の第3パラメータを入れています。任意のアイデア?
私は、ASM-コモンズライブラリがUnboxの方法を持っているGeneratorAdapterクラスを持っていました。しかし、私は本当にとても簡単でなければならない何かのためにさらに別のJARを含める必要はありません。私はGeneratorAdapterのソースを見て、それは非常によく似た何かをやっています。私はそれが働いていた場合、単に確認するために、GeneratorAdapterを使用するように私のコードを変更しようとしましたが、変換することは容易すべてでそれを見つけることができませんでした。
解決
アンボクシング上記の判明が正常に働いていました。私は、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;
}
他のヒント
を使用GeneratorAdapter MethodVisitorよりその必須クリーナと右primitive.valueOfのinvoke()メソッドを呼び出します。
をiniserts VHS版()を有しています