Moving accessor methods to a separate "Accessors" factory class.
Dieser Commit ist enthalten in:
Ursprung
b70c7fa775
Commit
143ed2ff02
@ -36,8 +36,9 @@ import com.comphenix.protocol.injector.server.SocketInjector;
|
||||
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.VolatileField;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftFields;
|
||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
@ -213,10 +214,10 @@ class ChannelInjector extends ByteToMessageDecoder {
|
||||
patchEncoder(vanillaEncoder);
|
||||
|
||||
if (DECODE_BUFFER == null)
|
||||
DECODE_BUFFER = FuzzyReflection.getMethodAccessor(vanillaDecoder.getClass(),
|
||||
DECODE_BUFFER = Accessors.getMethodAccessor(vanillaDecoder.getClass(),
|
||||
"decode", ChannelHandlerContext.class, ByteBuf.class, List.class);
|
||||
if (ENCODE_BUFFER == null)
|
||||
ENCODE_BUFFER = FuzzyReflection.getMethodAccessor(vanillaEncoder.getClass(),
|
||||
ENCODE_BUFFER = Accessors.getMethodAccessor(vanillaEncoder.getClass(),
|
||||
"encode", ChannelHandlerContext.class, Object.class, ByteBuf.class);
|
||||
|
||||
// Intercept sent packets
|
||||
@ -265,7 +266,7 @@ class ChannelInjector extends ByteToMessageDecoder {
|
||||
*/
|
||||
private void patchEncoder(MessageToByteEncoder<Object> encoder) {
|
||||
if (ENCODER_TYPE_MATCHER == null) {
|
||||
ENCODER_TYPE_MATCHER = FuzzyReflection.getFieldAccessor(encoder.getClass(), "matcher", true);
|
||||
ENCODER_TYPE_MATCHER = Accessors.getFieldAccessor(encoder.getClass(), "matcher", true);
|
||||
}
|
||||
ENCODER_TYPE_MATCHER.set(encoder, TypeParameterMatcher.get(MinecraftReflection.getPacketClass()));
|
||||
}
|
||||
@ -490,7 +491,7 @@ class ChannelInjector extends ByteToMessageDecoder {
|
||||
*/
|
||||
public Protocol getCurrentProtocol() {
|
||||
if (PROTOCOL_ACCESSOR == null) {
|
||||
PROTOCOL_ACCESSOR = FuzzyReflection.getFieldAccessor(
|
||||
PROTOCOL_ACCESSOR = Accessors.getFieldAccessor(
|
||||
networkManager.getClass(), MinecraftReflection.getEnumProtocolClass(), true);
|
||||
}
|
||||
return Protocol.fromVanilla((Enum<?>) PROTOCOL_ACCESSOR.get(networkManager));
|
||||
|
@ -5,8 +5,8 @@ import java.net.SocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import net.minecraft.util.io.netty.buffer.ByteBufAllocator;
|
||||
@ -128,7 +128,7 @@ abstract class ChannelProxy implements Channel {
|
||||
|
||||
if (accessor == null) {
|
||||
try {
|
||||
accessor = FuzzyReflection.getFieldAccessor(clazz, messageClass, true);
|
||||
accessor = Accessors.getFieldAccessor(clazz, messageClass, true);
|
||||
} catch (IllegalArgumentException e) {
|
||||
accessor = MARK_NO_MESSAGE;
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import java.util.List;
|
||||
|
||||
import com.comphenix.protocol.reflect.compiler.EmptyClassVisitor;
|
||||
import com.comphenix.protocol.reflect.compiler.EmptyMethodVisitor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import net.sf.cglib.asm.ClassReader;
|
||||
|
@ -0,0 +1,143 @@
|
||||
package com.comphenix.protocol.reflect;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
public class ExactReflection {
|
||||
// The class we're actually representing
|
||||
private Class<?> source;
|
||||
private boolean forceAccess;
|
||||
|
||||
private ExactReflection(Class<?> source, boolean forceAccess) {
|
||||
this.source = Preconditions.checkNotNull(source, "source class cannot be NULL");
|
||||
this.forceAccess = forceAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an exact reflection instance from a given class.
|
||||
* @param source - the class we'll use.
|
||||
* @return A fuzzy reflection instance.
|
||||
*/
|
||||
public static ExactReflection fromClass(Class<?> source) {
|
||||
return fromClass(source, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an exact reflection instance from a given class.
|
||||
* @param source - the class we'll use.
|
||||
* @param forceAccess - whether or not to override scope restrictions.
|
||||
* @return A fuzzy reflection instance.
|
||||
*/
|
||||
public static ExactReflection fromClass(Class<?> source, boolean forceAccess) {
|
||||
return new ExactReflection(source, forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an exact reflection instance from an object.
|
||||
* @param reference - the object we'll use.
|
||||
* @return A fuzzy reflection instance that uses the class of the given object.
|
||||
*/
|
||||
public static ExactReflection fromObject(Object reference) {
|
||||
return new ExactReflection(reference.getClass(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an exact reflection instance from an object.
|
||||
* @param reference - the object we'll use.
|
||||
* @param forceAccess - whether or not to override scope restrictions.
|
||||
* @return A fuzzy reflection instance that uses the class of the given object.
|
||||
*/
|
||||
public static ExactReflection fromObject(Object reference, boolean forceAccess) {
|
||||
return new ExactReflection(reference.getClass(), forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the first method in the class hierachy with the given name and parameters.
|
||||
* <p>
|
||||
* If {@link #isForceAccess()} is TRUE, we will also search for protected and private methods.
|
||||
* @param methodName - the method name to find, or NULL to look for everything.
|
||||
* @param parameters - the parameters.
|
||||
* @return The first matched method.
|
||||
* @throws IllegalArgumentException If we cannot find a method by this name.
|
||||
*/
|
||||
public Method getMethod(String methodName, Class<?>... parameters) {
|
||||
return getMethod(source, methodName, parameters);
|
||||
}
|
||||
|
||||
// For recursion
|
||||
private Method getMethod(Class<?> instanceClass, String methodName, Class<?>... parameters) {
|
||||
for (Method method : instanceClass.getDeclaredMethods()) {
|
||||
if ((forceAccess || Modifier.isPublic(method.getModifiers())) &&
|
||||
(methodName == null || method.getName().equals(methodName)) &&
|
||||
Arrays.equals(method.getParameterTypes(), parameters)) {
|
||||
|
||||
method.setAccessible(true);
|
||||
return method;
|
||||
}
|
||||
}
|
||||
// Search in every superclass
|
||||
if (instanceClass.getSuperclass() != null)
|
||||
return getMethod(instanceClass.getSuperclass(), methodName, parameters);
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find method %s (%s) in %s.", methodName, Arrays.asList(parameters), source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field in the class hierachy by the given name.
|
||||
* <p>
|
||||
* If {@link #isForceAccess()} is TRUE, we will also search for protected and private fields.
|
||||
* @param fieldName - the field name. Cannot be NULL.
|
||||
* @return The first matched field.
|
||||
*/
|
||||
public Field getField(String fieldName) {
|
||||
return getField(source, fieldName);
|
||||
}
|
||||
|
||||
// For recursion
|
||||
private Field getField(Class<?> instanceClass, @Nonnull String fieldName) {
|
||||
// Ignore access rules
|
||||
for (Field field : instanceClass.getDeclaredFields()) {
|
||||
if (field.getName().equals(fieldName)) {
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively fild the correct field
|
||||
if (instanceClass.getSuperclass() != null)
|
||||
return getField(instanceClass.getSuperclass(), fieldName);
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Unable to find field %s in %s.", fieldName, source));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an {@link ExactReflection} object where scope restrictions are ignored.
|
||||
* @return A copy of the current object.
|
||||
*/
|
||||
public ExactReflection forceAccess() {
|
||||
return new ExactReflection(source, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we are overriding scope restrictions and will also find
|
||||
* private, protected or package members.
|
||||
* @return TRUE if we are, FALSE otherwise.
|
||||
*/
|
||||
public boolean isForceAccess() {
|
||||
return forceAccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the source class we are searching.
|
||||
* @return The source.
|
||||
*/
|
||||
public Class<?> getSource() {
|
||||
return source;
|
||||
}
|
||||
}
|
@ -29,9 +29,9 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
@ -42,85 +42,6 @@ import com.google.common.collect.Sets;
|
||||
* @author Kristian
|
||||
*/
|
||||
public class FuzzyReflection {
|
||||
/**
|
||||
* Represents an interface for accessing a field.
|
||||
* @author Kristian
|
||||
*/
|
||||
public interface FieldAccessor {
|
||||
/**
|
||||
* Retrieve the value of a field for a particular instance.
|
||||
* @param instance - the instance, or NULL for a static field.
|
||||
* @return The value of the field.
|
||||
* @throws IllegalStateException If the current security context prohibits reflection.
|
||||
*/
|
||||
public Object get(Object instance);
|
||||
|
||||
/**
|
||||
* Set the value of a field for a particular instance.
|
||||
* @param instance - the instance, or NULL for a static field.
|
||||
* @param value - the new value of the field.
|
||||
*/
|
||||
public void set(Object instance, Object value);
|
||||
|
||||
/**
|
||||
* Retrieve the underlying field.
|
||||
* @return The field.
|
||||
*/
|
||||
public Field getField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an interface for invoking a method.
|
||||
* @author Kristian
|
||||
*/
|
||||
public interface MethodAccessor {
|
||||
/**
|
||||
* Invoke the underlying method.
|
||||
* @param target - the target instance, or NULL for a static method.
|
||||
* @param args - the arguments to pass to the method.
|
||||
* @return The return value, or NULL for void methods.
|
||||
*/
|
||||
public Object invoke(Object target, Object... args);
|
||||
|
||||
/**
|
||||
* Retrieve the underlying method.
|
||||
* @return The method.
|
||||
*/
|
||||
public Method getMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a field accessor that synchronizes access to the underlying field.
|
||||
* @author Kristian
|
||||
*/
|
||||
private static final class SynchronizedFieldAccessor implements FieldAccessor {
|
||||
private final FieldAccessor accessor;
|
||||
private SynchronizedFieldAccessor(FieldAccessor accessor) {
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object instance, Object value) {
|
||||
Object lock = accessor.get(instance);
|
||||
|
||||
if (lock != null) {
|
||||
synchronized (lock) {
|
||||
accessor.set(instance, value);
|
||||
}
|
||||
} else {
|
||||
accessor.set(instance, value);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public Object get(Object instance) {
|
||||
return accessor.get(instance);
|
||||
}
|
||||
@Override
|
||||
public Field getField() {
|
||||
return accessor.getField();
|
||||
}
|
||||
}
|
||||
|
||||
// The class we're actually representing
|
||||
private Class<?> source;
|
||||
|
||||
@ -170,107 +91,6 @@ public class FuzzyReflection {
|
||||
return new FuzzyReflection(reference.getClass(), forceAccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an accessor for the first field of the given type.
|
||||
* @param instanceClass - the type of the instance to retrieve.
|
||||
* @param fieldClass - type of the field to retrieve.
|
||||
* @param forceAccess - whether or not to look for private and protected fields.
|
||||
* @return The value of that field.
|
||||
* @throws IllegalArgumentException If the field cannot be found.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessor(Class<?> instanceClass, Class<?> fieldClass, boolean forceAccess) {
|
||||
// Get a field accessor
|
||||
Field field = FuzzyReflection.fromClass(instanceClass, forceAccess).getFieldByType(null, fieldClass);
|
||||
return getFieldAccessor(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an accessor for the first field of the given type.
|
||||
* @param instanceClass - the type of the instance to retrieve.
|
||||
* @param fieldClass - type of the field to retrieve.
|
||||
* @param forceAccess - whether or not to look for private and protected fields.
|
||||
* @return The value of that field.
|
||||
* @throws IllegalArgumentException If the field cannot be found.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessor(Class<?> instanceClass, String fieldName, boolean forceAccess) {
|
||||
return getFieldAccessor(FieldUtils.getField(instanceClass, fieldName, forceAccess));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor from a given field that uses unchecked exceptions.
|
||||
* @param field - the field.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessor(final Field field) {
|
||||
return getFieldAccessor(field, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor from a given field that uses unchecked exceptions.
|
||||
* @param field - the field.
|
||||
* @param forceAccess - whether or not to skip Java access checking.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessor(final Field field, boolean forceAccess) {
|
||||
field.setAccessible(true);
|
||||
return new DefaultFieldAccessor(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor where the write operation is synchronized on the current field value.
|
||||
* @param accessor - the accessor.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static FieldAccessor getSynchronized(final FieldAccessor accessor) {
|
||||
// Only wrap once
|
||||
if (accessor instanceof SynchronizedFieldAccessor)
|
||||
return accessor;
|
||||
return new SynchronizedFieldAccessor(accessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a method accessor for a method with the given name and signature.
|
||||
* @param instanceClass - the parent class.
|
||||
* @param name - the method name.
|
||||
* @param parameters - the parameters.
|
||||
* @return The method accessor.
|
||||
*/
|
||||
public static MethodAccessor getMethodAccessor(Class<?> instanceClass, String name, Class<?>... parameters) {
|
||||
return getMethodAccessor(instanceClass, instanceClass, name, parameters);
|
||||
}
|
||||
|
||||
// Helper method
|
||||
private static MethodAccessor getMethodAccessor(
|
||||
Class<?> initialClass, Class<?> instanceClass, String name, Class<?>... parameters) {
|
||||
|
||||
try {
|
||||
Method method = instanceClass.getDeclaredMethod(name, parameters);
|
||||
method.setAccessible(true);
|
||||
return getMethodAccessor(method);
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Search for a private method in the superclass
|
||||
if (initialClass.getSuperclass() != null)
|
||||
return getMethodAccessor(initialClass, instanceClass.getSuperclass(), name, parameters);
|
||||
|
||||
// Unable to find it
|
||||
throw new IllegalArgumentException("Unable to find method " + name +
|
||||
"(" + Joiner.on(", ").join(parameters) +") in " + initialClass);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to retrieve methods.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a method accessor for a particular method, avoding checked exceptions.
|
||||
* @param method - the method to access.
|
||||
* @return The method accessor.
|
||||
*/
|
||||
public static MethodAccessor getMethodAccessor(final Method method) {
|
||||
return new DefaultMethodAccessor(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value of the first field of the given type.
|
||||
* @param instance - the instance to retrieve from.
|
||||
@ -281,7 +101,7 @@ public class FuzzyReflection {
|
||||
*/
|
||||
public static <T> T getFieldValue(Object instance, Class<T> fieldClass, boolean forceAccess) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T result = (T) getFieldAccessor(instance.getClass(), fieldClass, forceAccess).get(instance);
|
||||
T result = (T) Accessors.getFieldAccessor(instance.getClass(), fieldClass, forceAccess).get(instance);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,8 @@ package com.comphenix.protocol.reflect;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
@ -48,7 +49,7 @@ public class VolatileField {
|
||||
* @param container - the object this field belongs to.
|
||||
*/
|
||||
public VolatileField(Field field, Object container) {
|
||||
this.accessor = FuzzyReflection.getFieldAccessor(field);
|
||||
this.accessor = Accessors.getFieldAccessor(field);
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
@ -59,7 +60,7 @@ public class VolatileField {
|
||||
* @param forceAccess - whether or not to override any scope restrictions.
|
||||
*/
|
||||
public VolatileField(Field field, Object container, boolean forceAccess) {
|
||||
this.accessor = FuzzyReflection.getFieldAccessor(field, true);
|
||||
this.accessor = Accessors.getFieldAccessor(field, true);
|
||||
this.container = container;
|
||||
this.forceAccess = forceAccess;
|
||||
}
|
||||
@ -193,7 +194,7 @@ public class VolatileField {
|
||||
* @return A synchronized volatile field.
|
||||
*/
|
||||
public VolatileField toSynchronized() {
|
||||
return new VolatileField(FuzzyReflection.getSynchronized(accessor), container);
|
||||
return new VolatileField(Accessors.getSynchronized(accessor), container);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,125 @@
|
||||
package com.comphenix.protocol.reflect.accessors;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.comphenix.protocol.reflect.ExactReflection;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
|
||||
public final class Accessors {
|
||||
/**
|
||||
* Represents a field accessor that synchronizes access to the underlying field.
|
||||
* @author Kristian
|
||||
*/
|
||||
public static final class SynchronizedFieldAccessor implements FieldAccessor {
|
||||
private final FieldAccessor accessor;
|
||||
private SynchronizedFieldAccessor(FieldAccessor accessor) {
|
||||
this.accessor = accessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object instance, Object value) {
|
||||
Object lock = accessor.get(instance);
|
||||
|
||||
if (lock != null) {
|
||||
synchronized (lock) {
|
||||
accessor.set(instance, value);
|
||||
}
|
||||
} else {
|
||||
accessor.set(instance, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object instance) {
|
||||
return accessor.get(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Field getField() {
|
||||
return accessor.getField();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an accessor for the first field of the given type.
|
||||
* @param instanceClass - the type of the instance to retrieve.
|
||||
* @param fieldClass - type of the field to retrieve.
|
||||
* @param forceAccess - whether or not to look for private and protected fields.
|
||||
* @return The value of that field.
|
||||
* @throws IllegalArgumentException If the field cannot be found.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessor(Class<?> instanceClass, Class<?> fieldClass, boolean forceAccess) {
|
||||
// Get a field accessor
|
||||
Field field = FuzzyReflection.fromClass(instanceClass, forceAccess).getFieldByType(null, fieldClass);
|
||||
return Accessors.getFieldAccessor(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an accessor for the first field of the given type.
|
||||
* @param instanceClass - the type of the instance to retrieve.
|
||||
* @param fieldClass - type of the field to retrieve.
|
||||
* @param forceAccess - whether or not to look for private and protected fields.
|
||||
* @return The value of that field.
|
||||
* @throws IllegalArgumentException If the field cannot be found.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessor(Class<?> instanceClass, String fieldName, boolean forceAccess) {
|
||||
return Accessors.getFieldAccessor(ExactReflection.fromClass(instanceClass, true).getField(fieldName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor from a given field that uses unchecked exceptions.
|
||||
* @param field - the field.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessor(final Field field) {
|
||||
return Accessors.getFieldAccessor(field, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor from a given field that uses unchecked exceptions.
|
||||
* @param field - the field.
|
||||
* @param forceAccess - whether or not to skip Java access checking.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static FieldAccessor getFieldAccessor(final Field field, boolean forceAccess) {
|
||||
field.setAccessible(true);
|
||||
return new DefaultFieldAccessor(field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a field accessor where the write operation is synchronized on the current field value.
|
||||
* @param accessor - the accessor.
|
||||
* @return The field accessor.
|
||||
*/
|
||||
public static FieldAccessor getSynchronized(final FieldAccessor accessor) {
|
||||
// Only wrap once
|
||||
if (accessor instanceof SynchronizedFieldAccessor)
|
||||
return accessor;
|
||||
return new SynchronizedFieldAccessor(accessor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a method accessor for a method with the given name and signature.
|
||||
* @param instanceClass - the parent class.
|
||||
* @param methodName - the method name.
|
||||
* @param parameters - the parameters.
|
||||
* @return The method accessor.
|
||||
*/
|
||||
public static MethodAccessor getMethodAccessor(Class<?> instanceClass, String methodName, Class<?>... parameters) {
|
||||
return new DefaultMethodAccessor(ExactReflection.fromClass(instanceClass, true).getMethod(methodName, parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a method accessor for a particular method, avoding checked exceptions.
|
||||
* @param method - the method to access.
|
||||
* @return The method accessor.
|
||||
*/
|
||||
public static MethodAccessor getMethodAccessor(final Method method) {
|
||||
return new DefaultMethodAccessor(method);
|
||||
}
|
||||
|
||||
// Seal this class
|
||||
private Accessors() {
|
||||
}
|
||||
}
|
@ -1,9 +1,7 @@
|
||||
package com.comphenix.protocol.reflect;
|
||||
package com.comphenix.protocol.reflect.accessors;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.FieldAccessor;
|
||||
|
||||
final class DefaultFieldAccessor implements FieldAccessor {
|
||||
private final Field field;
|
||||
|
@ -1,10 +1,8 @@
|
||||
package com.comphenix.protocol.reflect;
|
||||
package com.comphenix.protocol.reflect.accessors;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.MethodAccessor;
|
||||
|
||||
final class DefaultMethodAccessor implements MethodAccessor {
|
||||
private final Method method;
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.comphenix.protocol.reflect.accessors;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Represents an interface for accessing a field.
|
||||
* @author Kristian
|
||||
*/
|
||||
public interface FieldAccessor {
|
||||
/**
|
||||
* Retrieve the value of a field for a particular instance.
|
||||
* @param instance - the instance, or NULL for a static field.
|
||||
* @return The value of the field.
|
||||
* @throws IllegalStateException If the current security context prohibits reflection.
|
||||
*/
|
||||
public Object get(Object instance);
|
||||
|
||||
/**
|
||||
* Set the value of a field for a particular instance.
|
||||
* @param instance - the instance, or NULL for a static field.
|
||||
* @param value - the new value of the field.
|
||||
*/
|
||||
public void set(Object instance, Object value);
|
||||
|
||||
/**
|
||||
* Retrieve the underlying field.
|
||||
* @return The field.
|
||||
*/
|
||||
public Field getField();
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.comphenix.protocol.reflect.accessors;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Represents an interface for invoking a method.
|
||||
* @author Kristian
|
||||
*/
|
||||
public interface MethodAccessor {
|
||||
/**
|
||||
* Invoke the underlying method.
|
||||
* @param target - the target instance, or NULL for a static method.
|
||||
* @param args - the arguments to pass to the method.
|
||||
* @return The return value, or NULL for void methods.
|
||||
*/
|
||||
public Object invoke(Object target, Object... args);
|
||||
|
||||
/**
|
||||
* Retrieve the underlying method.
|
||||
* @return The method.
|
||||
*/
|
||||
public Method getMethod();
|
||||
}
|
@ -12,8 +12,8 @@ import java.nio.channels.GatheringByteChannel;
|
||||
import java.nio.channels.ScatteringByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.io.LimitInputStream;
|
||||
|
||||
@ -47,10 +47,10 @@ class ByteBufAdapter extends AbstractByteBuf {
|
||||
// Prepare accessors
|
||||
try {
|
||||
if (READER_INDEX == null) {
|
||||
READER_INDEX = FuzzyReflection.getFieldAccessor(AbstractByteBuf.class.getDeclaredField("readerIndex"));
|
||||
READER_INDEX = Accessors.getFieldAccessor(AbstractByteBuf.class.getDeclaredField("readerIndex"));
|
||||
}
|
||||
if (WRITER_INDEX == null) {
|
||||
WRITER_INDEX = FuzzyReflection.getFieldAccessor(AbstractByteBuf.class.getDeclaredField("writerIndex"));
|
||||
WRITER_INDEX = Accessors.getFieldAccessor(AbstractByteBuf.class.getDeclaredField("writerIndex"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot initialize ByteBufAdapter.", e);
|
||||
|
@ -33,7 +33,8 @@ import com.comphenix.protocol.injector.PacketConstructor;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.google.common.base.Strings;
|
||||
@ -108,10 +109,10 @@ public class ChatExtensions {
|
||||
|
||||
// Try one of the string constructors
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
messageFactory = FuzzyReflection.getMethodAccessor(
|
||||
messageFactory = Accessors.getMethodAccessor(
|
||||
MinecraftReflection.getCraftMessageClass(), "fromString", String.class);
|
||||
} else {
|
||||
messageFactory = FuzzyReflection.getMethodAccessor(
|
||||
messageFactory = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(messageClass).getMethod(
|
||||
FuzzyMethodContract.newBuilder().
|
||||
requireModifier(Modifier.STATIC).
|
||||
|
@ -3,8 +3,8 @@ package com.comphenix.protocol.utility;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
|
||||
/**
|
||||
* Retrieve the content of well-known fields in Minecraft.
|
||||
@ -30,7 +30,7 @@ public class MinecraftFields {
|
||||
if (NETWORK_ACCESSOR == null) {
|
||||
Class<?> networkClass = MinecraftReflection.getNetworkManagerClass();
|
||||
Class<?> connectionClass = MinecraftReflection.getNetServerHandlerClass();
|
||||
NETWORK_ACCESSOR = FuzzyReflection.getFieldAccessor(connectionClass, networkClass, true);
|
||||
NETWORK_ACCESSOR = Accessors.getFieldAccessor(connectionClass, networkClass, true);
|
||||
}
|
||||
// Retrieve the network manager
|
||||
return NETWORK_ACCESSOR.get(getPlayerConnection(nmsPlayer));
|
||||
@ -49,7 +49,7 @@ public class MinecraftFields {
|
||||
private static Object getPlayerConnection(Object nmsPlayer) {
|
||||
if (CONNECTION_ACCESSOR == null) {
|
||||
Class<?> connectionClass = MinecraftReflection.getNetServerHandlerClass();
|
||||
CONNECTION_ACCESSOR = FuzzyReflection.getFieldAccessor(nmsPlayer.getClass(), connectionClass, true);
|
||||
CONNECTION_ACCESSOR = Accessors.getFieldAccessor(nmsPlayer.getClass(), connectionClass, true);
|
||||
}
|
||||
return CONNECTION_ACCESSOR.get(nmsPlayer);
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.reflect.ClassAnalyser;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.ClassAnalyser.AsmMethod;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.compiler.EmptyClassVisitor;
|
||||
import com.comphenix.protocol.reflect.compiler.EmptyMethodVisitor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.AbstractFuzzyMatcher;
|
||||
@ -654,7 +655,7 @@ public class MinecraftReflection {
|
||||
return getMinecraftClass("IChatBaseComponent");
|
||||
} catch (RuntimeException e) {
|
||||
return setMinecraftClass("IChatBaseComponent",
|
||||
FuzzyReflection.getMethodAccessor(getCraftChatMessage(), "fromString", String.class).
|
||||
Accessors.getMethodAccessor(getCraftChatMessage(), "fromString", String.class).
|
||||
getMethod().getReturnType().getComponentType()
|
||||
);
|
||||
}
|
||||
|
@ -13,7 +13,8 @@ import org.bukkit.inventory.ItemStack;
|
||||
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
@ -100,7 +101,7 @@ public class StreamSerializer {
|
||||
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
if (READ_ITEM_METHOD == null) {
|
||||
READ_ITEM_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
READ_ITEM_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
|
||||
getMethodByParameters("readItemStack",
|
||||
MinecraftReflection.getItemStackClass(), new Class<?>[0])
|
||||
@ -110,7 +111,7 @@ public class StreamSerializer {
|
||||
|
||||
} else {
|
||||
if (READ_ITEM_METHOD == null) {
|
||||
READ_ITEM_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
READ_ITEM_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
|
||||
FuzzyMethodContract.newBuilder().
|
||||
parameterCount(1).
|
||||
@ -143,7 +144,7 @@ public class StreamSerializer {
|
||||
// Invoke the correct method
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
if (READ_NBT_METHOD == null) {
|
||||
READ_NBT_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
READ_NBT_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
|
||||
getMethodByParameters("readNbtCompound",
|
||||
MinecraftReflection.getNBTCompoundClass(), new Class<?>[0])
|
||||
@ -153,7 +154,7 @@ public class StreamSerializer {
|
||||
|
||||
} else {
|
||||
if (READ_NBT_METHOD == null) {
|
||||
READ_NBT_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
READ_NBT_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
|
||||
FuzzyMethodContract.newBuilder().
|
||||
parameterCount(1).
|
||||
@ -196,7 +197,7 @@ public class StreamSerializer {
|
||||
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
if (READ_STRING_METHOD == null) {
|
||||
READ_STRING_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
READ_STRING_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
|
||||
getMethodByParameters("readString", String.class, new Class<?>[] { int.class })
|
||||
);
|
||||
@ -205,7 +206,7 @@ public class StreamSerializer {
|
||||
|
||||
} else {
|
||||
if (READ_STRING_METHOD == null) {
|
||||
READ_STRING_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
READ_STRING_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
|
||||
FuzzyMethodContract.newBuilder().
|
||||
parameterCount(2).
|
||||
@ -254,7 +255,7 @@ public class StreamSerializer {
|
||||
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
if (WRITE_ITEM_METHOD == null) {
|
||||
WRITE_ITEM_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
WRITE_ITEM_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
|
||||
getMethodByParameters("writeStack", MinecraftReflection.getItemStackClass())
|
||||
);
|
||||
@ -263,7 +264,7 @@ public class StreamSerializer {
|
||||
|
||||
} else {
|
||||
if (WRITE_ITEM_METHOD == null)
|
||||
WRITE_ITEM_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
WRITE_ITEM_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
|
||||
FuzzyMethodContract.newBuilder().
|
||||
parameterCount(2).
|
||||
@ -293,7 +294,7 @@ public class StreamSerializer {
|
||||
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
if (WRITE_NBT_METHOD == null) {
|
||||
WRITE_NBT_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
WRITE_NBT_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
|
||||
getMethodByParameters("writeNbtCompound", MinecraftReflection.getNBTCompoundClass())
|
||||
);
|
||||
@ -302,7 +303,7 @@ public class StreamSerializer {
|
||||
|
||||
} else {
|
||||
if (WRITE_NBT_METHOD == null) {
|
||||
WRITE_NBT_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
WRITE_NBT_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true).getMethod(
|
||||
FuzzyMethodContract.newBuilder().
|
||||
parameterCount(2).
|
||||
@ -332,7 +333,7 @@ public class StreamSerializer {
|
||||
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
if (WRITE_STRING_METHOD == null) {
|
||||
WRITE_STRING_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
WRITE_STRING_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketDataSerializerClass(), true).
|
||||
getMethodByParameters("writeString", String.class)
|
||||
);
|
||||
@ -341,7 +342,7 @@ public class StreamSerializer {
|
||||
|
||||
} else {
|
||||
if (WRITE_STRING_METHOD == null) {
|
||||
WRITE_STRING_METHOD = FuzzyReflection.getMethodAccessor(
|
||||
WRITE_STRING_METHOD = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethod(
|
||||
FuzzyMethodContract.newBuilder().
|
||||
parameterCount(2).
|
||||
|
@ -3,7 +3,8 @@ package com.comphenix.protocol.wrappers;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
/**
|
||||
@ -21,13 +22,13 @@ public class WrappedChatComponent {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(SERIALIZER);
|
||||
|
||||
// Retrieve the correct methods
|
||||
SERIALIZE_COMPONENT = FuzzyReflection.getMethodAccessor(
|
||||
SERIALIZE_COMPONENT = Accessors.getMethodAccessor(
|
||||
fuzzy.getMethodByParameters("serialize", String.class, new Class<?>[] { COMPONENT }));
|
||||
DESERIALIZE_COMPONENT = FuzzyReflection.getMethodAccessor(
|
||||
DESERIALIZE_COMPONENT = Accessors.getMethodAccessor(
|
||||
fuzzy.getMethodByParameters("serialize", COMPONENT, new Class<?>[] { String.class }));
|
||||
|
||||
// Get a component from a standard Minecraft message
|
||||
CONSTRUCT_COMPONENT = FuzzyReflection.getMethodAccessor(
|
||||
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(
|
||||
MinecraftReflection.getCraftChatMessage(), "fromString", String.class);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,57 @@
|
||||
package com.comphenix.protocol.reflect.accessors;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class AccessorsTest {
|
||||
// --- Some classes we can use for testing ---
|
||||
private static class Entity {
|
||||
private int id;
|
||||
|
||||
public Entity(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void setId(int value) {
|
||||
this.id = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Player extends Entity {
|
||||
private String name;
|
||||
|
||||
public Player(int id, String name) {
|
||||
super(id);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
// --- Test classes ---
|
||||
|
||||
@Test
|
||||
public void testField() {
|
||||
Player player = new Player(123, "ABC");
|
||||
|
||||
Accessors.getFieldAccessor(player.getClass(), "id", true).set(player, 0);
|
||||
Accessors.getFieldAccessor(player.getClass(), "name", true).set(player, "MODIFIED");
|
||||
assertEquals(0, player.getId());
|
||||
assertEquals("MODIFIED", player.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethod() {
|
||||
Player player = new Player(123, "ABC");
|
||||
|
||||
Accessors.getMethodAccessor(player.getClass(), "setId", int.class).invoke(player, 0);
|
||||
assertEquals(0, player.getId());
|
||||
}
|
||||
}
|
In neuem Issue referenzieren
Einen Benutzer sperren