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 { 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 FieldAccessor getField(Class target, String fieldName) { return IReflection.getField(target, fieldName, null, 0); } public static FieldAccessor getField(Class target, Class fieldType, int index) { return IReflection.getField(target, null, fieldType, index); } private static FieldAccessor getField(Class target, String fieldName, Class 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() { @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, DataType> CLASS_MAP = new HashMap, 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 + "."; } } }