From 76d27017deb31669c8888fe2d07fd2070b65231d Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Sun, 11 Nov 2012 01:22:17 +0100 Subject: [PATCH] Allow the structure modifier to read final fields. --- .../protocol/reflect/StructureModifier.java | 23 +++++++++++++++---- .../reflect/compiler/StructureCompiler.java | 21 +++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java index 2665dc21..cd232710 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/StructureModifier.java @@ -152,6 +152,18 @@ public class StructureModifier { } } + /** + * Determine whether or not a field is read-only (final). + * @param fieldIndex - index of the field. + * @return TRUE if the field by the given index is read-only, FALSE otherwise. + */ + public boolean isReadOnly(int fieldIndex) { + if (fieldIndex < 0 || fieldIndex >= data.size()) + new IllegalArgumentException("Index parameter is not within [0 - " + data.size() + ")"); + + return Modifier.isFinal(data.get(fieldIndex).getModifiers()); + } + /** * Writes the value of a field given its index. * @param fieldIndex - index of the field. @@ -424,9 +436,10 @@ public class StructureModifier { for (Field field : fields) { Class type = field.getType(); + int modifier = field.getModifiers(); - // First, ignore primitive fields - if (!type.isPrimitive()) { + // First, ignore primitive fields and final fields + if (!type.isPrimitive() && !Modifier.isFinal(modifier)) { // Next, see if we actually can generate a default value if (generator.getDefault(type) != null) { // If so, require it @@ -449,9 +462,9 @@ public class StructureModifier { for (Field field : FuzzyReflection.fromClass(type, true).getFields()) { int mod = field.getModifiers(); - // Ignore static, final and "abstract packet" fields - if (!Modifier.isFinal(mod) && !Modifier.isStatic(mod) && ( - superclassExclude == null || !field.getDeclaringClass().equals(superclassExclude) + // Ignore static and "abstract packet" fields + if (!Modifier.isStatic(mod) && + (superclassExclude == null || !field.getDeclaringClass().equals(superclassExclude) )) { result.add(field); diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/compiler/StructureCompiler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/compiler/StructureCompiler.java index 10ceaa72..266bb45e 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/compiler/StructureCompiler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/reflect/compiler/StructureCompiler.java @@ -272,6 +272,10 @@ public final class StructureCompiler { return Modifier.isPublic(field.getModifiers()); } + private boolean isNonFinal(Field field) { + return !Modifier.isFinal(field.getModifiers()); + } + private void createFields(ClassWriter cw, String targetSignature) { FieldVisitor typedField = cw.visitField(Opcodes.ACC_PRIVATE, "typedTarget", targetSignature, null, null); typedField.visitEnd(); @@ -305,7 +309,8 @@ public final class StructureCompiler { for (int i = 0; i < fields.size(); i++) { - Class outputType = fields.get(i).getType(); + Field field = fields.get(i); + Class outputType = field.getType(); Class inputType = Primitives.wrap(outputType); String typeDescriptor = Type.getDescriptor(outputType); String inputPath = inputType.getName().replace('.', '/'); @@ -318,8 +323,8 @@ public final class StructureCompiler { else mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - // Only write to public fields - if (isPublic(fields.get(i))) { + // Only write to public non-final fields + if (isPublic(field) && isNonFinal(field)) { mv.visitVarInsn(Opcodes.ALOAD, 3); mv.visitVarInsn(Opcodes.ALOAD, 2); @@ -328,7 +333,7 @@ public final class StructureCompiler { else boxingHelper.unbox(Type.getType(outputType)); - mv.visitFieldInsn(Opcodes.PUTFIELD, targetName, fields.get(i).getName(), typeDescriptor); + mv.visitFieldInsn(Opcodes.PUTFIELD, targetName, field.getName(), typeDescriptor); } else { // Use reflection. We don't have a choice, unfortunately. @@ -386,7 +391,9 @@ public final class StructureCompiler { mv.visitTableSwitchInsn(0, fields.size() - 1, errorLabel, labels); for (int i = 0; i < fields.size(); i++) { - Class outputType = fields.get(i).getType(); + + Field field = fields.get(i); + Class outputType = field.getType(); String typeDescriptor = Type.getDescriptor(outputType); mv.visitLabel(labels[i]); @@ -398,9 +405,9 @@ public final class StructureCompiler { mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); // Note that byte code cannot access non-public fields - if (isPublic(fields.get(i))) { + if (isPublic(field)) { mv.visitVarInsn(Opcodes.ALOAD, 2); - mv.visitFieldInsn(Opcodes.GETFIELD, targetName, fields.get(i).getName(), typeDescriptor); + mv.visitFieldInsn(Opcodes.GETFIELD, targetName, field.getName(), typeDescriptor); boxingHelper.box(Type.getType(outputType)); } else {