Fixed writing private fields with a compiled structure modifier.
Incredibly hard to track down. Lucked out by randomly removing a semicolon.
Dieser Commit ist enthalten in:
Ursprung
456764468a
Commit
ac993896cc
@ -30,9 +30,8 @@ import com.google.common.collect.Sets;
|
|||||||
* Represents a compiled structure modifier.
|
* Represents a compiled structure modifier.
|
||||||
*
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
* @param <TField> Field type.
|
|
||||||
*/
|
*/
|
||||||
public abstract class CompiledStructureModifier<TField> extends StructureModifier<TField> {
|
public abstract class CompiledStructureModifier extends StructureModifier<Object> {
|
||||||
// Used to compile instances of structure modifiers
|
// Used to compile instances of structure modifiers
|
||||||
protected StructureCompiler compiler;
|
protected StructureCompiler compiler;
|
||||||
|
|
||||||
@ -64,9 +63,8 @@ public abstract class CompiledStructureModifier<TField> extends StructureModifie
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Speed up the default writer
|
// Speed up the default writer
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public StructureModifier<TField> writeDefaults() throws FieldAccessException {
|
public StructureModifier<Object> writeDefaults() throws FieldAccessException {
|
||||||
|
|
||||||
DefaultInstances generator = DefaultInstances.DEFAULT;
|
DefaultInstances generator = DefaultInstances.DEFAULT;
|
||||||
|
|
||||||
@ -75,21 +73,20 @@ public abstract class CompiledStructureModifier<TField> extends StructureModifie
|
|||||||
Integer index = entry.getValue();
|
Integer index = entry.getValue();
|
||||||
Field field = entry.getKey();
|
Field field = entry.getKey();
|
||||||
|
|
||||||
write(index, (TField) generator.getDefault(field.getType()));
|
write(index, (Object) generator.getDefault(field.getType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public final TField read(int fieldIndex) throws FieldAccessException {
|
public final Object read(int fieldIndex) throws FieldAccessException {
|
||||||
Object result = readGenerated(fieldIndex);
|
Object result = readGenerated(fieldIndex);
|
||||||
|
|
||||||
if (converter != null)
|
if (converter != null)
|
||||||
return converter.getSpecific(result);
|
return converter.getSpecific(result);
|
||||||
else
|
else
|
||||||
return (TField) result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,11 +101,10 @@ public abstract class CompiledStructureModifier<TField> extends StructureModifie
|
|||||||
|
|
||||||
protected abstract Object readGenerated(int fieldIndex) throws FieldAccessException;
|
protected abstract Object readGenerated(int fieldIndex) throws FieldAccessException;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public StructureModifier<TField> write(int index, Object value) throws FieldAccessException {
|
public StructureModifier<Object> write(int index, Object value) throws FieldAccessException {
|
||||||
if (converter != null)
|
if (converter != null)
|
||||||
value = converter.getGeneric(getFieldType(index), (TField) value);
|
value = converter.getGeneric(getFieldType(index), value);
|
||||||
return writeGenerated(index, value);
|
return writeGenerated(index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,15 +114,14 @@ public abstract class CompiledStructureModifier<TField> extends StructureModifie
|
|||||||
* @param value - new value.
|
* @param value - new value.
|
||||||
* @throws FieldAccessException The field doesn't exist, or it cannot be accessed under the current security contraints.
|
* @throws FieldAccessException The field doesn't exist, or it cannot be accessed under the current security contraints.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected void writeReflected(int index, Object value) throws FieldAccessException {
|
protected void writeReflected(int index, Object value) throws FieldAccessException {
|
||||||
super.write(index, (TField) value);
|
super.write(index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract StructureModifier<TField> writeGenerated(int index, Object value) throws FieldAccessException;
|
protected abstract StructureModifier<Object> writeGenerated(int index, Object value) throws FieldAccessException;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StructureModifier<TField> withTarget(Object target) {
|
public StructureModifier<Object> withTarget(Object target) {
|
||||||
if (compiler != null)
|
if (compiler != null)
|
||||||
return compiler.compile(super.withTarget(target));
|
return compiler.compile(super.withTarget(target));
|
||||||
else
|
else
|
||||||
|
@ -138,7 +138,7 @@ public final class StructureCompiler {
|
|||||||
* Construct a structure compiler.
|
* Construct a structure compiler.
|
||||||
* @param loader - main class loader.
|
* @param loader - main class loader.
|
||||||
*/
|
*/
|
||||||
StructureCompiler(ClassLoader loader) {
|
public StructureCompiler(ClassLoader loader) {
|
||||||
this.loader = loader;
|
this.loader = loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,15 +219,14 @@ public final class StructureCompiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, PACKAGE_NAME + "/" + className,
|
cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, PACKAGE_NAME + "/" + className,
|
||||||
"<TField:Ljava/lang/Object;>L" + COMPILED_CLASS + "<TTField;>;",
|
null, COMPILED_CLASS, null);
|
||||||
COMPILED_CLASS, null);
|
|
||||||
|
|
||||||
createFields(cw, targetSignature);
|
createFields(cw, targetSignature);
|
||||||
createConstructor(cw, className, targetSignature, targetName);
|
createConstructor(cw, className, targetSignature, targetName);
|
||||||
createReadMethod(cw, className, source.getFields(), targetSignature, targetName);
|
createReadMethod(cw, className, source.getFields(), targetSignature, targetName);
|
||||||
createWriteMethod(cw, className, source.getFields(), targetSignature, targetName);
|
createWriteMethod(cw, className, source.getFields(), targetSignature, targetName);
|
||||||
cw.visitEnd();
|
cw.visitEnd();
|
||||||
|
|
||||||
byte[] data = cw.toByteArray();
|
byte[] data = cw.toByteArray();
|
||||||
|
|
||||||
// Call the define method
|
// Call the define method
|
||||||
@ -295,14 +294,16 @@ public final class StructureCompiler {
|
|||||||
private void createWriteMethod(ClassWriter cw, String className, List<Field> fields, String targetSignature, String targetName) {
|
private void createWriteMethod(ClassWriter cw, String className, List<Field> fields, String targetSignature, String targetName) {
|
||||||
|
|
||||||
String methodDescriptor = "(ILjava/lang/Object;)L" + SUPER_CLASS + ";";
|
String methodDescriptor = "(ILjava/lang/Object;)L" + SUPER_CLASS + ";";
|
||||||
String methodSignature = "(ITTField;)L" + SUPER_CLASS + "<TTField;>;";
|
String methodSignature = "(ILjava/lang/Object;)L" + SUPER_CLASS + "<Ljava/lang/Object;>;";
|
||||||
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PROTECTED, "writeGenerated", methodDescriptor, methodSignature,
|
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PROTECTED, "writeGenerated", methodDescriptor, methodSignature,
|
||||||
new String[] { FIELD_EXCEPTION_CLASS });
|
new String[] { FIELD_EXCEPTION_CLASS });
|
||||||
BoxingHelper boxingHelper = new BoxingHelper(mv);
|
BoxingHelper boxingHelper = new BoxingHelper(mv);
|
||||||
|
|
||||||
|
String generatedClassName = PACKAGE_NAME + "/" + className;
|
||||||
|
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
mv.visitFieldInsn(Opcodes.GETFIELD, PACKAGE_NAME + "/" + className, "typedTarget", targetSignature);
|
mv.visitFieldInsn(Opcodes.GETFIELD, generatedClassName, "typedTarget", targetSignature);
|
||||||
mv.visitVarInsn(Opcodes.ASTORE, 3);
|
mv.visitVarInsn(Opcodes.ASTORE, 3);
|
||||||
mv.visitVarInsn(Opcodes.ILOAD, 1);
|
mv.visitVarInsn(Opcodes.ILOAD, 1);
|
||||||
|
|
||||||
@ -351,7 +352,7 @@ public final class StructureCompiler {
|
|||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
mv.visitVarInsn(Opcodes.ILOAD, 1);
|
mv.visitVarInsn(Opcodes.ILOAD, 1);
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 2);
|
mv.visitVarInsn(Opcodes.ALOAD, 2);
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, COMPILED_CLASS, "writeReflected", "(ILjava/lang/Object;)V;");
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, generatedClassName, "writeReflected", "(ILjava/lang/Object;)V");
|
||||||
}
|
}
|
||||||
|
|
||||||
mv.visitJumpInsn(Opcodes.GOTO, returnLabel);
|
mv.visitJumpInsn(Opcodes.GOTO, returnLabel);
|
||||||
@ -384,9 +385,11 @@ public final class StructureCompiler {
|
|||||||
new String[] { "com/comphenix/protocol/reflect/FieldAccessException" });
|
new String[] { "com/comphenix/protocol/reflect/FieldAccessException" });
|
||||||
BoxingHelper boxingHelper = new BoxingHelper(mv);
|
BoxingHelper boxingHelper = new BoxingHelper(mv);
|
||||||
|
|
||||||
|
String generatedClassName = PACKAGE_NAME + "/" + className;
|
||||||
|
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
mv.visitFieldInsn(Opcodes.GETFIELD, PACKAGE_NAME + "/" + className, "typedTarget", targetSignature);
|
mv.visitFieldInsn(Opcodes.GETFIELD, generatedClassName, "typedTarget", targetSignature);
|
||||||
mv.visitVarInsn(Opcodes.ASTORE, 2);
|
mv.visitVarInsn(Opcodes.ASTORE, 2);
|
||||||
mv.visitVarInsn(Opcodes.ILOAD, 1);
|
mv.visitVarInsn(Opcodes.ILOAD, 1);
|
||||||
|
|
||||||
@ -425,7 +428,7 @@ public final class StructureCompiler {
|
|||||||
// We have to use reflection for private and protected fields.
|
// We have to use reflection for private and protected fields.
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
mv.visitVarInsn(Opcodes.ILOAD, 1);
|
mv.visitVarInsn(Opcodes.ILOAD, 1);
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, COMPILED_CLASS, "readReflected", "(I)Ljava/lang/Object;");
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, generatedClassName, "readReflected", "(I)Ljava/lang/Object;");
|
||||||
}
|
}
|
||||||
|
|
||||||
mv.visitInsn(Opcodes.ARETURN);
|
mv.visitInsn(Opcodes.ARETURN);
|
||||||
@ -451,25 +454,27 @@ public final class StructureCompiler {
|
|||||||
private void createConstructor(ClassWriter cw, String className, String targetSignature, String targetName) {
|
private void createConstructor(ClassWriter cw, String className, String targetSignature, String targetName) {
|
||||||
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
|
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>",
|
||||||
"(L" + SUPER_CLASS + ";L" + PACKAGE_NAME + "/StructureCompiler;)V",
|
"(L" + SUPER_CLASS + ";L" + PACKAGE_NAME + "/StructureCompiler;)V",
|
||||||
"(L" + SUPER_CLASS + "<TTField;>;L" + SUPER_CLASS + ";)V", null);
|
"(L" + SUPER_CLASS + "<Ljava/lang/Object;>;L" + PACKAGE_NAME + "/StructureCompiler;)V", null);
|
||||||
|
String fullClassName = PACKAGE_NAME + "/" + className;
|
||||||
|
|
||||||
mv.visitCode();
|
mv.visitCode();
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, COMPILED_CLASS, "<init>", "()V");
|
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, COMPILED_CLASS, "<init>", "()V");
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 1);
|
mv.visitVarInsn(Opcodes.ALOAD, 1);
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, PACKAGE_NAME + "/" + className, "initialize", "(L" + SUPER_CLASS + ";)V");
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, fullClassName, "initialize", "(L" + SUPER_CLASS + ";)V");
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 1);
|
mv.visitVarInsn(Opcodes.ALOAD, 1);
|
||||||
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, SUPER_CLASS, "getTarget", "()Ljava/lang/Object;");
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, SUPER_CLASS, "getTarget", "()Ljava/lang/Object;");
|
||||||
mv.visitFieldInsn(Opcodes.PUTFIELD, PACKAGE_NAME + "/" + className, "target", "Ljava/lang/Object;");
|
mv.visitFieldInsn(Opcodes.PUTFIELD, fullClassName, "target", "Ljava/lang/Object;");
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
mv.visitFieldInsn(Opcodes.GETFIELD, PACKAGE_NAME + "/" + className, "target", "Ljava/lang/Object;");
|
mv.visitFieldInsn(Opcodes.GETFIELD, fullClassName, "target", "Ljava/lang/Object;");
|
||||||
mv.visitTypeInsn(Opcodes.CHECKCAST, targetName);
|
mv.visitTypeInsn(Opcodes.CHECKCAST, targetName);
|
||||||
mv.visitFieldInsn(Opcodes.PUTFIELD, PACKAGE_NAME + "/" + className, "typedTarget", targetSignature);
|
mv.visitFieldInsn(Opcodes.PUTFIELD, fullClassName, "typedTarget", targetSignature);
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
mv.visitVarInsn(Opcodes.ALOAD, 2);
|
mv.visitVarInsn(Opcodes.ALOAD, 2);
|
||||||
mv.visitFieldInsn(Opcodes.PUTFIELD, PACKAGE_NAME + "/" + className, "compiler", "L" + PACKAGE_NAME + "/StructureCompiler;");
|
mv.visitFieldInsn(Opcodes.PUTFIELD, fullClassName, "compiler", "L" + PACKAGE_NAME + "/StructureCompiler;");
|
||||||
mv.visitInsn(Opcodes.RETURN);
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
mv.visitMaxs(2, 3);
|
mv.visitMaxs(2, 3);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren