Created
July 18, 2017 16:47
-
-
Save TheMasteredPanda/ce5d5c55b3548085c8ab03eb50cf4b6b to your computer and use it in GitHub Desktop.
First rev of my ReflectUtil class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.themasteredpanda.library.utils.reflect; | |
import com.google.common.cache.CacheBuilder; | |
import com.google.common.cache.CacheLoader; | |
import com.google.common.cache.LoadingCache; | |
import com.google.common.collect.Lists; | |
import com.themasteredpanda.library.utils.UtilException; | |
import com.themasteredpanda.library.utils.reflect.accessors.ConstructorAccessor; | |
import com.themasteredpanda.library.utils.reflect.accessors.FieldAccessor; | |
import com.themasteredpanda.library.utils.reflect.accessors.MethodAccessor; | |
import lombok.SneakyThrows; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Parameter; | |
import java.util.List; | |
import java.util.concurrent.TimeUnit; | |
/** | |
* Reflection Utility class. | |
* | |
* TODO | |
* - getMethodsWithAnnotations(Annotation... annotations) - gets a list of methods with the annotations specified. | |
* - containsAnnotations(Annotation... annotations) - Gets methods that have the specified annotations. | |
* - containsAnnotation(Annotation annotation) - Gets methods that have the specified annotation. | |
* | |
* Remember to: | |
* - Cache the lists | |
*/ | |
public final class ReflectUtils<T> | |
{ | |
private static LoadingCache<String, Object> reflectionCache = CacheBuilder.newBuilder().expireAfterAccess(15, TimeUnit.MINUTES).weakKeys().build(new Loader()); | |
private ReflectUtils() | |
{ | |
throw new UtilException(); | |
} | |
public static class Loader extends CacheLoader<String, Object> | |
{ | |
@Override | |
public Object load(String s) throws Exception | |
{ | |
String[] args = s.split(";"); | |
Class<?> clazz = ReflectUtils.getClass(args[0]); | |
//Example: com.themasteredpanda.test.reflect.TestReflect;MethodAccessor;PUBLIC;getTestMethod;java.lang.Integer/java.lang.String/java.lang.Long | |
if (args[1].equalsIgnoreCase("MethodAccessor")) { | |
Type methodType = Type.valueOf(args[2]); | |
String method = args[3]; | |
List<Class<?>> parameters = Lists.newLinkedList(); | |
for (String param : args[4].split("/")) { | |
parameters.add(ReflectUtils.getClass(param)); | |
} | |
Method m = methodType == Type.DECLARED ? clazz.getDeclaredMethod(method, parameters.toArray(new Class[parameters.size()])) : clazz.getMethod(method, parameters.toArray(new Class[parameters.size()])); | |
m.setAccessible(true); | |
return new MethodAccessor() | |
{ | |
@Override | |
@SneakyThrows | |
public Object call(Object instance, Object... parameters) | |
{ | |
return m.invoke(instance, parameters); | |
} | |
@Override | |
public Annotation[] getPublicAnnotations() | |
{ | |
return m.getAnnotations(); | |
} | |
@Override | |
public Annotation[] getPrivateAnnotations() | |
{ | |
return m.getDeclaredAnnotations(); | |
} | |
@Override | |
public boolean hasAnnotation(Class annotation) | |
{ | |
return m.isAnnotationPresent(annotation); | |
} | |
@Override | |
public Object getAnnotation(Class annotation) | |
{ | |
return m.getAnnotation(annotation); | |
} | |
@Override | |
public Parameter[] getParameters() | |
{ | |
return m.getParameters(); | |
} | |
@Override | |
public String getName() | |
{ | |
return m.getName(); | |
} | |
@Override | |
public Method getMethod() | |
{ | |
return m; | |
} | |
@Override | |
public Annotation[][] getAnnotatedParameters() | |
{ | |
return m.getParameterAnnotations(); | |
} | |
}; | |
} | |
//Example: com.themasteredpands.test.reflect.TestReflect;FieldAccessor;DECLARED;testField | |
if (args[1].equalsIgnoreCase("FieldAccessor")) { | |
Type type = Type.valueOf(args[2]); | |
String field = args[3]; | |
Field f = type == Type.DECLARED ? clazz.getDeclaredField(field) : clazz.getField(field); | |
f.setAccessible(true); | |
return new FieldAccessor() | |
{ | |
@Override @SneakyThrows | |
public Object get(Object instance) | |
{ | |
return f.get(instance); | |
} | |
@Override @SneakyThrows | |
public void set(Object instance, Object value) | |
{ | |
f.set(instance, value); | |
} | |
@Override | |
public Annotation[] getPublicAnnotations() | |
{ | |
return f.getAnnotations(); | |
} | |
@Override | |
public Annotation[] getPrivateAnnotations() | |
{ | |
return f.getDeclaredAnnotations(); | |
} | |
@Override | |
public boolean hasAnnotation(Class annotation) | |
{ | |
return f.isAnnotationPresent(annotation); | |
} | |
@Override | |
public Annotation getAnnotation(Class annotation) | |
{ | |
return f.getAnnotation(annotation); | |
} | |
@Override | |
public Class<?> getType() | |
{ | |
return f.getType(); | |
} | |
@Override | |
public Field getField() | |
{ | |
return f; | |
} | |
}; | |
} | |
//Example: com.themasteredpanda.test.reflect.TestReflect;ConstructorAccessor;PUBLIC;java.lang.Integer/java.lang.String/com.themasteredpanda.library.utils.Pair | |
if (args[1].equalsIgnoreCase("ConstructorAccessor")) { | |
Type type = Type.valueOf(args[2]); | |
List<Class<?>> parameters = Lists.newLinkedList(); | |
for (String param : args[3].split("/")) { | |
parameters.add(ReflectUtils.getClass(param)); | |
} | |
Constructor c = clazz.getConstructor(parameters.toArray(new Class[parameters.size()])); | |
c.setAccessible(true); | |
return new ConstructorAccessor() | |
{ | |
@Override | |
@SneakyThrows | |
public Object call(Object... parameters) | |
{ | |
return c.newInstance(parameters); | |
} | |
@Override | |
public Annotation[] getPublicAnnotations() | |
{ | |
return c.getAnnotations(); | |
} | |
@Override | |
public Annotation[] getPrivateAnnotations() | |
{ | |
return c.getDeclaredAnnotations(); | |
} | |
@Override | |
public Annotation[][] getParameterAnnotations() | |
{ | |
return c.getParameterAnnotations(); | |
} | |
@Override | |
public Parameter[] getParameters() | |
{ | |
return c.getParameters(); | |
} | |
@Override | |
public boolean hasAnnotation(Class annotation) | |
{ | |
return c.isAnnotationPresent(annotation); | |
} | |
@Override | |
public Annotation getAnnotation(Class annotation) | |
{ | |
return c.getAnnotation(annotation); | |
} | |
@Override | |
public Constructor getConstructor() | |
{ | |
return null; | |
} | |
}; | |
} | |
return null; | |
} | |
} | |
@SneakyThrows | |
public static Class<?> getClass(String location) | |
{ | |
return Class.forName(location); | |
} | |
@SneakyThrows | |
public static MethodAccessor getMethod(Class<?> clazz, String method, Type methodType, Class... parameters) | |
{ | |
StringBuilder sb = new StringBuilder(clazz.getCanonicalName()).append(";").append("MethodAccessor").append(";").append(methodType.toString()).append(";"); | |
for (Class param : parameters) { | |
sb.append(param.getCanonicalName()); | |
if (param != parameters[parameters.length - 1]) { | |
sb.append("/"); | |
} | |
} | |
return (MethodAccessor) reflectionCache.get(sb.toString()); | |
} | |
@SneakyThrows | |
public static FieldAccessor getField(Class<?> clazz, String field, Type fieldType) | |
{ | |
return (FieldAccessor) reflectionCache.get(clazz.getCanonicalName() + ";" + "FieldAccessor" + ";" + fieldType.toString() + ";" + field); | |
} | |
@SneakyThrows | |
public static ConstructorAccessor getConstructor(Class clazz, Class... parameters) | |
{ | |
StringBuilder sb = new StringBuilder(clazz.getCanonicalName()).append(";"); | |
for (Class param : parameters) { | |
sb.append(param.getCanonicalName()); | |
if (param != parameters[parameters.length - 1]) { | |
sb.append("/"); | |
} | |
} | |
return (ConstructorAccessor) reflectionCache.get(sb.toString()); | |
} | |
public enum Type | |
{ | |
PUBLIC, DECLARED | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment