230 lines
6.9 KiB
Java
230 lines
6.9 KiB
Java
package eu.mikroskeem.utils.reflect;
|
|
|
|
import lombok.Getter;
|
|
import lombok.RequiredArgsConstructor;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.lang.reflect.Constructor;
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Stream;
|
|
|
|
/**
|
|
* Reflection utils
|
|
*
|
|
* @author Mark
|
|
*/
|
|
@Deprecated
|
|
public class Reflect {
|
|
|
|
/**
|
|
* Find class by name
|
|
*
|
|
* @param clazz Class to search
|
|
* @return Class or null
|
|
*/
|
|
@Nullable
|
|
public static Class<?> getClass(@NotNull String clazz){
|
|
try {
|
|
return Class.forName(clazz);
|
|
} catch (ClassNotFoundException e){
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return whether class exists or not
|
|
*
|
|
* @param clazz Class to search
|
|
* @return Whether class existed or not
|
|
*/
|
|
public static boolean classExists(@NotNull String clazz){
|
|
return getClass(clazz) != null;
|
|
}
|
|
|
|
/**
|
|
* Construct class with arguments. Note: primitive types aren't supported
|
|
*
|
|
*
|
|
* @param clazz Class to construct
|
|
* @param arguments Class constructor arguments
|
|
* @return Class instance or null
|
|
*/
|
|
public static Object fastConstruct(@NotNull Class<?> clazz, TypeWrapper... arguments){
|
|
try {
|
|
Class<?>[] tArgs = Stream.of(arguments).map(TypeWrapper::getType).collect(Collectors.toList()).toArray(new Class[0]);
|
|
Object[] args = Stream.of(arguments).map(TypeWrapper::getValue).collect(Collectors.toList()).toArray();
|
|
Constructor constructor = clazz.getDeclaredConstructor(tArgs);
|
|
constructor.setAccessible(true);
|
|
return constructor.newInstance(args);
|
|
} catch (NoSuchMethodException|InstantiationException|IllegalAccessException|InvocationTargetException e){
|
|
e.printStackTrace();
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get declared class method (public,protected,private)
|
|
*
|
|
* @param clazz Class to reflect
|
|
* @param method Method to search
|
|
* @param arguments Method arguments
|
|
* @return Method or null
|
|
*/
|
|
@Nullable
|
|
public static Method getMethod(@NotNull Class<?> clazz, @NotNull String method, Class<?>... arguments){
|
|
try {
|
|
Method m = clazz.getDeclaredMethod(method, arguments);
|
|
m.setAccessible(true);
|
|
return m;
|
|
} catch (NoSuchMethodException e){
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Invoke method and get result
|
|
*
|
|
* @param method Method to invoke
|
|
* @param instance Instance where given method resides (null if static)
|
|
* @param args Method arguments
|
|
* @return Method result or null
|
|
*/
|
|
@Nullable
|
|
public static Object invokeMethod(@NotNull Method method, @Nullable Object instance, @Nullable Object... args){
|
|
try {
|
|
return method.invoke(instance, args);
|
|
} catch (IllegalAccessException|InvocationTargetException e){
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get declared class field (public,protected,private)
|
|
*
|
|
* @param clazz Class to reflect
|
|
* @param field Field to search
|
|
* @return Field or null
|
|
*/
|
|
@Nullable
|
|
public static Field getField(@NotNull Class<?> clazz, @NotNull String field){
|
|
try {
|
|
Field f = clazz.getDeclaredField(field);
|
|
f.setAccessible(true);
|
|
return f;
|
|
} catch (NoSuchFieldException e){
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Read field
|
|
*
|
|
* @param field Field to read
|
|
* @param instance Instance where to read (null if static)
|
|
* @return Field contents or null;
|
|
*/
|
|
@Nullable
|
|
public static Object readField(@NotNull Field field, @Nullable Object instance){
|
|
try {
|
|
return field.get(instance);
|
|
} catch (IllegalAccessException e){
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write field
|
|
*
|
|
* @param field Field to write
|
|
* @param instance Instance where field resides (null if static)
|
|
* @param value Field new contents
|
|
*/
|
|
public static void writeField(@NotNull Field field, @Nullable Object instance, @Nullable Object value){
|
|
try {
|
|
field.set(instance, value);
|
|
} catch (IllegalAccessException e){}
|
|
}
|
|
|
|
/* Simpler reflection methods */
|
|
|
|
/**
|
|
* Read field
|
|
*
|
|
* @param instance Object where to read given field
|
|
* @param fieldName Field name
|
|
* @return Field contents or null
|
|
*/
|
|
@Nullable public static Object simpleReadField(@NotNull Object instance, @NotNull String fieldName){
|
|
try {
|
|
Field f = instance.getClass().getDeclaredField(fieldName);
|
|
if (!f.isAccessible()) {
|
|
f.setAccessible(true);
|
|
}
|
|
return f.get(instance);
|
|
} catch (NoSuchFieldException|IllegalAccessException e){
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write field
|
|
*
|
|
* @param instance Object where given field resides
|
|
* @param fieldName Field name
|
|
* @param value Field content
|
|
*/
|
|
public static void simpleWriteField(@NotNull Object instance, @NotNull String fieldName,
|
|
@Nullable Object value){
|
|
try {
|
|
Field f = instance.getClass().getDeclaredField(fieldName);
|
|
if (!f.isAccessible()) {
|
|
f.setAccessible(true);
|
|
}
|
|
f.set(instance, value);
|
|
} catch (NoSuchFieldException|IllegalAccessException ignored){}
|
|
}
|
|
|
|
/**
|
|
* Load class from bytearray to existing class loader. Useful when you need to
|
|
* add generated class to classpath
|
|
*
|
|
* @param classLoader Class loader which defines given class
|
|
* @param name Class name
|
|
* @param data Class in bytearray
|
|
* @return Defined class
|
|
* @throws ClassFormatError thrown by ClassLoader
|
|
*/
|
|
@Nullable
|
|
public static Class<?> defineClass(@NotNull ClassLoader classLoader, @NotNull String name, @NotNull byte[] data)
|
|
throws ClassFormatError {
|
|
Method defineClassMethod = Reflect.getMethod(ClassLoader.class, "defineClass",
|
|
String.class, byte[].class, int.class, int.class);
|
|
if(defineClassMethod != null){
|
|
try {
|
|
return (Class<?>) defineClassMethod.invoke(classLoader, name, data, 0, data.length);
|
|
} catch (InvocationTargetException e) {
|
|
if(e.getTargetException() instanceof ClassFormatError){
|
|
throw (ClassFormatError)e.getTargetException();
|
|
}
|
|
}
|
|
catch (IllegalAccessException ignored){}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
/**
|
|
* Type/value wrapper for reflective constructing
|
|
*/
|
|
@RequiredArgsConstructor
|
|
@Getter
|
|
public static class TypeWrapper {
|
|
private final Object value;
|
|
private final Class<?> type;
|
|
}
|
|
}
|