package de.sanandrew.core.manpack.util;
import com.google.common.collect.Maps;
import de.sanandrew.core.manpack.util.helpers.SAPUtils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
public final class SAPReflectionHelper
{
private static Map<String, Method> cachedMethods = Maps.newHashMap();
private static Map<String, Field> cachedFields = Maps.newHashMap();
public static boolean doesClassExist(String className) {
try {
Class.forName(className, false, null);
return true;
} catch( ClassNotFoundException ex ) {
return false;
}
}
public static <T> Class<T> getClass(String className) {
try {
return SAPUtils.getCasted(Class.forName(className));
} catch( ClassNotFoundException | UnsatisfiedLinkError ex ) {
return null;
}
}
public static <T, E> void setCachedFieldValue(Class<? super E> classToAccess, E instance, String mcpName, String srgName, T value) {
Field field = getCachedField(classToAccess, mcpName, srgName);
try {
field.set(instance, value);
} catch( Throwable ex ) {
throw new UnableToSetFieldException(ex);
}
}
@SuppressWarnings( "unchecked" )
public static <T, E> T getCachedFieldValue(Class<? super E> classToAccess, E instance, String mcpName, String srgName) {
Field field = getCachedField(classToAccess, mcpName, srgName);
try {
return (T) field.get(instance);
} catch( IllegalArgumentException | IllegalAccessException ex ) {
throw new UnableToGetFieldException(ex);
}
}
@SuppressWarnings( "unchecked" )
public static <T, E> T invokeCachedMethod(Class<? super E> classToAccess, E instance, String mcpName,
String srgName, Class<?>[] parameterTypes, Object[] parameterValues) {
Method method = getCachedMethod(classToAccess, mcpName, srgName, parameterTypes);
try {
return (T) method.invoke(instance, parameterValues);
} catch( IllegalAccessException | IllegalArgumentException | InvocationTargetException ex ) {
throw new UnableToInvokeMethodException(ex);
}
}
public static Field getCachedField(Class<?> classToAccess, String mcpName, String srgName) {
String key = classToAccess.getCanonicalName() + '_' + srgName;
if( cachedFields.containsKey(key) ) {
return cachedFields.get(key);
}
return cacheAccessedField(classToAccess, mcpName, srgName);
}
private static Field cacheAccessedField(Class<?> classToAccess, String mcpName, String srgName) {
Field method;
String key = classToAccess.getCanonicalName() + '_' + srgName;
try {
method = classToAccess.getDeclaredField(srgName);
method.setAccessible(true);
cachedFields.put(key, method);
return method;
} catch( Throwable ex1 ) {
try {
method = classToAccess.getDeclaredField(mcpName);
method.setAccessible(true);
cachedFields.put(key, method);
return method;
} catch( Throwable ex2 ) {
throw new UnableToAccessFieldException(ex2);
}
}
}
public static Method getCachedMethod(Class<?> classToAccess, String mcpName, String srgName, Class<?>... parameterTypes) {
String key = classToAccess.getCanonicalName() + '_' + srgName;
if( cachedMethods.containsKey(key) ) {
return cachedMethods.get(key);
}
return cacheAccessedMethod(classToAccess, mcpName, srgName, parameterTypes);
}
private static Method cacheAccessedMethod(Class<?> classToAccess, String mcpName, String srgName, Class<?>... parameterTypes) {
Method method;
String key = classToAccess.getCanonicalName() + '_' + srgName;
try {
method = classToAccess.getDeclaredMethod(srgName, parameterTypes);
method.setAccessible(true);
cachedMethods.put(key, method);
return method;
} catch( Throwable ex1 ) {
try {
method = classToAccess.getDeclaredMethod(mcpName, parameterTypes);
method.setAccessible(true);
cachedMethods.put(key, method);
return method;
} catch( Throwable ex2 ) {
throw new UnableToFindMethodException(ex2);
}
}
}
public static class UnableToSetFieldException
extends RuntimeException
{
private static final long serialVersionUID = 1L;
public UnableToSetFieldException(Throwable ex) {
super(ex);
}
}
public static class UnableToGetFieldException
extends RuntimeException
{
private static final long serialVersionUID = 1L;
public UnableToGetFieldException(Throwable failed) {
super(failed);
}
}
public static class UnableToInvokeMethodException
extends RuntimeException
{
private static final long serialVersionUID = 1L;
public UnableToInvokeMethodException(Throwable failed) {
super(failed);
}
}
public static class UnableToFindMethodException
extends RuntimeException
{
private static final long serialVersionUID = 1L;
public UnableToFindMethodException(Throwable failed) {
super(failed);
}
}
public static class UnableToAccessFieldException
extends RuntimeException
{
private static final long serialVersionUID = 1L;
public UnableToAccessFieldException(Throwable failed) {
super(failed);
}
}
}