Skip to content

Instantly share code, notes, and snippets.

@TheMasteredPanda
Created July 18, 2017 16:47
Show Gist options
  • Save TheMasteredPanda/ce5d5c55b3548085c8ab03eb50cf4b6b to your computer and use it in GitHub Desktop.
Save TheMasteredPanda/ce5d5c55b3548085c8ab03eb50cf4b6b to your computer and use it in GitHub Desktop.
First rev of my ReflectUtil class
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