-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
698 additions
and
4 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
distributionBase=GRADLE_USER_HOME | ||
distributionPath=wrapper/dists | ||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip | ||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip | ||
zipStoreBase=GRADLE_USER_HOME | ||
zipStorePath=wrapper/dists |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package reflection; | ||
|
||
import java.lang.reflect.*; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import static reflection.ReflectionUtils.*; | ||
|
||
public class ConstructorReflection { | ||
|
||
private static final Method copyConstructor; | ||
private static final Method getDeclaredConstructors0; | ||
|
||
|
||
static { | ||
try { | ||
copyConstructor = forceAccessible(Constructor.class.getDeclaredMethod("copy"), true); | ||
getDeclaredConstructors0 = forceAccessible(Class.class.getDeclaredMethod("getDeclaredConstructors0", boolean.class), true); | ||
} catch (NoSuchMethodException e) { | ||
throw new RuntimeException("Initialization of ConstructorReflection failed", e); | ||
} | ||
} | ||
|
||
/** | ||
* creates an instance of a class using the default constructor (even when the default constructor does not exist) | ||
* @param clazz the class to make an instance of | ||
* @return an instance of the class | ||
*/ | ||
public static <T> T createInstanceWithoutConstructor(Class<T> clazz) { | ||
try { | ||
return (T) unsafe.allocateInstance(clazz); | ||
} catch (InstantiationException e) { | ||
e.printStackTrace(); | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* makes a new instance of the constructor passed in | ||
* @param c constructor to create new instance of | ||
* @param args the arguments to make a new instance with | ||
* @return new instance of constructor | ||
*/ | ||
public static <T> T useConstructor(Constructor<T> c, Object ... args) { | ||
try { | ||
if(args.length == c.getParameterCount()) { | ||
boolean isOverride = isAccessible(c); | ||
|
||
forceAccessible(c, true); | ||
|
||
T instance = c.newInstance(args); | ||
|
||
forceAccessible(c, isOverride); | ||
|
||
return instance; | ||
} | ||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { | ||
e.printStackTrace(); | ||
} | ||
return null; | ||
} | ||
|
||
/** | ||
* gets constructor | ||
* @param clazz class to get constructor of | ||
* @param classes the argument types of the constructor | ||
* @return the constructor | ||
*/ | ||
public static <T> Constructor<T> getConstructor(Class<T> clazz, Class<?> ... classes) throws NoSuchMethodException { | ||
for(Constructor<T> constructor : getConstructors(clazz)) { | ||
if (Arrays.equals(constructor.getParameterTypes(), classes)) { | ||
return constructor; | ||
} | ||
} | ||
throw new NoSuchMethodException(methodToString(clazz, "<init>", classes)); | ||
} | ||
|
||
/** | ||
* gets all fields from class and all superclasses if specified | ||
* @param clazz the class the field is in | ||
* @return the fields specified | ||
*/ | ||
@SuppressWarnings("unchecked") | ||
public static <T> Constructor<T>[] getConstructors(Class<T> clazz) { | ||
try { | ||
List<Constructor<T>> constructors = new ArrayList<>(); | ||
|
||
for (Constructor<T> constructor : (Constructor<T>[]) getDeclaredConstructors0.invoke(clazz, false)) { | ||
constructors.add((Constructor<T>) copyConstructor.invoke(constructor)); | ||
} | ||
|
||
return constructors.toArray(new Constructor[0]); | ||
} catch (InvocationTargetException | IllegalAccessException e) { | ||
e.printStackTrace(); | ||
} | ||
return new Constructor[0]; | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
package reflection; | ||
|
||
import java.lang.reflect.*; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import static reflection.ReflectionUtils.*; | ||
|
||
public class FieldReflection { | ||
|
||
private static final Method getDeclaredFields0; | ||
private static final Method copyField; | ||
|
||
static { | ||
try { | ||
getDeclaredFields0 = forceAccessible(Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class), true); | ||
copyField = forceAccessible(Field.class.getDeclaredMethod("copy"), true); | ||
} catch (NoSuchMethodException e) { | ||
throw new RuntimeException("Initialization of FieldReflection failed", e); | ||
} | ||
} | ||
|
||
public static void setStaticFieldValue(Field f, Object value) { | ||
setFieldValue(f, null, value); | ||
} | ||
|
||
/** | ||
* sets field's value (doesn't work with trusted final fields) | ||
* @param f field to change | ||
* @param instance instance to change the field in (null if field is static) | ||
* @param value the value to change the field to | ||
*/ | ||
public static void setFieldValue(Field f, Object instance, Object value) { | ||
long offset; | ||
Object obj; | ||
|
||
if(instance == null) { | ||
offset = getStaticFieldOffset(f); | ||
obj = f.getDeclaringClass(); | ||
} else { | ||
offset = getObjectFieldOffset(f); | ||
obj = instance; | ||
} | ||
|
||
switch (f.getType().getName()) { | ||
case "int" -> unsafe.putInt(obj, offset, (Integer) value); | ||
case "boolean" -> unsafe.putBoolean(obj, offset, (Boolean) value); | ||
case "byte" -> unsafe.putByte(obj, offset, (Byte) value); | ||
case "long" -> unsafe.putLong(obj, offset, (Long) value); | ||
case "short" -> unsafe.putShort(obj, offset, (Short) value); | ||
case "float" -> unsafe.putFloat(obj, offset, (Float) value); | ||
case "char" -> unsafe.putChar(obj, offset, (Character) value); | ||
case "double" -> unsafe.putDouble(obj, offset, (Double) value); | ||
default -> unsafe.putObject(obj, offset, value); | ||
} | ||
} | ||
|
||
public static Object getStaticFieldValue(Field f) { | ||
return getFieldValue(f, null); | ||
} | ||
|
||
/** | ||
* gets field's value | ||
* @param f field to get value of | ||
* @param instance instance to get field value of (null if field is static) | ||
* @return value of the field in the instance | ||
*/ | ||
public static Object getFieldValue(Field f, Object instance) { | ||
long offset; | ||
Object obj; | ||
|
||
if(instance == null) { | ||
offset = getStaticFieldOffset(f); | ||
obj = f.getDeclaringClass(); | ||
} else { | ||
offset = getObjectFieldOffset(f); | ||
obj = instance; | ||
} | ||
|
||
return switch (f.getType().getName()) { | ||
case "int" -> unsafe.getInt(obj, offset); | ||
case "boolean" -> unsafe.getBoolean(obj, offset); | ||
case "byte" -> unsafe.getByte(obj, offset); | ||
case "long" -> unsafe.getLong(obj, offset); | ||
case "short" -> unsafe.getShort(obj, offset); | ||
case "float" -> unsafe.getFloat(obj, offset); | ||
case "char" -> unsafe.getChar(obj, offset); | ||
case "double" -> unsafe.getDouble(obj, offset); | ||
default -> unsafe.getObject(obj, offset); | ||
}; | ||
} | ||
|
||
public static Field getField(Class<?> clazz, String name) throws NoSuchFieldException { | ||
return getField(clazz, name, false); | ||
} | ||
|
||
/** | ||
* gets field from class and all superclasses | ||
* @param clazz the class the field is in | ||
* @param name the name of the field | ||
* @param includeInheritedFields if to search in the superclasses | ||
* @return the field | ||
*/ | ||
public static Field getField(Class<?> clazz, String name, boolean includeInheritedFields) throws NoSuchFieldException { | ||
for(Field field : getFields(clazz, includeInheritedFields)) { | ||
if (field.getName().equals(name)) { | ||
return field; | ||
} | ||
} | ||
throw new NoSuchFieldException(name); | ||
} | ||
|
||
/** | ||
* gets all fields from class and all superclasses if specified | ||
* @param clazz the class the field is in | ||
* @param includeInheritedFields if to get fields from superclasses | ||
* @return the fields specified | ||
*/ | ||
public static Field[] getFields(Class<?> clazz, boolean includeInheritedFields) { | ||
try { | ||
List<Field> fields = new ArrayList<>(); | ||
|
||
while (clazz != null) { | ||
for (Field field : (Field[]) getDeclaredFields0.invoke(clazz, false)) { | ||
fields.add((Field) copyField.invoke(field)); | ||
} | ||
if(includeInheritedFields) { | ||
clazz = clazz.getSuperclass(); | ||
} else { | ||
clazz = null; | ||
} | ||
} | ||
|
||
return fields.toArray(new Field[0]); | ||
} catch (InvocationTargetException | IllegalAccessException e) { | ||
e.printStackTrace(); | ||
} | ||
return new Field[0]; | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package reflection; | ||
|
||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
|
||
import static reflection.ReflectionUtils.*; | ||
|
||
public class MethodReflection { | ||
|
||
private static final Method getDeclaredMethods0; | ||
private static final Method copyMethod; | ||
|
||
static { | ||
try { | ||
getDeclaredMethods0 = forceAccessible(Class.class.getDeclaredMethod("getDeclaredMethods0", boolean.class), true); | ||
copyMethod = forceAccessible(Method.class.getDeclaredMethod("copy"), true); | ||
} catch (NoSuchMethodException e) { | ||
throw new RuntimeException("Initialization of MethodReflection failed", e); | ||
} | ||
} | ||
|
||
public static Object useStaticMethod(Method m, Object ... args) { | ||
return useMethod(m, null, args); | ||
} | ||
|
||
/** | ||
* invokes the method passed in | ||
* @param m method to invoke | ||
* @param instance the instance of the object to invoke the method with (null if method is static) | ||
* @param args the arguments to invoke the method with | ||
* @return new instance of constructor | ||
*/ | ||
public static Object useMethod(Method m, Object instance, Object ... args) { | ||
try { | ||
if(args.length == m.getParameterCount()) { | ||
boolean isOverride = isAccessible(m); | ||
|
||
forceAccessible(m, true); | ||
|
||
Object value = m.invoke(instance ,args); | ||
|
||
forceAccessible(m, isOverride); | ||
|
||
return value; | ||
} | ||
} catch (InvocationTargetException | IllegalAccessException e) { | ||
e.printStackTrace(); | ||
} | ||
return null; | ||
} | ||
|
||
public static Method getMethod(Class<?> clazz, String name, Class<?> ... classes) throws NoSuchMethodException { | ||
return getMethod(clazz, name, false, classes); | ||
} | ||
|
||
/** | ||
* gets method from class and all superclasses | ||
* @param clazz class the method is in | ||
* @param name the name of the method | ||
* @param includeInheritedMethods if to search in the superclasses | ||
* @param classes the argument types of the method | ||
* @return the constructor | ||
*/ | ||
public static Method getMethod(Class<?> clazz, String name, boolean includeInheritedMethods, Class<?> ... classes) throws NoSuchMethodException { | ||
for(Method method : getMethods(clazz, includeInheritedMethods)) { | ||
if (method.getName().equals(name) && Arrays.equals(method.getParameterTypes(), classes)) { | ||
return method; | ||
} | ||
} | ||
throw new NoSuchMethodException(methodToString(clazz, name, classes)); | ||
} | ||
|
||
/** | ||
* gets all methods from class and all superclasses if specified | ||
* @param clazz the class the method is in | ||
* @param includeInheritedFields if to get methods from superclasses | ||
* @return the methods specified | ||
*/ | ||
public static Method[] getMethods(Class<?> clazz, boolean includeInheritedFields) { | ||
try { | ||
List<Method> methods = new ArrayList<>(); | ||
|
||
while (clazz != null) { | ||
for (Method method : (Method[]) getDeclaredMethods0.invoke(clazz, false)) { | ||
methods.add((Method) copyMethod.invoke(method)); | ||
} | ||
if(includeInheritedFields) { | ||
clazz = clazz.getSuperclass(); | ||
} else { | ||
clazz = null; | ||
} | ||
} | ||
|
||
return methods.toArray(new Method[0]); | ||
} catch (InvocationTargetException | IllegalAccessException | IndexOutOfBoundsException e) { | ||
e.printStackTrace(); | ||
} | ||
return new Method[0]; | ||
} | ||
} |
Oops, something went wrong.