Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
vi945786 authored Apr 7, 2024
1 parent d79419f commit 55cb3ba
Show file tree
Hide file tree
Showing 12 changed files with 698 additions and 4 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

### ... and this library makes it suck a little less.

supports java 9 to 19
supports java 9 to 21

Including:

Expand All @@ -13,5 +13,3 @@ Including:
2. Change values of fields, invoke methods and create new instances by invoking constructors.

3. Support for accessing "Inaccessible" objects which would result in an InaccessibleObjectException when accessing with regular reflection.

4. Method to crash the JVM (lol)
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
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
98 changes: 98 additions & 0 deletions src/main/java/reflection/ConstructorReflection.java
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];
}
}
140 changes: 140 additions & 0 deletions src/main/java/reflection/FieldReflection.java
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];
}
}
103 changes: 103 additions & 0 deletions src/main/java/reflection/MethodReflection.java
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];
}
}
Loading

0 comments on commit 55cb3ba

Please sign in to comment.