Explorar el Código

Improve type resolution

Lortseam hace 4 años
padre
commit
6fb2a1f749

+ 22 - 32
src/main/java/me/lortseam/completeconfig/data/Entry.java

@@ -1,8 +1,6 @@
 package me.lortseam.completeconfig.data;
 
-import lombok.AccessLevel;
 import lombok.Getter;
-import lombok.RequiredArgsConstructor;
 import me.lortseam.completeconfig.api.ConfigEntry;
 import me.lortseam.completeconfig.api.ConfigEntryContainer;
 import me.lortseam.completeconfig.data.gui.TranslationIdentifier;
@@ -22,12 +20,12 @@ import java.math.BigDecimal;
 import java.util.*;
 import java.util.function.Consumer;
 
-public class Entry<T> implements EntryAccessor<T>, DataPart {
+public class Entry<T> extends EntryBase<T> implements DataPart {
 
     private static final Logger LOGGER = LogManager.getLogger();
-    private static final Map<Field, EntryAccessor> ENTRIES = new HashMap<>();
+    private static final Map<Field, EntryBase> ENTRIES = new HashMap<>();
 
-    static EntryAccessor<?> of(String fieldName, Class<? extends ConfigEntryContainer> parentClass) {
+    static EntryBase<?> of(String fieldName, Class<? extends ConfigEntryContainer> parentClass) {
         try {
             return of(parentClass.getDeclaredField(fieldName));
         } catch (NoSuchFieldException e) {
@@ -35,14 +33,10 @@ public class Entry<T> implements EntryAccessor<T>, DataPart {
         }
     }
 
-    static EntryAccessor<?> of(Field field) {
+    static EntryBase<?> of(Field field) {
         return ENTRIES.computeIfAbsent(field, absentField -> new Draft<>(field));
     }
 
-    @Getter
-    private final Field field;
-    @Getter
-    private final Class<T> type;
     private final ConfigEntryContainer parentObject;
     private String customID;
     @Getter
@@ -56,9 +50,8 @@ public class Entry<T> implements EntryAccessor<T>, DataPart {
     private final Extras<T> extras = new Extras<>(this);
     private final List<Listener<T>> listeners = new ArrayList<>();
 
-    private Entry(Field field, Class<T> type, ConfigEntryContainer parentObject, TranslationIdentifier parentTranslation) {
-        this.field = field;
-        this.type = type;
+    private Entry(Field field, ConfigEntryContainer parentObject, TranslationIdentifier parentTranslation) {
+        super(field);
         this.parentObject = parentObject;
         defaultValue = getValue();
         this.parentTranslation = parentTranslation;
@@ -163,11 +156,6 @@ public class Entry<T> implements EntryAccessor<T>, DataPart {
         return requiresRestart;
     }
 
-    @Override
-    public void connect(Consumer<Entry<T>> modifier) {
-        modifier.accept(this);
-    }
-
     void resolve(Field field) {
         if (field.isAnnotationPresent(ConfigEntry.class)) {
             ConfigEntry annotation = field.getDeclaredAnnotation(ConfigEntry.class);
@@ -231,7 +219,7 @@ public class Entry<T> implements EntryAccessor<T>, DataPart {
     @Override
     public void apply(CommentedConfigurationNode node) {
         try {
-            setValue(node.get(type));
+            setValue((T) node.get(type));
         } catch (SerializationException e) {
             //TODO
             e.printStackTrace();
@@ -248,34 +236,36 @@ public class Entry<T> implements EntryAccessor<T>, DataPart {
         }
     }
 
-    @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
-    static class Draft<T> implements EntryAccessor<T> {
+    @Override
+    void interact(Consumer<Entry<T>> interaction) {
+        interaction.accept(this);
+    }
+
+    static class Draft<T> extends EntryBase<T> {
 
         static <T> Draft<T> of(Field field) {
-            EntryAccessor<T> accessor = (EntryAccessor<T>) Entry.of(field);
+            EntryBase<T> accessor = (EntryBase<T>) Entry.of(field);
             if (!(accessor instanceof Draft)) {
                 throw new UnsupportedOperationException("Entry draft of " + field + " was already built");
             }
             return (Draft<T>) accessor;
         }
 
-        private final Field field;
-        private final List<Consumer<Entry<T>>> modifiers = new ArrayList<>();
+        private final List<Consumer<Entry<T>>> interactions = new ArrayList<>();
 
-        @Override
-        public Class<T> getType() {
-            return (Class<T>) field.getType();
+        private Draft(Field field) {
+            super(field);
         }
 
         @Override
-        public void connect(Consumer<Entry<T>> modifier) {
-            modifiers.add(modifier);
+        void interact(Consumer<Entry<T>> interaction) {
+            interactions.add(interaction);
         }
 
         Entry<T> build(ConfigEntryContainer parentObject, TranslationIdentifier parentTranslation) {
-            Entry<T> entry = new Entry<>(field, getType(), parentObject, parentTranslation);
-            for (Consumer<Entry<T>> modifier : modifiers) {
-                modifier.accept(entry);
+            Entry<T> entry = new Entry<>(field, parentObject, parentTranslation);
+            for (Consumer<Entry<T>> interaction : interactions) {
+                interaction.accept(entry);
             }
             ENTRIES.put(field, entry);
             return entry;

+ 0 - 11
src/main/java/me/lortseam/completeconfig/data/EntryAccessor.java

@@ -1,11 +0,0 @@
-package me.lortseam.completeconfig.data;
-
-import java.util.function.Consumer;
-
-interface EntryAccessor<T> {
-
-    Class<T> getType();
-
-    void connect(Consumer<Entry<T>> modifier);
-
-}

+ 27 - 0
src/main/java/me/lortseam/completeconfig/data/EntryBase.java

@@ -0,0 +1,27 @@
+package me.lortseam.completeconfig.data;
+
+import lombok.Getter;
+import me.lortseam.completeconfig.util.TypeUtils;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.function.Consumer;
+
+abstract class EntryBase<T> {
+
+    @Getter
+    protected final Field field;
+    @Getter
+    protected final Type type;
+    @Getter
+    private final Class<T> typeClass;
+
+    protected EntryBase(Field field) {
+        this.field = field;
+        type = TypeUtils.getFieldType(field);
+        typeClass = (Class<T>) TypeUtils.getTypeClass(type);
+    }
+
+    abstract void interact(Consumer<Entry<T>> interaction);
+
+}

+ 3 - 3
src/main/java/me/lortseam/completeconfig/data/EntryMap.java

@@ -39,8 +39,8 @@ public class EntryMap extends ConfigMap<Entry> {
                 if (method.getParameterCount() != 1) {
                     throw new IllegalArgumentException("Listener method " + method + " has wrong number of parameters");
                 }
-                EntryAccessor<?> accessor = Entry.of(fieldName, fieldClass);
-                if (method.getParameterTypes()[0] != accessor.getType()) {
+                EntryBase<?> entry = Entry.of(fieldName, fieldClass);
+                if (!method.getParameterTypes()[0].equals(entry.getType())) {
                     throw new IllegalArgumentException("Listener method " + method + " has wrong argument type");
                 }
                 if (method.getReturnType() != Void.TYPE) {
@@ -49,7 +49,7 @@ public class EntryMap extends ConfigMap<Entry> {
                 if (!method.isAccessible()) {
                     method.setAccessible(true);
                 }
-                accessor.connect(entry -> entry.addListener(method, container));
+                entry.interact(e -> e.addListener(method, container));
             });
             List<Entry> clazzEntries = new ArrayList<>();
             Arrays.stream(clazz.getDeclaredFields()).filter(field -> {

+ 2 - 2
src/main/java/me/lortseam/completeconfig/data/Extras.java

@@ -3,7 +3,7 @@ package me.lortseam.completeconfig.data;
 import lombok.AccessLevel;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
-import org.apache.commons.lang3.ClassUtils;
+import org.apache.commons.lang3.reflect.TypeUtils;
 
 @RequiredArgsConstructor(access = AccessLevel.PACKAGE)
 public class Extras<T> {
@@ -15,7 +15,7 @@ public class Extras<T> {
     private EnumOptions enumOptions;
 
     <N extends Number> void setBounds(N min, N max, boolean slider) {
-        if (!ClassUtils.isAssignable(entry.getType(), min.getClass()) || !ClassUtils.isAssignable(entry.getType(), max.getClass())) {
+        if (!TypeUtils.isAssignable(entry.getType(), min.getClass()) || !TypeUtils.isAssignable(entry.getType(), max.getClass())) {
             throw new IllegalArgumentException();
         }
         bounds = new Bounds<>((T) min, (T) max, slider);

+ 18 - 28
src/main/java/me/lortseam/completeconfig/gui/cloth/GuiRegistry.java

@@ -2,8 +2,10 @@ package me.lortseam.completeconfig.gui.cloth;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.MoreCollectors;
+import io.leangen.geantyref.TypeToken;
 import me.lortseam.completeconfig.data.Entry;
 import me.lortseam.completeconfig.data.EnumOptions;
+import me.lortseam.completeconfig.util.TypeUtils;
 import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
 import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
 import me.shedaniel.clothconfig2.impl.builders.DropdownMenuBuilder;
@@ -12,7 +14,6 @@ import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import org.apache.commons.lang3.ArrayUtils;
 
-import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -35,24 +36,23 @@ public class GuiRegistry {
         registerDefaultProviders();
     }
 
-    public <T> void registerProvider(GuiProvider<T> provider, GuiProviderPredicate<T> predicate, Class... types) {
+    public <T> void registerProvider(GuiProvider<T> provider, GuiProviderPredicate<T> predicate, Type... types) {
         registrations.add(new GuiProviderRegistration<>(predicate.and((field, extras) -> {
             if (types.length == 0) {
                 return true;
             }
-            Type fieldType = field.getGenericType();
-            return ArrayUtils.contains(types, fieldType instanceof ParameterizedType ? ((ParameterizedType) fieldType).getRawType() : fieldType);
+            return ArrayUtils.contains(types, TypeUtils.getFieldType(field));
         }), provider));
     }
 
-    public void registerProvider(GuiProvider<?> provider, Class... types) {
+    public void registerProvider(GuiProvider<?> provider, Type... types) {
         if (types.length == 0) {
             throw new IllegalArgumentException("Types must not be empty");
         }
         registerProvider(provider, (field, extras) -> true, types);
     }
 
-    private void registerBoundedProvider(GuiProvider<?> provider, boolean slider, Class... types) {
+    private void registerBoundedProvider(GuiProvider<?> provider, boolean slider, Type... types) {
         registerProvider(provider, (field, extras) -> extras.getBounds() != null && extras.getBounds().isSlider() == slider, types);
     }
 
@@ -60,16 +60,6 @@ public class GuiRegistry {
         registerProvider(provider, (field, extras) -> Enum.class.isAssignableFrom(field.getType()) && extras.getEnumOptions().getDisplayType() == enumDisplayType);
     }
 
-    public <T> void registerGenericProvider(GuiProvider<T> provider, Class<?> type, Class... genericTypes) {
-        registerProvider(provider, (field, extras) -> {
-            Type fieldType = field.getGenericType();
-            if (!(fieldType instanceof ParameterizedType)) {
-                return false;
-            }
-            return Arrays.equals(((ParameterizedType) fieldType).getActualTypeArguments(), genericTypes);
-        }, type);
-    }
-
     private void registerDefaultProviders() {
        registerProvider((GuiProvider<Boolean>) entry -> build(
                builder -> builder
@@ -177,7 +167,7 @@ public class GuiRegistry {
        ), String.class);
        registerEnumProvider((GuiProvider<? extends Enum<?>>) entry -> build(
                builder -> builder
-                       .startEnumSelector(entry.getText(), entry.getType(), entry.getValue())
+                       .startEnumSelector(entry.getText(), entry.getTypeClass(), entry.getValue())
                        .setDefaultValue(entry.getDefaultValue())
                        .setTooltip(entry.getTooltip())
                        .setEnumNameProvider(entry.getExtras().getEnumOptions().getNameProvider())
@@ -185,7 +175,7 @@ public class GuiRegistry {
                entry.requiresRestart()
        ), EnumOptions.DisplayType.BUTTON);
        registerEnumProvider((GuiProvider<? extends Enum>) entry -> {
-           List<Enum> enumValues = Arrays.asList(((Class<? extends Enum>) entry.getType()).getEnumConstants());
+           List<Enum> enumValues = Arrays.asList(((Class<? extends Enum>) entry.getTypeClass()).getEnumConstants());
            return build(
                    builder -> builder
                            .startDropdownMenu(entry.getText(), DropdownMenuBuilder.TopCellElementBuilder.of(
@@ -199,46 +189,46 @@ public class GuiRegistry {
                    entry.requiresRestart()
            );
        }, EnumOptions.DisplayType.DROPDOWN);
-       registerGenericProvider((GuiProvider<List<Integer>>) entry -> build(
+       registerProvider((GuiProvider<List<Integer>>) entry -> build(
                builder -> builder
                        .startIntList(entry.getText(), entry.getValue())
                        .setDefaultValue(entry.getDefaultValue())
                        .setTooltip(entry.getTooltip())
                        .setSaveConsumer(entry::setValue),
                entry.requiresRestart()
-       ), List.class, Integer.class);
-       registerGenericProvider((GuiProvider<List<Long>>) entry -> build(
+       ), new TypeToken<List<Integer>>() {}.getType());
+       registerProvider((GuiProvider<List<Long>>) entry -> build(
                builder -> builder
                        .startLongList(entry.getText(), entry.getValue())
                        .setDefaultValue(entry.getDefaultValue())
                        .setTooltip(entry.getTooltip())
                        .setSaveConsumer(entry::setValue),
                entry.requiresRestart()
-       ), List.class, Long.class);
-       registerGenericProvider((GuiProvider<List<Float>>) entry -> build(
+       ), new TypeToken<List<Long>>() {}.getType());
+       registerProvider((GuiProvider<List<Float>>) entry -> build(
                builder -> builder
                        .startFloatList(entry.getText(), entry.getValue())
                        .setDefaultValue(entry.getDefaultValue())
                        .setTooltip(entry.getTooltip())
                        .setSaveConsumer(entry::setValue),
                entry.requiresRestart()
-       ), List.class, Float.class);
-       registerGenericProvider((GuiProvider<List<Double>>) entry -> build(
+       ), new TypeToken<List<Float>>() {}.getType());
+       registerProvider((GuiProvider<List<Double>>) entry -> build(
                builder -> builder
                        .startDoubleList(entry.getText(), entry.getValue())
                        .setDefaultValue(entry.getDefaultValue())
                        .setTooltip(entry.getTooltip())
                        .setSaveConsumer(entry::setValue),
                entry.requiresRestart()
-       ), List.class, Double.class);
-       registerGenericProvider((GuiProvider<List<String>>) entry -> build(
+       ), new TypeToken<List<Double>>() {}.getType());
+       registerProvider((GuiProvider<List<String>>) entry -> build(
                builder -> builder
                        .startStrList(entry.getText(), entry.getValue())
                        .setDefaultValue(entry.getDefaultValue())
                        .setTooltip(entry.getTooltip())
                        .setSaveConsumer(entry::setValue),
                entry.requiresRestart()
-       ), List.class, String.class);
+       ), new TypeToken<List<String>>() {}.getType());
     }
 
     <T> Optional<GuiProvider<T>> getProvider(Entry<T> entry) {

+ 19 - 0
src/main/java/me/lortseam/completeconfig/util/TypeUtils.java

@@ -0,0 +1,19 @@
+package me.lortseam.completeconfig.util;
+
+import com.google.common.reflect.TypeToken;
+import io.leangen.geantyref.GenericTypeReflector;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+
+public final class TypeUtils {
+
+    public static Type getFieldType(Field field) {
+        return GenericTypeReflector.getExactFieldType(field, field.getDeclaringClass());
+    }
+
+    public static Class<?> getTypeClass(Type type) {
+        return TypeToken.of(type).getRawType();
+    }
+
+}