major reflection improvements (fixes #12)

This commit is contained in:
Pyrbu 2023-04-22 04:32:17 +01:00
parent dfbd9bebce
commit 5395094063
11 changed files with 199 additions and 101 deletions

@ -6,7 +6,6 @@ import io.github.znetworkw.znpcservers.commands.exception.CommandExecuteExceptio
import io.github.znetworkw.znpcservers.commands.exception.CommandPermissionException;
import io.github.znetworkw.znpcservers.reflection.Reflections;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandMap;
import org.bukkit.command.CommandSender;
import org.bukkit.command.defaults.BukkitCommand;
@ -23,7 +22,7 @@ public class Command extends BukkitCommand {
}
private void load() {
((CommandMap) Reflections.COMMAND_MAP_FIELD.get()).register(getName(), this);
Reflections.COMMAND_MAP_FIELD.get().register(getName(), this);
for (Method method : getClass().getMethods()) {
if (method.isAnnotationPresent(CommandInformation.class)) {
CommandInformation cmdInfo = method.getAnnotation(CommandInformation.class);

@ -11,7 +11,7 @@ public class PacketV19 extends PacketV18 {
public Object getPlayerPacket(Object nmsWorld, GameProfile gameProfile) throws ReflectiveOperationException {
try {
return Reflections.PLAYER_CONSTRUCTOR_NEW_1.get(true).newInstance(Reflections.GET_SERVER_METHOD.get().invoke(Bukkit.getServer()), nmsWorld, gameProfile, null);
return Reflections.PLAYER_CONSTRUCTOR_NEW_1.get().newInstance(Reflections.GET_SERVER_METHOD.get().invoke(Bukkit.getServer()), nmsWorld, gameProfile, null);
} catch (Throwable e) {
return Reflections.PLAYER_CONSTRUCTOR_NEW_2.get().newInstance(Reflections.GET_SERVER_METHOD.get().invoke(Bukkit.getServer()), nmsWorld, gameProfile);
}

@ -39,7 +39,7 @@ public class PacketV8 implements Packet {
public Object getMetadataPacket(int entityId, Object nmsEntity) throws ReflectiveOperationException {
Object dataWatcher = Reflections.GET_DATA_WATCHER_METHOD.get().invoke(nmsEntity);
try {
return Reflections.PACKET_PLAY_OUT_ENTITY_META_DATA_CONSTRUCTOR.get(true).newInstance(entityId, dataWatcher, true);
return Reflections.PACKET_PLAY_OUT_ENTITY_META_DATA_CONSTRUCTOR.get().newInstance(entityId, dataWatcher, true);
} catch (Exception e2) {
return Reflections.PACKET_PLAY_OUT_ENTITY_META_DATA_CONSTRUCTOR_V1.get().newInstance(entityId, Reflections.GET_DATAWATCHER_B_LIST.get().invoke(dataWatcher));
}

@ -13,6 +13,7 @@ public class ReflectionBuilder {
private final ArrayList<String> methods = new ArrayList<>();
private final ArrayList<Class<?>[]> parameterTypes = new ArrayList<>();
private Class<?> expectType;
private boolean strict = true;
public ReflectionBuilder(String reflectionPackage) {
this(reflectionPackage, "", "", null);
@ -60,6 +61,15 @@ public class ReflectionBuilder {
return this;
}
public ReflectionBuilder setStrict(boolean strict) {
this.strict = strict;
return this;
}
public boolean isStrict() {
return strict;
}
public Class<?> getExpectType() {
return expectType;
}

@ -3,50 +3,46 @@ package io.github.znetworkw.znpcservers.reflection;
import io.github.znetworkw.znpcservers.utility.Utils;
import lol.pyr.znpcsplus.ZNPCsPlus;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public abstract class ReflectionLazyLoader<T> {
protected final List<String> possibleClassNames;
protected Class<?> reflectionClass;
protected List<Class<?>> reflectionClasses = new ArrayList<>();
protected final boolean strict;
private T cached;
private boolean loaded = false;
protected ReflectionLazyLoader(ReflectionBuilder builder) {
this(builder.getClassNames());
this(builder.getClassNames(), builder.isStrict());
}
protected ReflectionLazyLoader(List<String> possibleClassNames) {
protected ReflectionLazyLoader(List<String> possibleClassNames, boolean strict) {
this.possibleClassNames = possibleClassNames;
for (String classes : possibleClassNames) {
try {
this.reflectionClass = Class.forName(classes);
break;
} catch (ClassNotFoundException ignored) {
}
}
this.strict = strict;
for (String name : possibleClassNames) try {
reflectionClasses.add(Class.forName(name));
} catch (ClassNotFoundException ignored) {}
}
public T get() {
return get(false);
}
public T get(boolean missAllowed) {
if (this.loaded) return this.cached;
try {
if (this.reflectionClass == null) throw new ClassNotFoundException("No class found: " + possibleClassNames);
if (this.reflectionClasses.size() == 0) throw new ClassNotFoundException("No class found: " + possibleClassNames);
T eval = (this.cached != null) ? this.cached : (this.cached = load());
if (eval == null) throw new NullPointerException();
if (eval == null) throw new RuntimeException("Returned value is null");
} catch (Throwable throwable) {
if (!missAllowed) {
warn(getClass().getSimpleName() + " get failed!");
if (strict) {
warn(" ----- REFLECTION FAILURE DEBUG INFORMATION, REPORT THIS ON OUR GITHUB ----- ");
warn(getClass().getSimpleName() + " failed!");
warn("Class Names: " + possibleClassNames);
warn("Loader Type: " + getClass().getCanonicalName());
warn("Reflection Type: " + getClass().getCanonicalName());
warn("Bukkit Version: " + Utils.BUKKIT_VERSION + " (" + Utils.getBukkitPackage() + ")");
printDebugInfo(this::warn);
warn("Exception:");
throwable.printStackTrace();
warn(" ----- REFLECTION FAILURE DEBUG INFORMATION, REPORT THIS ON OUR GITHUB ----- ");
}
}
this.loaded = true;
@ -58,4 +54,5 @@ public abstract class ReflectionLazyLoader<T> {
}
protected abstract T load() throws Exception;
protected void printDebugInfo(Consumer<String> logger) {}
}

@ -1,10 +1,14 @@
package io.github.znetworkw.znpcservers.reflection;
import com.mojang.authlib.GameProfile;
import io.github.znetworkw.znpcservers.reflection.types.*;
import io.github.znetworkw.znpcservers.reflection.types.ClassReflection;
import io.github.znetworkw.znpcservers.reflection.types.ConstructorReflection;
import io.github.znetworkw.znpcservers.reflection.types.FieldReflection;
import io.github.znetworkw.znpcservers.reflection.types.MethodReflection;
import io.github.znetworkw.znpcservers.utility.Utils;
import io.netty.channel.Channel;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandMap;
import org.bukkit.inventory.ItemStack;
import java.lang.reflect.Constructor;
@ -104,7 +108,8 @@ public final class Reflections {
public static final Class<?> ENTITY_LLAMA_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal.horse")
.withClassName("EntityLlama")).get(!Utils.versionNewer(11));
.withClassName("EntityLlama")
.setStrict(Utils.versionNewer(11))).get();
public static final Class<?> ENTITY_MAGMA_CUBE_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("monster")
@ -120,20 +125,24 @@ public final class Reflections {
public static final Class<?> ENTITY_TURTLE = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal")
.withClassName("EntityTurtle")).get(!Utils.versionNewer(13));
.withClassName("EntityTurtle")
.setStrict(Utils.versionNewer(13))).get();
public static final Class<?> ENTITY_WARDEN = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("monster.warden")
.withClassName("EntityWarden")
.withClassName("Warden")).get(!Utils.versionNewer(19));
.withClassName("Warden")
.setStrict(Utils.versionNewer(19))).get();
public static final Class<?> ENTITY_BEE_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal")
.withClassName("EntityBee")).get(!Utils.versionNewer(15));
.withClassName("EntityBee")
.setStrict(Utils.versionNewer(15))).get();
public static final Class<?> ENTITY_PARROT_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal")
.withClassName("EntityParrot")).get(!Utils.versionNewer(12));
.withClassName("EntityParrot")
.setStrict(Utils.versionNewer(12))).get();
public static final Class<?> ENTITY_PIG_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal")
@ -145,11 +154,13 @@ public final class Reflections {
public static final Class<?> ENTITY_POLAR_BEAR_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal")
.withClassName("EntityPolarBear")).get(!Utils.versionNewer(10));
.withClassName("EntityPolarBear")
.setStrict(Utils.versionNewer(10))).get();
public static final Class<?> ENTITY_PANDA_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal")
.withClassName("EntityPanda")).get(!Utils.versionNewer(14));
.withClassName("EntityPanda")
.setStrict(Utils.versionNewer(14))).get();
public static final Class<?> ENTITY_SHEEP_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal")
@ -161,7 +172,8 @@ public final class Reflections {
public static final Class<?> ENTITY_SHULKER_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("monster")
.withClassName("EntityShulker")).get(!Utils.versionNewer(9));
.withClassName("EntityShulker")
.setStrict(Utils.versionNewer(9))).get();
public static final Class<?> ENTITY_SILVERFISH_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("monster")
@ -205,15 +217,18 @@ public final class Reflections {
public static final Class<?> ENTITY_AXOLOTL_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal.axolotl")
.withClassName("Axolotl")).get(!Utils.versionNewer(17));
.withClassName("Axolotl")
.setStrict(Utils.versionNewer(17))).get();
public static final Class<?> ENTITY_GOAT_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal.goat")
.withClassName("Goat")).get(!Utils.versionNewer(17));
.withClassName("Goat")
.setStrict(Utils.versionNewer(17))).get();
public static final Class<?> ENTITY_FOX_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withSubClass("animal")
.withClassName("EntityFox")).get(!Utils.versionNewer(14));
.withClassName("EntityFox")
.setStrict(Utils.versionNewer(14))).get();
public static final Class<?> ENTITY_TYPES_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withClassName("EntityTypes")).get();
@ -222,7 +237,8 @@ public final class Reflections {
.withClassName("EnumChatFormat")).get();
public static final Class<?> ENUM_ITEM_SLOT = new ClassReflection(new ReflectionBuilder(ReflectionPackage.ENTITY)
.withClassName("EnumItemSlot")).get(!Utils.versionNewer(9));
.withClassName("EnumItemSlot")
.setStrict(Utils.versionNewer(9))).get();
public static final Class<?> I_CHAT_BASE_COMPONENT = new ClassReflection(new ReflectionBuilder(ReflectionPackage.CHAT)
.withClassName("IChatBaseComponent")).get();
@ -231,16 +247,20 @@ public final class Reflections {
.withClassName("ItemStack")).get();
public static final Class<?> DATA_WATCHER_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.SYNCHER)
.withClassName("DataWatcher")).get(!Utils.versionNewer(9));
.withClassName("DataWatcher")
.setStrict(Utils.versionNewer(9))).get();
public static final Class<?> DATA_WATCHER_OBJECT = new ClassReflection(new ReflectionBuilder(ReflectionPackage.SYNCHER)
.withClassName("DataWatcherObject")).get(!Utils.versionNewer(9));
.withClassName("DataWatcherObject")
.setStrict(Utils.versionNewer(9))).get();
public static final Class<?> DATA_WATCHER_REGISTRY = new ClassReflection(new ReflectionBuilder(ReflectionPackage.SYNCHER)
.withClassName("DataWatcherRegistry")).get(!Utils.versionNewer(9));
.withClassName("DataWatcherRegistry")
.setStrict(Utils.versionNewer(9))).get();
public static final Class<?> DATA_WATCHER_SERIALIZER = new ClassReflection(new ReflectionBuilder(ReflectionPackage.SYNCHER)
.withClassName("DataWatcherSerializer")).get(!Utils.versionNewer(9));
.withClassName("DataWatcherSerializer")
.setStrict(Utils.versionNewer(9))).get();
public static final Class<?> WORLD_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.WORLD_LEVEL)
.withClassName("World")).get();
@ -265,12 +285,11 @@ public final class Reflections {
public static final Class<?> PACKET_PLAY_OUT_PLAYER_INFO_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.PACKET)
.withClassName("PacketPlayOutPlayerInfo")
.withClassName("ClientboundPlayerInfoUpdatePacket"))
.get();
.withClassName("ClientboundPlayerInfoUpdatePacket")).get();
public static final Class<?> PACKET_PLAY_OUT_PLAYER_INFO_REMOVE_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.PACKET)
.withClassName("ClientboundPlayerInfoRemovePacket"))
.get(true);
.withClassName("ClientboundPlayerInfoRemovePacket")
.setStrict(false)).get();
public static final Class<?> PACKET_PLAY_OUT_SCOREBOARD_TEAM_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.PACKET)
.withClassName("PacketPlayOutScoreboardTeam")).get();
@ -291,7 +310,8 @@ public final class Reflections {
.withClassName("util.CraftChatMessage")).get();
public static final Class<?> PROFILE_PUBLIC_KEY_CLASS = new ClassReflection(new ReflectionBuilder(ReflectionPackage.WORLD_ENTITY_PLAYER)
.withClassName("ProfilePublicKey")).get(!Utils.versionNewer(19));
.withClassName("ProfilePublicKey")
.setStrict(Utils.versionNewer(19))).get();
public static final ReflectionLazyLoader<Constructor<?>> SCOREBOARD_TEAM_CONSTRUCTOR = new ConstructorReflection(new ReflectionBuilder(ReflectionPackage.PACKET)
.withClassName(SCOREBOARD_TEAM_CLASS)
@ -307,7 +327,8 @@ public final class Reflections {
public static final ReflectionLazyLoader<Constructor<?>> PLAYER_CONSTRUCTOR_NEW_1 = new ConstructorReflection(new ReflectionBuilder(ReflectionPackage.PACKET)
.withClassName(ENTITY_PLAYER_CLASS)
.withParameterTypes(MINECRAFT_SERVER_CLASS, WORLD_SERVER_CLASS, GameProfile.class, PROFILE_PUBLIC_KEY_CLASS));
.withParameterTypes(MINECRAFT_SERVER_CLASS, WORLD_SERVER_CLASS, GameProfile.class, PROFILE_PUBLIC_KEY_CLASS)
.setStrict(false));
public static final ReflectionLazyLoader<Constructor<?>> PLAYER_CONSTRUCTOR_NEW_2 = new ConstructorReflection(new ReflectionBuilder(ReflectionPackage.PACKET)
.withClassName(ENTITY_PLAYER_CLASS)
@ -335,7 +356,8 @@ public final class Reflections {
public static final ReflectionLazyLoader<Constructor<?>> PACKET_PLAY_OUT_ENTITY_META_DATA_CONSTRUCTOR = new ConstructorReflection(new ReflectionBuilder(ReflectionPackage.PACKET)
.withClassName("PacketPlayOutEntityMetadata")
.withParameterTypes(int.class, DATA_WATCHER_CLASS, boolean.class));
.withParameterTypes(int.class, DATA_WATCHER_CLASS, boolean.class)
.setStrict(false));
public static final ReflectionLazyLoader<Constructor<?>> PACKET_PLAY_OUT_ENTITY_META_DATA_CONSTRUCTOR_V1 = new ConstructorReflection(new ReflectionBuilder(ReflectionPackage.PACKET)
.withClassName("PacketPlayOutEntityMetadata")
@ -558,7 +580,7 @@ public final class Reflections {
.withClassName(ENUM_TAG_VISIBILITY)
.withFieldName("b")).staticValueLoader();
public static final ReflectionLazyLoader<Object> COMMAND_MAP_FIELD = new FieldReflection(new ReflectionBuilder(ReflectionPackage.BUKKIT)
public static final ReflectionLazyLoader<CommandMap> COMMAND_MAP_FIELD = new FieldReflection(new ReflectionBuilder(ReflectionPackage.BUKKIT)
.withClassName("CraftServer")
.withFieldName("commandMap")).valueLoader(Bukkit.getServer());
.withFieldName("commandMap")).valueLoader(Bukkit.getServer(), CommandMap.class);
}

@ -1,7 +1,7 @@
package io.github.znetworkw.znpcservers.reflection.types;
import io.github.znetworkw.znpcservers.reflection.ReflectionLazyLoader;
import io.github.znetworkw.znpcservers.reflection.ReflectionBuilder;
import io.github.znetworkw.znpcservers.reflection.ReflectionLazyLoader;
public class ClassReflection extends ReflectionLazyLoader<Class<?>> {
public ClassReflection(ReflectionBuilder reflectionBuilder) {
@ -9,6 +9,6 @@ public class ClassReflection extends ReflectionLazyLoader<Class<?>> {
}
protected Class<?> load() {
return this.reflectionClass;
return this.reflectionClasses.size() > 0 ? this.reflectionClasses.get(0) : null;
}
}

@ -1,11 +1,12 @@
package io.github.znetworkw.znpcservers.reflection.types;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import io.github.znetworkw.znpcservers.reflection.ReflectionLazyLoader;
import io.github.znetworkw.znpcservers.reflection.ReflectionBuilder;
import io.github.znetworkw.znpcservers.reflection.ReflectionLazyLoader;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.function.Consumer;
public class ConstructorReflection extends ReflectionLazyLoader<Constructor<?>> {
private final ImmutableList<Class<?>[]> parameterTypes;
@ -16,13 +17,28 @@ public class ConstructorReflection extends ReflectionLazyLoader<Constructor<?>>
}
protected Constructor<?> load() throws NoSuchMethodException {
Constructor<?> constructor = null;
if (Iterables.size(parameterTypes) > 1) {
for (Class<?>[] keyParameters : parameterTypes) try {
constructor = this.reflectionClass.getDeclaredConstructor(keyParameters);
} catch (NoSuchMethodException ignored) {}
} else constructor = (Iterables.size(parameterTypes) > 0) ? this.reflectionClass.getDeclaredConstructor(Iterables.get(parameterTypes, 0)) : this.reflectionClass.getDeclaredConstructor();
if (constructor != null) constructor.setAccessible(true);
return constructor;
for (Class<?> clazz : this.reflectionClasses) {
Constructor<?> constructor = load(clazz);
if (constructor != null) return constructor;
}
return null;
}
private Constructor<?> load(Class<?> clazz) {
if (parameterTypes != null && parameterTypes.size() > 0) for (Class<?>[] possibleConstructor : parameterTypes) try {
Constructor<?> constructor = clazz.getDeclaredConstructor(possibleConstructor);
constructor.setAccessible(true);
return constructor;
} catch (NoSuchMethodException ignored) {}
else try {
return clazz.getDeclaredConstructor();
} catch (NoSuchMethodException ignored) {}
return null;
}
@Override
protected void printDebugInfo(Consumer<String> logger) {
logger.accept("Possible Parameter Type Combinations:");
for (Class<?>[] possible : parameterTypes) logger.accept(Arrays.toString(possible));
}
}

@ -1,8 +1,8 @@
package io.github.znetworkw.znpcservers.reflection.types;
import io.github.znetworkw.znpcservers.reflection.ReflectionLazyLoader;
import io.github.znetworkw.znpcservers.reflection.EnumPropertyCache;
import io.github.znetworkw.znpcservers.reflection.ReflectionBuilder;
import io.github.znetworkw.znpcservers.reflection.ReflectionLazyLoader;
public class EnumReflection extends ReflectionLazyLoader<Enum<?>[]> {
public EnumReflection(ReflectionBuilder reflectionBuilder) {
@ -10,8 +10,9 @@ public class EnumReflection extends ReflectionLazyLoader<Enum<?>[]> {
}
protected Enum<?>[] load() {
Enum<?>[] enums = (Enum<?>[]) this.reflectionClass.getEnumConstants();
for (Enum<?> enumConstant : enums) EnumPropertyCache.register(enumConstant.name(), enumConstant, this.reflectionClass);
if (reflectionClasses.size() == 0) return null;
Enum<?>[] enums = (Enum<?>[]) this.reflectionClasses.get(0).getEnumConstants();
for (Enum<?> enumConstant : enums) EnumPropertyCache.register(enumConstant.name(), enumConstant, this.reflectionClasses.get(0));
return enums;
}
}

@ -5,6 +5,7 @@ import io.github.znetworkw.znpcservers.reflection.ReflectionBuilder;
import java.lang.reflect.Field;
import java.util.List;
import java.util.function.Consumer;
public class FieldReflection extends ReflectionLazyLoader<Field> {
private final String fieldName;
@ -17,39 +18,64 @@ public class FieldReflection extends ReflectionLazyLoader<Field> {
}
protected Field load() throws NoSuchFieldException {
if (expectType != null)
for (Field field1 : this.reflectionClass.getDeclaredFields()) {
if (field1.getType() == expectType) {
field1.setAccessible(true);
return field1;
}
}
Field field = this.reflectionClass.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
for (Class<?> clazz : this.reflectionClasses) {
Field field = load(clazz);
if (field != null) return field;
}
return null;
}
public FieldValueReflection staticValueLoader() {
return new FieldValueReflection(this, possibleClassNames, null);
private Field load(Class<?> clazz) {
if (expectType != null) for (Field field : clazz.getDeclaredFields()) if (field.getType() == expectType) {
field.setAccessible(true);
return field;
}
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (NoSuchFieldException ignored) {}
return null;
}
public FieldValueReflection valueLoader(Object obj) {
return new FieldValueReflection(this, possibleClassNames, obj);
@Override
protected void printDebugInfo(Consumer<String> logger) {
logger.accept("Field Name: " + fieldName);
logger.accept("Field Type: " + expectType);
}
private static class FieldValueReflection extends ReflectionLazyLoader<Object> {
public FieldValueReflection<Object> staticValueLoader() {
return staticValueLoader(Object.class);
}
@SuppressWarnings("unused")
public <T> FieldValueReflection<T> staticValueLoader(Class<T> valueType) {
return new FieldValueReflection<>(this, possibleClassNames, null, strict);
}
@SuppressWarnings("unused")
public <T> FieldValueReflection<T> valueLoader(Object obj, Class<T> valueType) {
return new FieldValueReflection<>(this, possibleClassNames, obj, strict);
}
private static class FieldValueReflection<T> extends ReflectionLazyLoader<T> {
private final Object obj;
private final FieldReflection fieldReflection;
public FieldValueReflection(FieldReflection fieldReflection, List<String> className, Object obj) {
super(className);
public FieldValueReflection(FieldReflection fieldReflection, List<String> className, Object obj, boolean strict) {
super(className, strict);
this.obj = obj;
this.fieldReflection = fieldReflection;
}
protected Object load() throws IllegalAccessException, NoSuchFieldException {
Field field = this.fieldReflection.get();
return field.get(obj);
@SuppressWarnings("unchecked")
protected T load() throws IllegalAccessException, NoSuchFieldException, ClassCastException {
return (T) this.fieldReflection.get().get(obj);
}
@Override
protected void printDebugInfo(Consumer<String> logger) {
fieldReflection.printDebugInfo(logger);
}
}
}

@ -1,11 +1,12 @@
package io.github.znetworkw.znpcservers.reflection.types;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import io.github.znetworkw.znpcservers.reflection.ReflectionLazyLoader;
import io.github.znetworkw.znpcservers.reflection.ReflectionBuilder;
import io.github.znetworkw.znpcservers.reflection.ReflectionLazyLoader;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Consumer;
public class MethodReflection extends ReflectionLazyLoader<Method> {
private final ImmutableList<String> methods;
@ -20,17 +21,43 @@ public class MethodReflection extends ReflectionLazyLoader<Method> {
}
protected Method load() {
Method methodThis = null;
boolean hasExpectedType = (expectType != null);
if (methods.isEmpty() && hasExpectedType) for (Method method : this.reflectionClass.getDeclaredMethods()) if (method.getReturnType() == expectType) return method;
for (String methodName : methods) try {
Method maybeGet;
if (!Iterables.isEmpty(parameterTypes)) maybeGet = this.reflectionClass.getDeclaredMethod(methodName, Iterables.get(parameterTypes, 0));
else maybeGet = this.reflectionClass.getDeclaredMethod(methodName);
if (expectType != null && expectType != maybeGet.getReturnType()) continue;
maybeGet.setAccessible(true);
methodThis = maybeGet;
} catch (NoSuchMethodException ignored) {}
return methodThis;
Map<Integer, List<Method>> imperfectMatches = new HashMap<>();
for (Class<?> clazz : this.reflectionClasses) {
Method method = load(clazz, imperfectMatches);
if (method != null) return method;
}
for (int i = 2; i > 0; i--) if (imperfectMatches.containsKey(i)) {
return imperfectMatches.get(i).get(0);
}
return null;
}
private Method load(Class<?> clazz, Map<Integer, List<Method>> imperfectMatches) {
for (Method method : clazz.getDeclaredMethods()) {
int matches = 0;
if (expectType != null) {
if (!method.getReturnType().equals(expectType)) continue;
matches++;
}
if (parameterTypes.size() > 0) out: for (Class<?>[] possible : parameterTypes) {
if (method.getParameterCount() != possible.length) continue;
for (int i = 0; i < possible.length; i++) if (!method.getParameterTypes()[i].equals(possible[i])) continue out;
matches++;
}
if (methods.contains(method.getName())) {
matches++;
}
if (matches == 3) return method;
else imperfectMatches.computeIfAbsent(matches, i -> new ArrayList<>()).add(method);
}
return null;
}
@Override
protected void printDebugInfo(Consumer<String> logger) {
logger.accept("Expected Return Type: " + expectType);
logger.accept("Possible method names: " + methods);
logger.accept("Possible Parameter Type Combinations:");
for (Class<?>[] possible : parameterTypes) logger.accept(Arrays.toString(possible));
}
}