2021-07-01 20:16:25 +00:00
|
|
|
package com.fastasyncworldedit.core.util;
|
2018-08-12 14:03:07 +00:00
|
|
|
|
2021-07-24 13:52:08 +00:00
|
|
|
import javax.annotation.Nonnull;
|
2020-07-14 02:50:59 +00:00
|
|
|
|
2020-02-22 03:53:25 +00:00
|
|
|
import java.lang.invoke.MethodHandles;
|
2018-08-12 14:03:07 +00:00
|
|
|
import java.lang.reflect.AccessibleObject;
|
|
|
|
import java.lang.reflect.Field;
|
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
import java.lang.reflect.Modifier;
|
2019-06-21 00:05:18 +00:00
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.Comparator;
|
2019-06-12 13:45:41 +00:00
|
|
|
|
2018-08-12 14:03:07 +00:00
|
|
|
public class ReflectionUtils {
|
2020-03-05 21:07:20 +00:00
|
|
|
|
2018-08-12 14:03:07 +00:00
|
|
|
public static <T> T as(Class<T> t, Object o) {
|
|
|
|
return t.isInstance(o) ? t.cast(o) : null;
|
|
|
|
}
|
|
|
|
|
2020-10-05 17:41:41 +00:00
|
|
|
public static void setAccessibleNonFinal(Field field) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
|
2018-08-12 14:03:07 +00:00
|
|
|
// let's make the field accessible
|
|
|
|
field.setAccessible(true);
|
|
|
|
|
|
|
|
// next we change the modifier in the Field instance to
|
|
|
|
// not be final anymore, thus tricking reflection into
|
|
|
|
// letting us modify the static final field
|
2018-08-16 09:56:31 +00:00
|
|
|
if (Modifier.isFinal(field.getModifiers())) {
|
2019-12-21 20:21:25 +00:00
|
|
|
try {
|
2020-02-22 03:53:25 +00:00
|
|
|
Field lookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
|
|
|
|
lookupField.setAccessible(true);
|
2019-12-21 20:21:25 +00:00
|
|
|
|
|
|
|
// blank out the final bit in the modifiers int
|
2020-02-22 03:53:25 +00:00
|
|
|
((MethodHandles.Lookup) lookupField.get(null))
|
2020-03-05 21:07:20 +00:00
|
|
|
.findSetter(Field.class, "modifiers", int.class)
|
2020-02-22 03:53:25 +00:00
|
|
|
.invokeExact(field, field.getModifiers() & ~Modifier.FINAL);
|
|
|
|
} catch (Throwable e) {
|
|
|
|
e.printStackTrace();
|
2019-12-21 20:21:25 +00:00
|
|
|
}
|
2018-08-16 09:56:31 +00:00
|
|
|
}
|
2019-12-21 20:21:25 +00:00
|
|
|
}
|
|
|
|
|
2020-10-05 17:41:41 +00:00
|
|
|
public static void setFailsafeFieldValue(Field field, Object target, Object value) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
|
2019-12-21 20:21:25 +00:00
|
|
|
setAccessibleNonFinal(field);
|
2020-03-05 21:07:20 +00:00
|
|
|
field.set(target, value);
|
2018-08-12 14:03:07 +00:00
|
|
|
}
|
|
|
|
|
2019-08-15 19:21:24 +00:00
|
|
|
public static Object getHandle(Object wrapper) {
|
2018-08-12 14:03:07 +00:00
|
|
|
final Method getHandle = makeMethod(wrapper.getClass(), "getHandle");
|
|
|
|
return callMethod(getHandle, wrapper);
|
|
|
|
}
|
|
|
|
|
|
|
|
//Utils
|
2019-08-15 19:21:24 +00:00
|
|
|
public static Method makeMethod(Class<?> clazz, String methodName, Class<?>... parameters) {
|
2018-08-12 14:03:07 +00:00
|
|
|
try {
|
2019-05-29 03:23:51 +00:00
|
|
|
return clazz.getDeclaredMethod(methodName, parameters);
|
2019-08-15 19:21:24 +00:00
|
|
|
} catch (NoSuchMethodException ex) {
|
2018-08-12 14:03:07 +00:00
|
|
|
return null;
|
2019-08-15 19:21:24 +00:00
|
|
|
} catch (Exception ex) {
|
2018-08-12 14:03:07 +00:00
|
|
|
throw new RuntimeException(ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
2019-08-15 19:21:24 +00:00
|
|
|
public static <T> T callMethod(Method method, Object instance, Object... parameters) {
|
2018-08-12 14:03:07 +00:00
|
|
|
if (method == null) {
|
|
|
|
throw new RuntimeException("No such method");
|
|
|
|
}
|
|
|
|
method.setAccessible(true);
|
|
|
|
try {
|
2019-05-29 03:23:51 +00:00
|
|
|
return (T) method.invoke(instance, parameters);
|
2019-08-15 19:21:24 +00:00
|
|
|
} catch (InvocationTargetException ex) {
|
2018-08-12 14:03:07 +00:00
|
|
|
throw new RuntimeException(ex.getCause());
|
2019-08-15 19:21:24 +00:00
|
|
|
} catch (Exception ex) {
|
2018-08-12 14:03:07 +00:00
|
|
|
throw new RuntimeException(ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Field[] sortFields(Field[] fields) {
|
2019-06-04 15:48:30 +00:00
|
|
|
Arrays.sort(fields, Comparator.comparing(Field::getName));
|
2018-08-12 14:03:07 +00:00
|
|
|
return fields;
|
|
|
|
}
|
|
|
|
|
2019-08-15 19:21:24 +00:00
|
|
|
public static <T extends AccessibleObject> T setAccessible(T ao) {
|
2018-08-12 14:03:07 +00:00
|
|
|
ao.setAccessible(true);
|
|
|
|
return ao;
|
|
|
|
}
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
2021-07-24 13:52:08 +00:00
|
|
|
public static <T> T getField(@Nonnull Field field, Object instance) {
|
2018-08-12 14:03:07 +00:00
|
|
|
field.setAccessible(true);
|
|
|
|
try {
|
|
|
|
return (T) field.get(instance);
|
2019-08-15 19:21:24 +00:00
|
|
|
} catch (Exception ex) {
|
2018-08-12 14:03:07 +00:00
|
|
|
throw new RuntimeException(ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-15 19:21:24 +00:00
|
|
|
public static Class<?> getClass(String name) {
|
2018-08-12 14:03:07 +00:00
|
|
|
try {
|
|
|
|
return Class.forName(name);
|
2019-08-15 19:21:24 +00:00
|
|
|
} catch (ClassNotFoundException ex) {
|
2018-08-12 14:03:07 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-15 19:21:24 +00:00
|
|
|
public static <T> Class<? extends T> getClass(String name, Class<T> superClass) {
|
2018-08-12 14:03:07 +00:00
|
|
|
try {
|
|
|
|
return Class.forName(name).asSubclass(superClass);
|
|
|
|
} catch (ClassCastException | ClassNotFoundException ex) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|