Skip to content

Commit

Permalink
2.0.0: Update everything
Browse files Browse the repository at this point in the history
Implement few API methods
Fix Java 12 support
Fix warnings
Make plugin disabling properly
Replace injected netty handler with old handler on onDisable
  • Loading branch information
metabrixkt committed May 9, 2021
1 parent 96cf2e7 commit 40658f2
Show file tree
Hide file tree
Showing 13 changed files with 448 additions and 174 deletions.
17 changes: 11 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@

<groupId>nl.thijsalders</groupId>
<artifactId>spigotproxy</artifactId>
<version>1</version>
<version>2.0.0</version>
<packaging>jar</packaging>

<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<repositories>
Expand All @@ -25,7 +26,7 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.13.2-R0.1-SNAPSHOT</version>
<version>1.16.5-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
Expand All @@ -34,6 +35,10 @@
<version>4.1.31.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>20.1.0</version>
</dependency>
</dependencies>

</project>
</project>
24 changes: 24 additions & 0 deletions src/main/java/nl/thijsalders/spigotproxy/ReflectionException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package nl.thijsalders.spigotproxy;

public class ReflectionException extends RuntimeException {

public ReflectionException(Throwable throwable) {
super("An exception occurred during the reflection process", throwable);
}


public ReflectionException(String message) {
super(message);
}


public ReflectionException(String message, Throwable throwable) {
super(message, throwable);
}


public ReflectionException() {
super();
}

}
209 changes: 172 additions & 37 deletions src/main/java/nl/thijsalders/spigotproxy/ReflectionUtils.java
Original file line number Diff line number Diff line change
@@ -1,59 +1,194 @@
package nl.thijsalders.spigotproxy;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

/**
* Utils for reflection and manipulation
*/
public class ReflectionUtils {

private static final Field FIELD_MODIFIERS;
private static final Field FIELD_ACCESSSOR;
private static final Field FIELD_ACCESSSOR_OVERRIDE;
private static final Field FIELD_ROOT;
/**
* Cached information for Fields
*/
private static final Table<Class<?>, String, Field> CACHED_FIELDS_BY_NAME = HashBasedTable.create();
private static final Table<Class<?>, Class<?>, Field> CACHED_FIELDS_BY_CLASS = HashBasedTable.create();
private static Field modifiersField;


/**
* Sets a final field, with a field name, inside an object
* @param object The object
* @param fieldName The field name
* @param value The new value
* @throws ReflectionException Thrown when the operation was not successful
*/
public static void setFinalField(Object object, String fieldName, Object value) throws ReflectionException {
setFinalField(object, getPrivateField(object.getClass(), fieldName), value);
}

/**
* Sets a final field, with a field object, inside an object
* @param object The object
* @param field The field
* @param value The new value
* @throws ReflectionException Thrown when the operation was not successful
*/
public static void setFinalField(Object object, Field field, Object value) throws ReflectionException {
field.setAccessible(true);

if (Modifier.isFinal(field.getModifiers())) {
if (modifiersField == null) {
try {
modifiersField = getDeclaredField(Field.class, "modifiers");
} catch (ReflectionException e) { // workaround for when searching for the modifiers field on Java 12 or higher
try {
Method getDeclaredFields0 = Class.class.getDeclaredMethod("getDeclaredFields0", boolean.class);
getDeclaredFields0.setAccessible(true);

Field[] fields = (Field[]) getDeclaredFields0.invoke(Field.class, false);
modifiersField = Arrays.stream(fields).filter(modifier -> modifier.getName().equals("modifiers")).findFirst().orElseThrow(() -> new ReflectionException("Could not find the modifiers field"));
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e2) {
throw new ReflectionException(e2);
}
}

static {
Field fieldModifiers = null;
Field fieldAccessor = null;
Field fieldAccessorOverride = null;
Field fieldRoot = null;
modifiersField.setAccessible(true);
}

try {
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
} catch (IllegalAccessException e) {
throw new ReflectionException(e);
}
}

setField(object, field, value);
}

/**
* Sets a field, with a field name, inside an object
* @param object The object
* @param fieldName The field name
* @param value The new value
* @throws ReflectionException Thrown when the operation was not successful
*/
public static void setField(Object object, String fieldName, Object value) throws ReflectionException {
setField(object, getPrivateField(object.getClass(), fieldName), value);
}

/**
* Sets a field, with a field object, inside an object
* @param object The object
* @param field The field
* @param value The new value
* @throws ReflectionException Thrown when the operation was not successful
*/
public static void setField(Object object, Field field, Object value) throws ReflectionException {
try {
fieldModifiers = Field.class.getDeclaredField("modifiers");
fieldModifiers.setAccessible(true);
fieldAccessor = Field.class.getDeclaredField("fieldAccessor");
fieldAccessor.setAccessible(true);
fieldAccessorOverride = Field.class.getDeclaredField("overrideFieldAccessor");
fieldAccessorOverride.setAccessible(true);
fieldRoot = Field.class.getDeclaredField("root");
fieldRoot.setAccessible(true);
} catch (Exception exception) {
exception.printStackTrace();
field.set(object, value);
} catch (IllegalAccessException e) {
throw new ReflectionException(e);
}
FIELD_MODIFIERS = fieldModifiers;
FIELD_ACCESSSOR = fieldAccessor;
FIELD_ACCESSSOR_OVERRIDE = fieldAccessorOverride;
FIELD_ROOT = fieldRoot;
}

public static void setFinalField(Class<?> objectClass, Object object, String fieldName, Object value) throws Exception {
Field field = objectClass.getDeclaredField(fieldName);
/**
* Gets the object inside a private field, with a field name, in an object
* @param object The object
* @param fieldName The field name
* @return The grabbed object
* @throws ReflectionException Thrown when the operation was not successful
*/
public static Object getObjectInPrivateField(Object object, String fieldName) throws ReflectionException {
Field field = getPrivateField(object.getClass(), fieldName);
try {
return field.get(object);
} catch (IllegalAccessException e) {
throw new ReflectionException(e);
}
}

/**
* Gets a private field, with a field name, inside an object
* @param clazz The clazz
* @param fieldName The field name
* @return The grabbed field
* @throws ReflectionException Thrown when the operation was not successful
*/
public static Field getPrivateField(Class<?> clazz, String fieldName) throws ReflectionException {
Field field = getDeclaredField(clazz, fieldName);
field.setAccessible(true);
return field;
}

if (Modifier.isFinal(field.getModifiers())) {
FIELD_MODIFIERS.setInt(field, field.getModifiers() & ~Modifier.FINAL);
Field currentField = field;
do {
FIELD_ACCESSSOR.set(currentField, null);
FIELD_ACCESSSOR_OVERRIDE.set(currentField, null);
} while((currentField = (Field) FIELD_ROOT.get(currentField)) != null);
/**
* Searches for a field, with the type of the provided class, inside a class
* @param clazz The class to search through
* @param searchFor The class type to search for
* @return The found field
* @throws ReflectionException Thrown when the operation was not successful
*/
public static Field searchFieldByClass(Class<?> clazz, Class<?> searchFor) throws ReflectionException {
Field cachedField = CACHED_FIELDS_BY_CLASS.get(clazz, searchFor);
if (cachedField != null) return cachedField;

Class<?> currentClass = clazz;
do {
for (Field field : currentClass.getDeclaredFields()) {
if (!searchFor.isAssignableFrom(field.getType())) continue;

CACHED_FIELDS_BY_CLASS.put(clazz, searchFor, field);
return field;
}

currentClass = currentClass.getSuperclass();
} while (currentClass != null);

throw new ReflectionException("no " + searchFor.getName() + " field for clazz = " + clazz.getName() + " found");
}

/**
* Gets a declared field, with a field name, inside a class
* @param clazz The clazz
* @param fieldName The field name
* @return The declared field
* @throws ReflectionException Thrown when the operation was not successful
*/
public static Field getDeclaredField(Class<?> clazz, String fieldName) throws ReflectionException {
Field cachedField = CACHED_FIELDS_BY_NAME.get(clazz, fieldName);
if (cachedField != null) return cachedField;

Field field;
try {
field = clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
Class<?> superclass = clazz.getSuperclass();
if (superclass != null) {
return getDeclaredField(superclass, fieldName);
} else {
throw new ReflectionException(e);
}
}

field.set(object, value);

CACHED_FIELDS_BY_NAME.put(clazz, fieldName, field);
return field;
}

@SuppressWarnings("unchecked")
public static <T> T getPrivateField(Class<?> objectClass, Object object, Class<T> fieldClass, String fieldName) throws Exception {
Field field = objectClass.getDeclaredField(fieldName);
public static <T> T getDeclaredField(Object object, String fieldName) {
Field field = getDeclaredField(object.getClass(), fieldName);
field.setAccessible(true);
return (T) field.get(object);
try {
return (T) field.get(object);
} catch (IllegalAccessException e) {
throw new ReflectionException(e);
}
}

}
Loading

0 comments on commit 40658f2

Please sign in to comment.