package choonster.testmod3.util; import net.minecraftforge.fml.relauncher.ReflectionHelper; import net.minecraftforge.fml.relauncher.ReflectionHelper.UnableToFindFieldException; import javax.annotation.Nullable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * Utility methods for reflection. * * @author Choonster */ public class ReflectionUtil { /** * Get a {@link MethodHandle} for a method. * * @param clazz The class to find the method on. * @param methodName The name of the method to find (used in developer environments, e.g. "getWorldTime"). * @param methodObfName The obfuscated name of the method to find (used in obfuscated environments, e.g. "func_72820_D"). * If the name you are looking for is on a class that is never obfuscated, this should be null. * @param parameterTypes The parameter types of the method to find. * @return The MethodHandle */ public static MethodHandle findMethod(final Class<?> clazz, final String methodName, @Nullable final String methodObfName, final Class<?>... parameterTypes) { final Method method = ReflectionHelper.findMethod(clazz, methodName, methodObfName, parameterTypes); try { return MethodHandles.lookup().unreflect(method); } catch (IllegalAccessException e) { throw new ReflectionHelper.UnableToFindMethodException(e); } } /** * Get an array of field names to pass to {@link ReflectionHelper#findField}. * <p> * Passing a {@code null} field name to the method would throw a {@link UnableToFindFieldException} with a * {@link NullPointerException} as the cause instead of a {@link NoSuchFieldException}. * * @param fieldName The name of the field * @param fieldObfName The obfuscated name of the field * @return An array of field names */ private static String[] getFieldNameArray(final String fieldName, @Nullable final String fieldObfName) { if (fieldObfName != null) { return new String[]{fieldName, fieldObfName}; } else { return new String[]{fieldName}; } } /** * Get a {@link MethodHandle} for a field's getter. * * @param clazz The class * @param fieldName The name of the field to find (used in developer environments, e.g. "worldInfo"). * @param fieldObfName The obfuscated name of the field to find (used in obfuscated environments, e.g. "field_72986_A"). * If the name you are looking for is on a class that is never obfuscated, this should be null. * @return The MethodHandle */ public static MethodHandle findFieldGetter(final Class<?> clazz, final String fieldName, @Nullable final String fieldObfName) { final Field field = ReflectionHelper.findField(clazz, getFieldNameArray(fieldName, fieldObfName)); try { return MethodHandles.lookup().unreflectGetter(field); } catch (IllegalAccessException e) { throw new ReflectionHelper.UnableToAccessFieldException(new String[0], e); } } /** * Get a {@link MethodHandle} for a field's setter. * * @param clazz The class * @param fieldName The name of the field to find (used in developer environments, e.g. "worldInfo"). * @param fieldObfName The obfuscated name of the field to find (used in obfuscated environments, e.g. "field_72986_A"). * If the name you are looking for is on a class that is never obfuscated, this should be null. * @return The MethodHandle */ public static MethodHandle findFieldSetter(Class<?> clazz, final String fieldName, @Nullable final String fieldObfName) { final Field field = ReflectionHelper.findField(clazz, getFieldNameArray(fieldName, fieldObfName)); try { return MethodHandles.lookup().unreflectSetter(field); } catch (IllegalAccessException e) { throw new ReflectionHelper.UnableToAccessFieldException(new String[0], e); } } }