PlotSquared/Core/src/main/java/com/plotsquared/core/util/ReflectionUtils.java

304 lines
8.2 KiB
Java
Raw Normal View History

/*
* PlotSquared, a land and world management plugin for Minecraft.
* Copyright (C) IntellectualSites <https://intellectualsites.com>
* Copyright (C) IntellectualSites team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2020-04-15 21:26:54 +02:00
package com.plotsquared.core.util;
2014-09-22 13:02:14 +02:00
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
2014-09-22 13:02:14 +02:00
/**
* @author DPOH-VAR
* @version 1.0
*/
2015-09-13 06:04:31 +02:00
public class ReflectionUtils {
2016-03-23 02:41:37 +01:00
2014-11-08 20:27:09 +01:00
/**
* prefix of bukkit classes
*/
2014-12-18 03:15:11 +01:00
private static String preClassB = "org.bukkit.craftbukkit";
2014-11-08 20:27:09 +01:00
/**
* prefix of minecraft classes
*/
2014-12-18 03:15:11 +01:00
private static String preClassM = "net.minecraft.server";
2016-03-23 02:41:37 +01:00
public ReflectionUtils(String version) {
if (version != null) {
2016-04-28 22:38:51 +02:00
preClassB += '.' + version;
preClassM += '.' + version;
}
}
2016-03-23 02:41:37 +01:00
public static Class<?> getClass(String name) {
2015-09-13 06:04:31 +02:00
try {
2015-06-08 12:30:46 +02:00
return Class.forName(name);
2016-04-30 00:14:12 +02:00
} catch (ClassNotFoundException ignored) {
2015-06-08 12:30:46 +02:00
return null;
}
}
2016-03-23 02:41:37 +01:00
public static <T> Class<? extends T> getClass(String name, Class<T> superClass) {
2015-09-13 06:04:31 +02:00
try {
2015-06-08 12:30:46 +02:00
return Class.forName(name).asSubclass(superClass);
2016-04-30 00:14:12 +02:00
} catch (ClassCastException | ClassNotFoundException ignored) {
2015-06-08 12:30:46 +02:00
return null;
}
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
2014-12-18 03:15:11 +01:00
* Get class for name. Replace {nms} to net.minecraft.server.V*. Replace {cb} to org.bukkit.craftbukkit.V*. Replace
* {nm} to net.minecraft
*
2016-04-30 00:14:12 +02:00
* @param className possible class paths
2014-11-05 04:42:08 +01:00
* @return RefClass object
2016-04-30 00:14:12 +02:00
* @throws ClassNotFoundException if no class found
2014-11-05 04:42:08 +01:00
*/
2016-04-30 00:14:12 +02:00
public static RefClass getRefClass(String className) throws ClassNotFoundException {
2018-08-10 17:01:10 +02:00
className = className.replace("{cb}", preClassB).replace("{nms}", preClassM)
.replace("{nm}", "net.minecraft");
2016-04-30 00:14:12 +02:00
return getRefClass(Class.forName(className));
2014-11-05 04:42:08 +01:00
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* get RefClass object by real class
*
2014-12-18 03:15:11 +01:00
* @param clazz class
2014-11-05 04:42:08 +01:00
* @return RefClass based on passed class
*/
2021-05-01 18:33:02 +02:00
public static RefClass getRefClass(Class<?> clazz) {
2014-11-05 04:42:08 +01:00
return new RefClass(clazz);
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* RefClass - utility to simplify work with reflections.
*/
2015-09-13 06:04:31 +02:00
public static class RefClass {
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
private final Class<?> clazz;
2016-03-23 02:41:37 +01:00
private RefClass(Class<?> clazz) {
2014-11-16 10:48:18 +01:00
this.clazz = clazz;
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* get passed class
*
* @return class
*/
2015-09-13 06:04:31 +02:00
public Class<?> getRealClass() {
2016-03-23 02:41:37 +01:00
return this.clazz;
2014-11-05 04:42:08 +01:00
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* get existing method by name and types
*
2014-12-18 03:15:11 +01:00
* @param name name
* @param types method parameters. can be Class or RefClass
2014-11-05 04:42:08 +01:00
* @return RefMethod object
* @throws NoSuchMethodException if method not found
2014-11-05 04:42:08 +01:00
*/
2016-04-30 00:14:12 +02:00
public RefMethod getMethod(String name, Object... types) throws NoSuchMethodException {
2021-05-01 18:33:02 +02:00
Class<?>[] classes = new Class[types.length];
2016-04-30 00:14:12 +02:00
int i = 0;
for (Object e : types) {
if (e instanceof Class) {
2021-05-01 18:33:02 +02:00
classes[i++] = (Class<?>) e;
2016-04-30 00:14:12 +02:00
} else if (e instanceof RefClass) {
classes[i++] = ((RefClass) e).getRealClass();
} else {
classes[i++] = e.getClass();
2014-11-05 04:42:08 +01:00
}
2016-04-30 00:14:12 +02:00
}
try {
return new RefMethod(this.clazz.getMethod(name, classes));
} catch (NoSuchMethodException ignored) {
return new RefMethod(this.clazz.getDeclaredMethod(name, classes));
2014-11-05 04:42:08 +01:00
}
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* get field by name
*
2014-12-18 03:15:11 +01:00
* @param name field name
2014-11-05 04:42:08 +01:00
* @return RefField
* @throws NoSuchFieldException if field not found
2014-11-05 04:42:08 +01:00
*/
2016-04-30 00:14:12 +02:00
public RefField getField(String name) throws NoSuchFieldException {
2015-09-13 06:04:31 +02:00
try {
2016-04-30 00:14:12 +02:00
return new RefField(this.clazz.getField(name));
} catch (NoSuchFieldException ignored) {
return new RefField(this.clazz.getDeclaredField(name));
2014-11-05 04:42:08 +01:00
}
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
}
2016-03-23 02:41:37 +01:00
2018-08-10 17:01:10 +02:00
2014-11-05 04:42:08 +01:00
/**
* Method wrapper
*/
2015-09-13 06:04:31 +02:00
public static class RefMethod {
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
private final Method method;
2016-03-23 02:41:37 +01:00
private RefMethod(Method method) {
2014-11-16 10:48:18 +01:00
this.method = method;
method.setAccessible(true);
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* @return passed method
*/
2015-09-13 06:04:31 +02:00
public Method getRealMethod() {
2016-03-23 02:41:37 +01:00
return this.method;
2014-11-05 04:42:08 +01:00
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* apply method to object
*
2014-12-18 03:15:11 +01:00
* @param e object to which the method is applied
2014-11-05 04:42:08 +01:00
* @return RefExecutor with method call(...)
*/
2016-03-23 02:41:37 +01:00
public RefExecutor of(Object e) {
2014-11-05 04:42:08 +01:00
return new RefExecutor(e);
}
2016-03-23 02:41:37 +01:00
2015-09-13 06:04:31 +02:00
public class RefExecutor {
2016-03-23 02:41:37 +01:00
2014-11-21 23:45:46 +01:00
final Object e;
2016-03-23 02:41:37 +01:00
public RefExecutor(Object e) {
2014-11-05 04:42:08 +01:00
this.e = e;
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* apply method for selected object
*
2014-12-18 03:15:11 +01:00
* @param params sent parameters
2014-11-05 04:42:08 +01:00
* @return return value
2014-12-18 03:15:11 +01:00
* @throws RuntimeException if something went wrong
2014-11-05 04:42:08 +01:00
*/
2016-03-23 02:41:37 +01:00
public Object call(Object... params) {
2015-09-13 06:04:31 +02:00
try {
2016-03-23 02:41:37 +01:00
return RefMethod.this.method.invoke(this.e, params);
} catch (Exception e) {
2014-11-05 04:42:08 +01:00
throw new RuntimeException(e);
}
}
2014-11-05 04:42:08 +01:00
}
2014-11-05 04:42:08 +01:00
}
2016-03-23 02:41:37 +01:00
2018-08-10 17:01:10 +02:00
2014-11-05 04:42:08 +01:00
/**
* Constructor wrapper
*/
2015-09-13 06:04:31 +02:00
public static class RefConstructor {
2016-03-23 02:41:37 +01:00
2021-05-01 18:33:02 +02:00
private final Constructor<?> constructor;
2016-03-23 02:41:37 +01:00
2021-05-01 18:33:02 +02:00
private RefConstructor(Constructor<?> constructor) {
2014-11-16 10:48:18 +01:00
this.constructor = constructor;
constructor.setAccessible(true);
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* create new instance with constructor
*
2014-12-18 03:15:11 +01:00
* @param params parameters for constructor
2014-11-05 04:42:08 +01:00
* @return new object
* @throws ReflectiveOperationException reflective operation exception
* @throws IllegalArgumentException illegal argument exception
2014-11-05 04:42:08 +01:00
*/
2018-08-10 17:01:10 +02:00
public Object create(Object... params)
throws ReflectiveOperationException, IllegalArgumentException {
2018-08-10 17:01:10 +02:00
return this.constructor.newInstance(params);
2014-11-05 04:42:08 +01:00
}
2014-11-05 04:42:08 +01:00
}
2016-03-23 02:41:37 +01:00
2018-08-10 17:01:10 +02:00
2015-09-13 06:04:31 +02:00
public static class RefField {
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
private final Field field;
2016-03-23 02:41:37 +01:00
private RefField(Field field) {
2014-11-16 10:48:18 +01:00
this.field = field;
field.setAccessible(true);
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* @return passed field
*/
2015-09-13 06:04:31 +02:00
public Field getRealField() {
2016-03-23 02:41:37 +01:00
return this.field;
2014-11-05 04:42:08 +01:00
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* apply fiend for object
*
2014-12-18 03:15:11 +01:00
* @param e applied object
2014-11-05 04:42:08 +01:00
* @return RefExecutor with getter and setter
*/
2016-03-23 02:41:37 +01:00
public RefExecutor of(Object e) {
2014-11-05 04:42:08 +01:00
return new RefExecutor(e);
}
2016-03-23 02:41:37 +01:00
2015-09-13 06:04:31 +02:00
public class RefExecutor {
2016-03-23 02:41:37 +01:00
2014-11-21 23:45:46 +01:00
final Object e;
2016-03-23 02:41:37 +01:00
public RefExecutor(Object e) {
2014-11-05 04:42:08 +01:00
this.e = e;
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* set field value for applied object
*
2014-12-18 03:15:11 +01:00
* @param param value
2014-11-05 04:42:08 +01:00
*/
2016-03-23 02:41:37 +01:00
public void set(Object param) {
2015-09-13 06:04:31 +02:00
try {
2016-03-23 02:41:37 +01:00
RefField.this.field.set(this.e, param);
} catch (Exception e) {
2014-11-05 04:42:08 +01:00
throw new RuntimeException(e);
}
}
2016-03-23 02:41:37 +01:00
2014-11-05 04:42:08 +01:00
/**
* get field value for applied object
*
* @return value of field
*/
2015-09-13 06:04:31 +02:00
public Object get() {
try {
2016-03-23 02:41:37 +01:00
return RefField.this.field.get(this.e);
} catch (Exception e) {
2014-11-05 04:42:08 +01:00
throw new RuntimeException(e);
}
}
2014-11-05 04:42:08 +01:00
}
2014-11-05 04:42:08 +01:00
}
2014-09-22 13:02:14 +02:00
}