Core/src/eu/univento/core/api/utils/reflection/IReflection.java

256 lines
9.6 KiB
Java

package eu.univento.core.api.utils.reflection;
import org.bukkit.Bukkit;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/**
* -== IReflection ==-
*
* This library was created by @Ingrim4 and allows you to use the reflection-api implemented in java easily for spigot plugins
* You are welcome to use it and redistribute it under the following conditions:
* * Don't claim this class as your own
* * Don't remove this disclaimer
*
* @author Ingrim4
* @version 1.2.8
*/
public class IReflection {
public interface ConstructorAccessor {
public Object newInstance(Object... args);
public Constructor<?> getConstructor();
}
public interface MethodAccessor {
public Object invoke(Object target, Object... args);
public Method getMehtod();
}
public interface FieldAccessor<T> {
public T get(Object target);
public void set(Object target, Object value);
public Field getField();
}
public static Class<?> getClass(ServerPacket packet, String name) {
try {
return Class.forName(packet + name);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
public static ConstructorAccessor getConstructor(Class<?> clazz, Class<?>... parameterTypes) {
Class<?>[] p = DataType.convertToPrimitive(parameterTypes);
for (Constructor<?> c : clazz.getDeclaredConstructors())
if (DataType.equalsArray(DataType.convertToPrimitive(c.getParameterTypes()), p)) {
c.setAccessible(true);
return new ConstructorAccessor() {
@Override
public Object newInstance(Object... args) {
try {
return c.newInstance(args);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Cannot use reflection.", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("An internal error occured.", e.getCause());
} catch (InstantiationException e) {
throw new RuntimeException("Cannot instantiate object.", e);
} catch (IllegalArgumentException e) {
throw e;
}
}
@Override
public Constructor<?> getConstructor() {
return c;
}
};
}
if (clazz.getSuperclass() != null)
return IReflection.getConstructor(clazz.getSuperclass(), parameterTypes);
return null;
}
public static MethodAccessor getMethod(Class<?> target, String methodName, Class<?>... parameterTypes) {
return IReflection.getMethod(target, methodName, null, parameterTypes);
}
public static MethodAccessor getMethod(Class<?> target, String methodName, Class<?> returnType, Class<?>... parameterTypes) {
Class<?>[] primitiveParameter = DataType.convertToPrimitive(parameterTypes);
for (Method method : target.getDeclaredMethods())
if ((methodName == null || method.getName().equals(methodName)) && (returnType == null || method.getReturnType().equals(returnType)) && (primitiveParameter.length == 0 || DataType.equalsArray(DataType.convertToPrimitive(method.getParameterTypes()), primitiveParameter))) {
method.setAccessible(true);
return new MethodAccessor() {
@Override
public Object invoke(Object target, Object... args) {
try {
return method.invoke(target, args);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Cannot use reflection.", e);
} catch (InvocationTargetException e) {
throw new RuntimeException("An internal error occured.", e.getCause());
} catch (IllegalArgumentException e) {
throw e;
}
}
@Override
public Method getMehtod() {
return method;
}
};
}
if (target.getSuperclass() != null)
return IReflection.getMethod(target.getSuperclass(), methodName, returnType, parameterTypes);
throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, parameterTypes));
}
public static <T> FieldAccessor<T> getField(Class<?> target, String fieldName) {
return IReflection.getField(target, fieldName, null, 0);
}
public static <T> FieldAccessor<T> getField(Class<?> target, Class<T> fieldType, int index) {
return IReflection.getField(target, null, fieldType, index);
}
private static <T> FieldAccessor<T> getField(Class<?> target, String fieldName, Class<T> fieldType, int index) {
for (Field field : target.getDeclaredFields())
if ((fieldName == null || fieldName.equals(field.getName())) && (fieldType == null || (fieldType.isAssignableFrom(field.getType()) && index-- <= 0))) {
field.setAccessible(true);
return new FieldAccessor<T>() {
@Override
@SuppressWarnings("unchecked")
public T get(Object target) {
try {
return (T) field.get(target);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Cannot use reflection.", e);
} catch (IllegalArgumentException e) {
throw e;
}
}
@Override
public void set(Object target, Object value) {
try {
field.set(target, value);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Cannot use reflection.", e);
} catch (IllegalArgumentException e) {
throw e;
}
}
@Override
public Field getField() {
return field;
}
};
}
if (target.getSuperclass() != null)
return IReflection.getField(target.getSuperclass(), fieldName, fieldType, index);
throw new IllegalStateException(String.format("Unable to find field %s (%s).", fieldName, fieldType));
}
public enum DataType {
BYTE(byte.class, Byte.class), SHORT(short.class, Short.class), INTEGER(int.class,
Integer.class), LONG(long.class, Long.class), CHARACTER(char.class, Character.class), FLOAT(float.class,
Float.class), DOUBLE(double.class, Double.class), BOOLEAN(boolean.class, Boolean.class);
private static final Map<Class<?>, DataType> CLASS_MAP = new HashMap<Class<?>, DataType>();
private final Class<?> primitive;
private final Class<?> reference;
static {
for (DataType t : DataType.values()) {
DataType.CLASS_MAP.put(t.primitive, t);
DataType.CLASS_MAP.put(t.reference, t);
}
}
private DataType(Class<?> primitive, Class<?> reference) {
this.primitive = primitive;
this.reference = reference;
}
public Class<?> getPrimitive() {
return this.primitive;
}
public Class<?> getReference() {
return this.reference;
}
public static DataType fromClass(Class<?> c) {
return DataType.CLASS_MAP.get(c);
}
public static Class<?> getPrimitive(Class<?> c) {
DataType t = DataType.fromClass(c);
return t == null ? c : t.getPrimitive();
}
public static Class<?> getReference(Class<?> c) {
DataType t = DataType.fromClass(c);
return t == null ? c : t.getReference();
}
public static Class<?>[] convertToPrimitive(Class<?>[] classes) {
int length = classes == null ? 0 : classes.length;
Class<?>[] types = new Class<?>[length];
for (int i = 0; i < length; i++)
types[i] = DataType.getPrimitive(classes[i]);
return types;
}
public static boolean equalsArray(Class<?>[] a1, Class<?>[] a2) {
if (a1 == null || a2 == null || a1.length != a2.length)
return false;
for (int i = 0; i < a1.length; i++)
if (!a1[i].equals(a2[i]) && !a1[i].isAssignableFrom(a2[i]))
return false;
return true;
}
}
public enum ServerPacket {
MINECRAFT_PACKAGE("net.minecraft.server." + Bukkit.getServer().getClass().getPackage().getName().substring(23)), MOJANG_AUTHLIB("com.mojang.authlib"), CRAFTBUKKIT_PACKAGE(Bukkit.getServer().getClass().getPackage().getName());
ServerPacket(String source) {
this.name = source;
}
private final String name;
@Override
public String toString() {
return this.name + ".";
}
}
}