Some refactor of Reflect class
This commit is contained in:
parent
66cbf8097c
commit
774b5f9e47
@ -12,8 +12,6 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
@ -106,7 +104,7 @@ public class Reflect {
|
|||||||
|
|
||||||
|
|
||||||
public static class ReflectClass<T> {
|
public static class ReflectClass<T> {
|
||||||
private Class<T> clazz;
|
private final Class<T> clazz;
|
||||||
|
|
||||||
private final Map<MethodIdentifier, ReflectMethod<T>> methodCache = 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<ConstructorIdentifier, ReflectConstructor<T>> constructorCache = Collections.synchronizedMap(new HashMap<>());
|
||||||
@ -116,24 +114,62 @@ public class Reflect {
|
|||||||
this.clazz = clazz;
|
this.clazz = clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReflectMethod<T> method(MethodIdentifier key) {
|
/**
|
||||||
return methodCache.computeIfAbsent(key, k -> new ReflectMethod<>(this, k));
|
* Returns the class wrapped by this ReflectClass instance.
|
||||||
|
*/
|
||||||
|
public Class<T> get() {
|
||||||
|
return clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReflectMethod<T> method(String name, Class<?>... paramTypes) {
|
private ReflectMethod<T> method(MethodIdentifier key, boolean bypassFilter) throws NoSuchMethodException {
|
||||||
return method(new MethodIdentifier(name, paramTypes));
|
ReflectMethod<T> method = methodCache.get(key);
|
||||||
|
if (method == null) {
|
||||||
|
method = new ReflectMethod<>(this, key, bypassFilter);
|
||||||
|
methodCache.put(key, method);
|
||||||
|
}
|
||||||
|
return method;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReflectConstructor<T> constructor(ConstructorIdentifier key) {
|
public ReflectMethod<T> method(String name, Class<?>... paramTypes) throws NoSuchMethodException {
|
||||||
return constructorCache.computeIfAbsent(key, k -> new ReflectConstructor<>(this, k));
|
return method(new MethodIdentifier(name, paramTypes), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReflectConstructor<T> constructor(Class<?>... paramTypes) {
|
public ReflectMethod<T> filteredMethod(String name, Class<?>... paramTypes) throws NoSuchMethodException {
|
||||||
return constructor(new ConstructorIdentifier(paramTypes));
|
return method(new MethodIdentifier(name, paramTypes), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReflectField<T> field(String name) {
|
private ReflectConstructor<T> constructor(ConstructorIdentifier key, boolean bypassFilter) throws NoSuchMethodException {
|
||||||
return fieldCache.computeIfAbsent(name, n -> new ReflectField<>(this, n));
|
ReflectConstructor<T> constructor = constructorCache.get(key);
|
||||||
|
if (constructor == null) {
|
||||||
|
constructor = new ReflectConstructor<>(this, key, bypassFilter);
|
||||||
|
constructorCache.put(key, constructor);
|
||||||
|
}
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReflectConstructor<T> constructor(Class<?>... paramTypes) throws NoSuchMethodException {
|
||||||
|
return constructor(new ConstructorIdentifier(paramTypes), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReflectConstructor<T> filteredConstructor(Class<?>... paramTypes) throws NoSuchMethodException {
|
||||||
|
return constructor(new ConstructorIdentifier(paramTypes), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ReflectField<T> field0(String name, boolean bypassFilter) throws NoSuchFieldException {
|
||||||
|
ReflectField<T> constructor = fieldCache.get(name);
|
||||||
|
if (constructor == null) {
|
||||||
|
constructor = new ReflectField<>(this, name, bypassFilter);
|
||||||
|
fieldCache.put(name, constructor);
|
||||||
|
}
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReflectField<T> field(String name) throws NoSuchFieldException {
|
||||||
|
return field0(name, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReflectField<T> filteredField(String name) throws NoSuchFieldException {
|
||||||
|
return field0(name, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,45 +195,127 @@ public class Reflect {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static abstract class ReflectClassEl<T> {
|
public static abstract class ReflectMember<T, EL, EX extends ReflectiveOperationException> {
|
||||||
ReflectClass<T> reflectClass;
|
ReflectClass<T> reflectClass;
|
||||||
|
protected EL cached;
|
||||||
|
|
||||||
protected ReflectClassEl(ReflectClass<T> c) {
|
protected ReflectMember(ReflectClass<T> c, boolean bypassFilter) throws EX {
|
||||||
reflectClass = c;
|
reflectClass = c;
|
||||||
|
cached = (bypassFilter) ? fetchFiltered() : get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected EL fetch() throws EX {
|
||||||
|
EX ex = null;
|
||||||
|
|
||||||
|
// get element in current class
|
||||||
|
try {
|
||||||
|
EL el = fetchFromClass(reflectClass.clazz);
|
||||||
|
setAccessible(el);
|
||||||
|
return el;
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
EX ee = (EX) e;
|
||||||
|
ex = ee;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get parent class
|
||||||
|
Class<? super T> superClass = reflectClass.clazz.getSuperclass();
|
||||||
|
if (superClass == null)
|
||||||
|
throw ex;
|
||||||
|
|
||||||
|
// get element in parent class (will do recursion)
|
||||||
|
try {
|
||||||
|
EL el = fetchFromReflectClass(ofClass(superClass));
|
||||||
|
setAccessible(el);
|
||||||
|
return el;
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
ex.addSuppressed(e);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EL fetchFiltered() throws EX {
|
||||||
|
EX ex = null;
|
||||||
|
|
||||||
|
// get element in current class
|
||||||
|
try {
|
||||||
|
EL el = fetchFromClass(reflectClass.clazz);
|
||||||
|
setAccessible(el);
|
||||||
|
return el;
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
EX ee = (EX) e;
|
||||||
|
ex = ee;
|
||||||
|
}
|
||||||
|
|
||||||
|
// trying to bypass filtered member
|
||||||
|
try {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
EL[] elements = (EL[]) Reflect.ofClassOfInstance(reflectClass.clazz)
|
||||||
|
.method(internalMethodNameElementArray(), boolean.class)
|
||||||
|
.invoke(reflectClass.clazz, false);
|
||||||
|
for (EL element : elements) {
|
||||||
|
if (isEqualOurElement(element)) {
|
||||||
|
// the values in the elements array have to be copied
|
||||||
|
// (using special private methods in reflection api) before using it
|
||||||
|
Object reflectionFactoryOfClazz = Reflect.ofClassOfInstance(reflectClass.clazz)
|
||||||
|
.method("getReflectionFactory")
|
||||||
|
.invoke(reflectClass.clazz);
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
EL copiedElement = (EL) Reflect.ofClassOfInstance(reflectionFactoryOfClazz)
|
||||||
|
.method(internalMethodNameCopyElement(), element.getClass())
|
||||||
|
.invoke(reflectionFactoryOfClazz, element);
|
||||||
|
EL el = copiedElement;
|
||||||
|
setAccessible(el);
|
||||||
|
return el;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ReflectiveOperationException e) {
|
||||||
|
ex.addSuppressed(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw ex;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract EL fetchFromClass(Class<T> clazz) throws EX;
|
||||||
|
protected abstract EL fetchFromReflectClass(ReflectClass<?> rc) throws EX;
|
||||||
|
protected abstract boolean isEqualOurElement(EL el);
|
||||||
|
protected abstract String internalMethodNameElementArray();
|
||||||
|
protected abstract String internalMethodNameCopyElement();
|
||||||
|
protected abstract void setAccessible(EL el);
|
||||||
|
|
||||||
|
public EL get() {
|
||||||
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ReflectField<T> extends ReflectClassEl<T> {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static class ReflectField<T> extends ReflectMember<T, Field, NoSuchFieldException> {
|
||||||
String elementName;
|
String elementName;
|
||||||
|
|
||||||
private Field cached, cachedFiltered;
|
/* package */ ReflectField(ReflectClass<T> c, String name, boolean bypassFilter) throws NoSuchFieldException {
|
||||||
|
super(c, bypassFilter);
|
||||||
/* package */ ReflectField(ReflectClass<T> c, String name) {
|
|
||||||
super(c);
|
|
||||||
elementName = name;
|
elementName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Field get() throws NoSuchFieldException {
|
@Override protected Field fetchFromClass(Class<T> clazz) throws NoSuchFieldException { return clazz.getDeclaredField(elementName); };
|
||||||
if (cached == null) {
|
@Override protected Field fetchFromReflectClass(ReflectClass<?> rc) throws NoSuchFieldException { return rc.field(elementName).get(); };
|
||||||
cached = getDeclaredRecursively(reflectClass.clazz,
|
@Override protected boolean isEqualOurElement(Field el) { return elementName.equals(el.getName()); };
|
||||||
c -> c.getDeclaredField(elementName),
|
@Override protected String internalMethodNameElementArray() { return "getDeclaredFields0"; };
|
||||||
c -> ofClass(c).field(elementName).get(),
|
@Override protected String internalMethodNameCopyElement() { return "copyField"; };
|
||||||
f -> f.setAccessible(true));
|
@Override protected void setAccessible(Field el) { el.setAccessible(true); }
|
||||||
}
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ synchronized Field getFiltered() throws NoSuchFieldException {
|
|
||||||
if (cachedFiltered == null) {
|
|
||||||
cachedFiltered = Reflect.getFiltered(reflectClass.clazz,
|
|
||||||
c -> c.getDeclaredField(elementName),
|
|
||||||
f -> f.setAccessible(true),
|
|
||||||
f -> elementName.equals(f.getName()),
|
|
||||||
"getDeclaredFields0", "copyField");
|
|
||||||
}
|
|
||||||
return cachedFiltered;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getValue(Object instance) throws ReflectiveOperationException {
|
public Object getValue(Object instance) throws ReflectiveOperationException {
|
||||||
return get().get(instance);
|
return get().get(instance);
|
||||||
@ -225,7 +343,7 @@ public class Reflect {
|
|||||||
// change the modifier in the Field instance so the method #set(instance, value) doesn’t throw an exception
|
// change the modifier in the Field instance so the method #set(instance, value) doesn’t throw an exception
|
||||||
int modifiers = f.getModifiers();
|
int modifiers = f.getModifiers();
|
||||||
if (Modifier.isFinal(modifiers)) {
|
if (Modifier.isFinal(modifiers)) {
|
||||||
ofClass(Field.class).field("modifiers").getFiltered().set(f, modifiers & ~Modifier.FINAL);
|
ofClass(Field.class).field("modifiers").fetchFiltered().set(f, modifiers & ~Modifier.FINAL);
|
||||||
}
|
}
|
||||||
f.set(instance, value);
|
f.set(instance, value);
|
||||||
}
|
}
|
||||||
@ -243,42 +361,31 @@ public class Reflect {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ReflectMethod<T> extends ReflectClassEl<T> {
|
|
||||||
String elementName;
|
|
||||||
|
|
||||||
private Method cached, cachedFiltered;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static class ReflectMethod<T> extends ReflectMember<T, Method, NoSuchMethodException> {
|
||||||
|
String elementName;
|
||||||
|
|
||||||
MethodIdentifier methodId;
|
MethodIdentifier methodId;
|
||||||
Class<?>[] parameterTypes;
|
Class<?>[] parameterTypes;
|
||||||
|
|
||||||
/* package */ ReflectMethod(ReflectClass<T> c, MethodIdentifier methodId) {
|
/* package */ ReflectMethod(ReflectClass<T> c, MethodIdentifier methodId, boolean bypassFilter) throws NoSuchMethodException {
|
||||||
super(c);
|
super(c, bypassFilter);
|
||||||
this.elementName = methodId.methodName;
|
this.elementName = methodId.methodName;
|
||||||
this.methodId = methodId;
|
this.methodId = methodId;
|
||||||
parameterTypes = methodId.parameters;
|
parameterTypes = methodId.parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override protected Method fetchFromClass(Class<T> clazz) throws NoSuchMethodException { return clazz.getDeclaredMethod(elementName, parameterTypes); };
|
||||||
public Method get() throws NoSuchMethodException {
|
@Override protected Method fetchFromReflectClass(ReflectClass<?> rc) throws NoSuchMethodException { return rc.method(methodId, false).get(); };
|
||||||
if (cached == null) {
|
@Override protected boolean isEqualOurElement(Method el) { return elementName.equals(el.getName()) && Arrays.equals(parameterTypes, el.getParameterTypes()); };
|
||||||
cached = getDeclaredRecursively(reflectClass.clazz,
|
@Override protected String internalMethodNameElementArray() { return "getDeclaredMethods0"; };
|
||||||
c -> c.getDeclaredMethod(elementName, parameterTypes),
|
@Override protected String internalMethodNameCopyElement() { return "copyMethod"; };
|
||||||
c -> ofClass(c).method(methodId).get(),
|
@Override protected void setAccessible(Method el) { el.setAccessible(true); }
|
||||||
m -> m.setAccessible(true));
|
|
||||||
}
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* package */ Method getFiltered() throws NoSuchMethodException {
|
|
||||||
if (cachedFiltered == null) {
|
|
||||||
cachedFiltered = Reflect.getFiltered(reflectClass.clazz,
|
|
||||||
c -> c.getDeclaredMethod(elementName, parameterTypes),
|
|
||||||
m -> m.setAccessible(true),
|
|
||||||
m -> elementName.equals(m.getName()) && Arrays.equals(parameterTypes, m.getParameterTypes()),
|
|
||||||
"getDeclaredMethods0", "copyMethod");
|
|
||||||
}
|
|
||||||
return cachedFiltered;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object invoke(Object instance, Object... values) throws ReflectiveOperationException {
|
public Object invoke(Object instance, Object... values) throws ReflectiveOperationException {
|
||||||
return get().invoke(instance, values);
|
return get().invoke(instance, values);
|
||||||
@ -289,40 +396,37 @@ public class Reflect {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ReflectConstructor<T> extends ReflectClassEl<T> {
|
|
||||||
|
|
||||||
private Constructor<T> cached, cachedFiltered;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static class ReflectConstructor<T> extends ReflectMember<T, Constructor<T>, NoSuchMethodException> {
|
||||||
|
|
||||||
ConstructorIdentifier constructorId;
|
ConstructorIdentifier constructorId;
|
||||||
Class<?>[] parameterTypes;
|
Class<?>[] parameterTypes;
|
||||||
|
|
||||||
/* package */ ReflectConstructor(ReflectClass<T> c, ConstructorIdentifier constructorId) {
|
/* package */ ReflectConstructor(ReflectClass<T> c, ConstructorIdentifier constructorId, boolean bypassFilter) throws NoSuchMethodException {
|
||||||
super(c);
|
super(c, bypassFilter);
|
||||||
this.constructorId = constructorId;
|
this.constructorId = constructorId;
|
||||||
parameterTypes = constructorId.parameters;
|
parameterTypes = constructorId.parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Override since we don't want to recursively search for a constructor
|
||||||
public Constructor<T> get() throws NoSuchMethodException {
|
@Override
|
||||||
if (cached == null) {
|
protected Constructor<T> fetch() throws NoSuchMethodException {
|
||||||
Constructor<T> el = null;
|
Constructor<T> el = null;
|
||||||
el = reflectClass.clazz.getDeclaredConstructor(parameterTypes);
|
el = fetchFromClass(reflectClass.clazz);
|
||||||
el.setAccessible(true);
|
setAccessible(el);
|
||||||
cached = el;
|
return el;
|
||||||
}
|
|
||||||
return cached;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ Constructor<T> getFiltered() throws NoSuchMethodException {
|
@Override protected Constructor<T> fetchFromClass(Class<T> clazz) throws NoSuchMethodException { return clazz.getDeclaredConstructor(parameterTypes); };
|
||||||
if (cachedFiltered == null) {
|
@Override protected Constructor<T> fetchFromReflectClass(ReflectClass<?> rc) throws NoSuchMethodException { throw new UnsupportedOperationException(); };
|
||||||
cachedFiltered = Reflect.getFiltered(reflectClass.clazz,
|
@Override protected boolean isEqualOurElement(Constructor<T> el) { return Arrays.equals(parameterTypes, el.getParameterTypes()); };
|
||||||
c -> c.getDeclaredConstructor(parameterTypes),
|
@Override protected String internalMethodNameElementArray() { return "getDeclaredConstructors0"; };
|
||||||
m -> m.setAccessible(true),
|
@Override protected String internalMethodNameCopyElement() { return "copyConstructor"; };
|
||||||
m -> Arrays.equals(parameterTypes, m.getParameterTypes()),
|
@Override protected void setAccessible(Constructor<T> el) { el.setAccessible(true); }
|
||||||
"getDeclaredConstructors0", "copyConstructor");
|
|
||||||
}
|
|
||||||
return cachedFiltered;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T instanciate(Object... values) throws ReflectiveOperationException {
|
public T instanciate(Object... values) throws ReflectiveOperationException {
|
||||||
return get().newInstance(values);
|
return get().newInstance(values);
|
||||||
@ -340,124 +444,10 @@ public class Reflect {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private interface GetUncheckedClassReflectiveElement<T, E extends ReflectiveOperationException> {
|
|
||||||
public T get(Class<?> clazz) throws E;
|
|
||||||
}
|
|
||||||
|
|
||||||
private interface GetReflectiveElement<C, T, E extends ReflectiveOperationException> {
|
|
||||||
public T get(Class<C> clazz) 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");
|
|
||||||
|
|
||||||
E ex = null;
|
|
||||||
T el = null;
|
|
||||||
|
|
||||||
// get element in provided class
|
|
||||||
try {
|
|
||||||
el = jlrGetter.get(clazz);
|
|
||||||
setAccessible.accept(el);
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
E ee = (E) e;
|
|
||||||
ex = ee;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get element in parent class (will do recursion)
|
|
||||||
if (el == null) {
|
|
||||||
try {
|
|
||||||
el = parentGetter.get(clazz.getSuperclass());
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
if (ex == null) {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
E ee = (E) e;
|
|
||||||
ex = ee;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ex.addSuppressed(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (el == null)
|
|
||||||
throw ex;
|
|
||||||
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
private static Cache<Class<?>, List<Class<?>>> subClassesLists = CacheBuilder.newBuilder()
|
||||||
* 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}
|
|
||||||
* block its direct access.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
private static <C, T, E extends ReflectiveOperationException> T getFiltered(
|
|
||||||
Class<C> clazz, GetReflectiveElement<C, T, E> jlrGetter,
|
|
||||||
Consumer<T> setAccessible, Predicate<T> elementChecker,
|
|
||||||
String privateMethodName, String copyMethodName) throws E {
|
|
||||||
Objects.requireNonNull(clazz, "Class instance not provided");
|
|
||||||
|
|
||||||
T el = null;
|
|
||||||
|
|
||||||
E ex = null;
|
|
||||||
try {
|
|
||||||
el = jlrGetter.get(clazz);
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
E ee = (E) e;
|
|
||||||
ex = ee;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
T[] elements = (T[]) ofClassOfInstance(clazz).method(privateMethodName, boolean.class).invoke(clazz, false);
|
|
||||||
for (T element : elements) {
|
|
||||||
if (elementChecker.test(element)) {
|
|
||||||
// the values in the elements array have to be copied
|
|
||||||
// (using special private methods in reflection api) before using it
|
|
||||||
Object reflectionFactoryOfClazz = ofClassOfInstance(clazz).method("getReflectionFactory").invoke(clazz);
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
T copiedElement = (T) ofClassOfInstance(reflectionFactoryOfClazz)
|
|
||||||
.method(copyMethodName, element.getClass())
|
|
||||||
.invoke(reflectionFactoryOfClazz, element);
|
|
||||||
el = copiedElement;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ReflectiveOperationException e) {
|
|
||||||
if (ex != null)
|
|
||||||
ex.addSuppressed(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (el == null)
|
|
||||||
throw ex;
|
|
||||||
|
|
||||||
setAccessible.accept(el);
|
|
||||||
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static Cache<Class<?>, List<Class<?>>> subClassesLists = CacheBuilder.newBuilder()
|
|
||||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user