Reflect: classes are now generic and added Constructor reflection
This commit is contained in:
parent
c1219336b5
commit
b7b89f3ea9
@ -1,5 +1,6 @@
|
|||||||
package fr.pandacube.lib.core.util;
|
package fr.pandacube.lib.core.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
@ -43,17 +44,18 @@ public class Reflect {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static final Map<Class<?>, ReflectClass> classCache;
|
private static final Map<Class<?>, ReflectClass<?>> classCache;
|
||||||
|
|
||||||
public static ReflectClass ofClass(Class<?> clazz) {
|
@SuppressWarnings("unchecked")
|
||||||
return classCache.computeIfAbsent(clazz, ReflectClass::new);
|
public static <T> ReflectClass<T> ofClass(Class<T> clazz) {
|
||||||
|
return (ReflectClass<T>) classCache.computeIfAbsent(clazz, ReflectClass::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReflectClass ofClass(String className) throws ClassNotFoundException {
|
public static ReflectClass<?> ofClass(String className) throws ClassNotFoundException {
|
||||||
return ofClass(Class.forName(className));
|
return ofClass(Class.forName(className));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReflectClass ofClassOfInstance(Object instance) {
|
public static ReflectClass<?> ofClassOfInstance(Object instance) {
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
throw new IllegalArgumentException("instance can't be null");
|
throw new IllegalArgumentException("instance can't be null");
|
||||||
return ofClass(instance.getClass());
|
return ofClass(instance.getClass());
|
||||||
@ -83,31 +85,55 @@ public class Reflect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private record ConstructorIdentifier(Class<?>[] parameters) {
|
||||||
|
private ConstructorIdentifier {
|
||||||
|
parameters = (parameters == null) ? new Class<?>[0] : parameters;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
return other != null && other instanceof ConstructorIdentifier o
|
||||||
|
&& Arrays.equals(o.parameters, parameters);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Arrays.hashCode(parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static class ReflectClass {
|
|
||||||
private Class<?> clazz;
|
public static class ReflectClass<T> {
|
||||||
|
private Class<T> clazz;
|
||||||
private final Map<MethodIdentifier, ReflectMethod> methodCache = Collections.synchronizedMap(new HashMap<>());
|
|
||||||
private final Map<String, ReflectField> fieldCache = Collections.synchronizedMap(new HashMap<>());
|
private final Map<MethodIdentifier, ReflectMethod<T>> methodCache = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
private final Map<ConstructorIdentifier, ReflectConstructor<T>> constructorCache = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
private final Map<String, ReflectField<T>> fieldCache = Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
private ReflectClass(Class<?> clazz) {
|
private ReflectClass(Class<T> clazz) {
|
||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReflectMethod method(MethodIdentifier key) {
|
private ReflectMethod<T> method(MethodIdentifier key) {
|
||||||
return methodCache.computeIfAbsent(key, k -> new ReflectMethod(this, k));
|
return methodCache.computeIfAbsent(key, k -> new ReflectMethod<>(this, k));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReflectMethod method(String name, Class<?>... paramTypes) {
|
public ReflectMethod<T> method(String name, Class<?>... paramTypes) {
|
||||||
return method(new MethodIdentifier(name, paramTypes));
|
return method(new MethodIdentifier(name, paramTypes));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReflectField field(String name) {
|
private ReflectConstructor<T> constructor(ConstructorIdentifier key) {
|
||||||
return fieldCache.computeIfAbsent(name, n -> new ReflectField(this, n));
|
return constructorCache.computeIfAbsent(key, k -> new ReflectConstructor<>(this, k));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReflectConstructor<T> constructor(Class<?>... paramTypes) {
|
||||||
|
return constructor(new ConstructorIdentifier(paramTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReflectField<T> field(String name) {
|
||||||
|
return fieldCache.computeIfAbsent(name, n -> new ReflectField<>(this, n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,23 +159,23 @@ public class Reflect {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static abstract class ReflectClassEl {
|
public static abstract class ReflectClassEl<T> {
|
||||||
ReflectClass reflectClass;
|
ReflectClass<T> reflectClass;
|
||||||
String elementName;
|
|
||||||
|
|
||||||
protected ReflectClassEl(ReflectClass c, String elementName) {
|
protected ReflectClassEl(ReflectClass<T> c) {
|
||||||
reflectClass = c;
|
reflectClass = c;
|
||||||
this.elementName = elementName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ReflectField extends ReflectClassEl {
|
public static class ReflectField<T> extends ReflectClassEl<T> {
|
||||||
|
String elementName;
|
||||||
|
|
||||||
private Field cached, cachedFiltered;
|
private Field cached, cachedFiltered;
|
||||||
|
|
||||||
/* package */ ReflectField(ReflectClass c, String name) {
|
/* package */ ReflectField(ReflectClass<T> c, String name) {
|
||||||
super(c, name);
|
super(c);
|
||||||
|
elementName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Field get() throws NoSuchFieldException {
|
public synchronized Field get() throws NoSuchFieldException {
|
||||||
@ -217,15 +243,17 @@ public class Reflect {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ReflectMethod extends ReflectClassEl {
|
public static class ReflectMethod<T> extends ReflectClassEl<T> {
|
||||||
|
String elementName;
|
||||||
|
|
||||||
private Method cached, cachedFiltered;
|
private Method cached, cachedFiltered;
|
||||||
|
|
||||||
MethodIdentifier methodId;
|
MethodIdentifier methodId;
|
||||||
Class<?>[] parameterTypes;
|
Class<?>[] parameterTypes;
|
||||||
|
|
||||||
/* package */ ReflectMethod(ReflectClass c, MethodIdentifier methodId) {
|
/* package */ ReflectMethod(ReflectClass<T> c, MethodIdentifier methodId) {
|
||||||
super(c, methodId.methodName);
|
super(c);
|
||||||
|
this.elementName = methodId.methodName;
|
||||||
this.methodId = methodId;
|
this.methodId = methodId;
|
||||||
parameterTypes = methodId.parameters;
|
parameterTypes = methodId.parameters;
|
||||||
}
|
}
|
||||||
@ -261,6 +289,46 @@ public class Reflect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ReflectConstructor<T> extends ReflectClassEl<T> {
|
||||||
|
|
||||||
|
private Constructor<T> cached, cachedFiltered;
|
||||||
|
|
||||||
|
ConstructorIdentifier constructorId;
|
||||||
|
Class<?>[] parameterTypes;
|
||||||
|
|
||||||
|
/* package */ ReflectConstructor(ReflectClass<T> c, ConstructorIdentifier constructorId) {
|
||||||
|
super(c);
|
||||||
|
this.constructorId = constructorId;
|
||||||
|
parameterTypes = constructorId.parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Constructor<T> get() throws NoSuchMethodException {
|
||||||
|
if (cached == null) {
|
||||||
|
Constructor<T> el = null;
|
||||||
|
el = reflectClass.clazz.getDeclaredConstructor(parameterTypes);
|
||||||
|
el.setAccessible(true);
|
||||||
|
cached = el;
|
||||||
|
}
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* package */ Constructor<T> getFiltered() throws NoSuchMethodException {
|
||||||
|
if (cachedFiltered == null) {
|
||||||
|
cachedFiltered = Reflect.getFiltered(reflectClass.clazz,
|
||||||
|
c -> c.getDeclaredConstructor(parameterTypes),
|
||||||
|
m -> m.setAccessible(true),
|
||||||
|
m -> Arrays.equals(parameterTypes, m.getParameterTypes()),
|
||||||
|
"getDeclaredConstructors0", "copyConstructor");
|
||||||
|
}
|
||||||
|
return cachedFiltered;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T instanciate(Object... values) throws ReflectiveOperationException {
|
||||||
|
return get().newInstance(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -272,13 +340,17 @@ public class Reflect {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private interface GetReflectiveElement<T, E extends ReflectiveOperationException> {
|
private interface GetUncheckedClassReflectiveElement<T, E extends ReflectiveOperationException> {
|
||||||
public T get(Class<?> clazz) throws E;
|
public T get(Class<?> clazz) throws E;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T, E extends ReflectiveOperationException, K> T getDeclaredRecursively(
|
private interface GetReflectiveElement<C, T, E extends ReflectiveOperationException> {
|
||||||
Class<?> clazz, GetReflectiveElement<T, E> jlrGetter,
|
public T get(Class<C> clazz) throws E;
|
||||||
GetReflectiveElement<T, E> parentGetter, Consumer<T> setAccessible) throws E {
|
}
|
||||||
|
|
||||||
|
private static <C, T, E extends ReflectiveOperationException> T getDeclaredRecursively(
|
||||||
|
Class<C> clazz, GetReflectiveElement<C, T, E> jlrGetter,
|
||||||
|
GetUncheckedClassReflectiveElement<T, E> parentGetter, Consumer<T> setAccessible) throws E {
|
||||||
Objects.requireNonNull(clazz, "Class instance not provided");
|
Objects.requireNonNull(clazz, "Class instance not provided");
|
||||||
|
|
||||||
E ex = null;
|
E ex = null;
|
||||||
@ -289,11 +361,9 @@ public class Reflect {
|
|||||||
el = jlrGetter.get(clazz);
|
el = jlrGetter.get(clazz);
|
||||||
setAccessible.accept(el);
|
setAccessible.accept(el);
|
||||||
} catch (ReflectiveOperationException e) {
|
} catch (ReflectiveOperationException e) {
|
||||||
if (ex == null) {
|
@SuppressWarnings("unchecked")
|
||||||
@SuppressWarnings("unchecked")
|
E ee = (E) e;
|
||||||
E ee = (E) e;
|
ex = ee;
|
||||||
ex = ee;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get element in parent class (will do recursion)
|
// get element in parent class (will do recursion)
|
||||||
@ -318,6 +388,8 @@ public class Reflect {
|
|||||||
return el;
|
return el;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a Field or Method of a class that is not accessible using {@link Class#getDeclaredField(String)}
|
* Get a Field or Method of a class that is not accessible using {@link Class#getDeclaredField(String)}
|
||||||
* or using {@link Class#getDeclaredMethod(String, Class...)} because the implementation of {@link Class}
|
* or using {@link Class#getDeclaredMethod(String, Class...)} because the implementation of {@link Class}
|
||||||
@ -326,8 +398,8 @@ public class Reflect {
|
|||||||
* This method calls an internal method of {@link Class} to retrieve the full list of field or method, then
|
* This method calls an internal method of {@link Class} to retrieve the full list of field or method, then
|
||||||
* search in the list for the requested element.
|
* search in the list for the requested element.
|
||||||
*/
|
*/
|
||||||
private static <T, E extends ReflectiveOperationException, K> T getFiltered(
|
private static <C, T, E extends ReflectiveOperationException> T getFiltered(
|
||||||
Class<?> clazz, GetReflectiveElement<T, E> jlrGetter,
|
Class<C> clazz, GetReflectiveElement<C, T, E> jlrGetter,
|
||||||
Consumer<T> setAccessible, Predicate<T> elementChecker,
|
Consumer<T> setAccessible, Predicate<T> elementChecker,
|
||||||
String privateMethodName, String copyMethodName) throws E {
|
String privateMethodName, String copyMethodName) throws E {
|
||||||
Objects.requireNonNull(clazz, "Class instance not provided");
|
Objects.requireNonNull(clazz, "Class instance not provided");
|
||||||
|
Loading…
Reference in New Issue
Block a user