Procházet zdrojové kódy

GSON -> Configurate refactor

Lortseam před 4 roky
rodič
revize
46c9e9da2a
26 změnil soubory, kde provedl 411 přidání a 474 odebrání
  1. 13 6
      build.gradle
  2. 2 1
      gradle.properties
  3. binární
      gradle/wrapper/gradle-wrapper.jar
  4. 1 1
      gradle/wrapper/gradle-wrapper.properties
  5. 2 0
      gradlew
  6. 4 18
      gradlew.bat
  7. 6 19
      src/main/java/me/lortseam/completeconfig/Config.java
  8. 33 44
      src/main/java/me/lortseam/completeconfig/ConfigHandler.java
  9. 27 21
      src/main/java/me/lortseam/completeconfig/data/Collection.java
  10. 24 7
      src/main/java/me/lortseam/completeconfig/data/CollectionMap.java
  11. 2 1
      src/main/java/me/lortseam/completeconfig/data/ConfigMap.java
  12. 13 0
      src/main/java/me/lortseam/completeconfig/data/DataPart.java
  13. 164 78
      src/main/java/me/lortseam/completeconfig/data/Entry.java
  14. 11 0
      src/main/java/me/lortseam/completeconfig/data/EntryAccessor.java
  15. 26 69
      src/main/java/me/lortseam/completeconfig/data/EntryMap.java
  16. 3 8
      src/main/java/me/lortseam/completeconfig/data/EnumOptions.java
  17. 26 0
      src/main/java/me/lortseam/completeconfig/data/Listener.java
  18. 51 0
      src/main/java/me/lortseam/completeconfig/data/gui/TranslationIdentifier.java
  19. 1 2
      src/main/java/me/lortseam/completeconfig/gui/cloth/ClothGuiBuilder.java
  20. 2 2
      src/main/java/me/lortseam/completeconfig/gui/cloth/GuiRegistry.java
  21. 0 32
      src/main/java/me/lortseam/completeconfig/serialization/CollectionDeserializer.java
  22. 0 53
      src/main/java/me/lortseam/completeconfig/serialization/CollectionMapDeserializer.java
  23. 0 21
      src/main/java/me/lortseam/completeconfig/serialization/CollectionSerializer.java
  24. 0 36
      src/main/java/me/lortseam/completeconfig/serialization/EntryDeserializer.java
  25. 0 36
      src/main/java/me/lortseam/completeconfig/serialization/EntryMapDeserializer.java
  26. 0 19
      src/main/java/me/lortseam/completeconfig/serialization/EntrySerializer.java

+ 13 - 6
build.gradle

@@ -10,17 +10,24 @@ archivesBaseName = project.archives_base_name
 version = project.mod_version
 group = project.maven_group
 
+repositories {
+	jcenter()
+}
+
 dependencies {
-	minecraft "com.mojang:minecraft:${project.minecraft_version}"
-	mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
-	modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
+	minecraft("com.mojang:minecraft:${project.minecraft_version}")
+	mappings("net.fabricmc:yarn:${project.yarn_mappings}:v2")
+	modImplementation("net.fabricmc:fabric-loader:${project.loader_version}")
 
-	modImplementation("me.shedaniel.cloth:config-2:${project.cloth_config_version}") {
+	modApi("me.shedaniel.cloth:config-2:${project.cloth_config_version}") {
 		exclude(group: "net.fabricmc.fabric-api")
 	}
 
-	compileOnly "org.projectlombok:lombok:${project.lombok_version}"
-	annotationProcessor "org.projectlombok:lombok:${project.lombok_version}"
+	// Using modImplementation because implementation does not include dependency inside Maven pom file
+	modImplementation("org.spongepowered:configurate-hocon:${project.configurate_version}")
+
+	compileOnly("org.projectlombok:lombok:${project.lombok_version}")
+	annotationProcessor("org.projectlombok:lombok:${project.lombok_version}")
 }
 
 processResources {

+ 2 - 1
gradle.properties

@@ -13,4 +13,5 @@ org.gradle.jvmargs=-Xmx1G
 
 # Dependencies
 	cloth_config_version=4.8.3
-	lombok_version=1.18.12
+	lombok_version=1.18.12
+	configurate_version=4.0.0

binární
gradle/wrapper/gradle-wrapper.jar


+ 1 - 1
gradle/wrapper/gradle-wrapper.properties

@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists

+ 2 - 0
gradlew

@@ -82,6 +82,7 @@ esac
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 
+
 # Determine the Java command to use to start the JVM.
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -129,6 +130,7 @@ fi
 if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
     APP_HOME=`cygpath --path --mixed "$APP_HOME"`
     CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
     JAVACMD=`cygpath --unix "$JAVACMD"`
 
     # We build the pattern for arguments to be converted via cygpath

+ 4 - 18
gradlew.bat

@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
 
 set JAVA_EXE=java.exe
 %JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto init
+if "%ERRORLEVEL%" == "0" goto execute
 
 echo.
 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +54,7 @@ goto fail
 set JAVA_HOME=%JAVA_HOME:"=%
 set JAVA_EXE=%JAVA_HOME%/bin/java.exe
 
-if exist "%JAVA_EXE%" goto init
+if exist "%JAVA_EXE%" goto execute
 
 echo.
 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,28 +64,14 @@ echo location of your Java installation.
 
 goto fail
 
-:init
-@rem Get command-line arguments, handling Windows variants
-
-if not "%OS%" == "Windows_NT" goto win9xME_args
-
-:win9xME_args
-@rem Slurp the command line arguments.
-set CMD_LINE_ARGS=
-set _SKIP=2
-
-:win9xME_args_slurp
-if "x%~1" == "x" goto execute
-
-set CMD_LINE_ARGS=%*
-
 :execute
 @rem Setup the command line
 
 set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
 
+
 @rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
 
 :end
 @rem End local scope for the variables with windows NT shell

+ 6 - 19
src/main/java/me/lortseam/completeconfig/Config.java

@@ -1,11 +1,8 @@
 package me.lortseam.completeconfig;
 
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonSyntaxException;
 import me.lortseam.completeconfig.api.ConfigGroup;
 import me.lortseam.completeconfig.data.CollectionMap;
-import me.lortseam.completeconfig.serialization.CollectionMapDeserializer;
+import me.lortseam.completeconfig.data.gui.TranslationIdentifier;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -15,25 +12,15 @@ public class Config extends CollectionMap {
 
     private static final Logger LOGGER = LogManager.getLogger();
 
-    Config(String modID, List<ConfigGroup> topLevelGroups, JsonElement json) {
-        super("config." + modID);
+    Config(String modID, List<ConfigGroup> topLevelGroups) {
+        super(new TranslationIdentifier(modID));
         for (ConfigGroup group : topLevelGroups) {
-            if (!fill(modTranslationKey, group)) {
-                continue;
-            }
-            try {
-                new GsonBuilder()
-                        .registerTypeAdapter(CollectionMapDeserializer.TYPE, new CollectionMapDeserializer(this, group.getConfigGroupID()))
-                        .create()
-                        .fromJson(json, CollectionMapDeserializer.TYPE);
-            } catch (JsonSyntaxException e) {
-                LOGGER.warn("[CompleteConfig] An error occurred while trying to load the config for group " + group.getClass());
-            }
+            resolve(group);
         }
     }
 
-    public String getModTranslationKey() {
-        return modTranslationKey;
+    public TranslationIdentifier getTranslation() {
+        return translation;
     }
 
 }

+ 33 - 44
src/main/java/me/lortseam/completeconfig/ConfigHandler.java

@@ -1,11 +1,8 @@
 package me.lortseam.completeconfig;
 
-import com.google.gson.*;
 import me.lortseam.completeconfig.api.ConfigGroup;
 import me.lortseam.completeconfig.api.ConfigOwner;
 import me.lortseam.completeconfig.gui.GuiBuilder;
-import me.lortseam.completeconfig.serialization.CollectionSerializer;
-import me.lortseam.completeconfig.serialization.EntrySerializer;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.fabricmc.loader.api.FabricLoader;
@@ -13,23 +10,16 @@ import net.minecraft.client.gui.screen.Screen;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.spongepowered.configurate.CommentedConfigurationNode;
+import org.spongepowered.configurate.ConfigurateException;
+import org.spongepowered.configurate.hocon.HoconConfigurationLoader;
 
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.Writer;
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.*;
 
 public final class ConfigHandler {
 
-    private static final Gson GSON = new GsonBuilder()
-            .registerTypeAdapter(CollectionSerializer.TYPE, new CollectionSerializer())
-            .registerTypeAdapter(EntrySerializer.TYPE, new EntrySerializer())
-            .setPrettyPrinting()
-            .create();
     private static final Logger LOGGER = LogManager.getLogger();
     private static final Map<Class<? extends ConfigOwner>, ConfigHandler> HANDLERS = new HashMap<>();
 
@@ -50,12 +40,13 @@ public final class ConfigHandler {
             return null;
         }
         String[] subPath = ArrayUtils.add(branch, 0, modID);
-        subPath[subPath.length - 1] = subPath[subPath.length - 1] + ".json";
-        Path jsonPath = Paths.get(FabricLoader.getInstance().getConfigDir().toString(), subPath);
-        if (HANDLERS.values().stream().anyMatch(handler -> handler.jsonPath.equals(jsonPath))) {
+        subPath[subPath.length - 1] = subPath[subPath.length - 1] + ".conf";
+        Path filePath = Paths.get(FabricLoader.getInstance().getConfigDir().toString(), subPath);
+        //TODO: filePath field was removed
+        /*if (HANDLERS.values().stream().anyMatch(handler -> handler.filePath.equals(filePath))) {
             throw new IllegalArgumentException("A config of the mod " + modID + " with the specified branch " + Arrays.toString(branch) + " already exists!");
-        }
-        ConfigHandler handler = new ConfigHandler(modID, jsonPath, topLevelGroups, guiBuilder);
+        }*/
+        ConfigHandler handler = new ConfigHandler(modID, filePath, topLevelGroups, guiBuilder);
         HANDLERS.put(owner, handler);
         return handler;
     }
@@ -70,27 +61,30 @@ public final class ConfigHandler {
         return Optional.ofNullable(HANDLERS.get(owner));
     }
 
-    private final Path jsonPath;
+    private final HoconConfigurationLoader loader;
     private final Config config;
     private GuiBuilder guiBuilder;
 
-    private ConfigHandler(String modID, Path jsonPath, List<ConfigGroup> topLevelGroups, GuiBuilder guiBuilder) {
-        this.jsonPath = jsonPath;
-        config = new Config(modID, topLevelGroups, load());
+    private ConfigHandler(String modID, Path filePath, List<ConfigGroup> topLevelGroups, GuiBuilder guiBuilder) {
+        loader = HoconConfigurationLoader.builder()
+                .path(filePath)
+                .build();
+        config = new Config(modID, topLevelGroups);
+        CommentedConfigurationNode root = load();
+        if (!root.virtual()) {
+            config.apply(root);
+        }
         this.guiBuilder = guiBuilder;
     }
 
-    private JsonElement load() {
-        if(Files.exists(jsonPath)) {
-            try {
-                return GSON.fromJson(new FileReader(jsonPath.toString()), JsonElement.class);
-            } catch (FileNotFoundException e) {
-                throw new RuntimeException(e);
-            } catch (JsonSyntaxException e) {
-                LOGGER.warn("[CompleteConfig] An error occurred while trying to load the config " + jsonPath.toString());
-            }
+    private CommentedConfigurationNode load() {
+        try {
+            return loader.load();
+        } catch (ConfigurateException e) {
+            //TODO
+            e.printStackTrace();
         }
-        return JsonNull.INSTANCE;
+        return CommentedConfigurationNode.root();
     }
 
     /**
@@ -115,18 +109,13 @@ public final class ConfigHandler {
      * Saves the config to a save file.
      */
     public void save() {
-        if (!Files.exists(jsonPath)) {
-            try {
-                Files.createDirectories(jsonPath.getParent());
-                Files.createFile(jsonPath);
-            } catch (IOException e) {
-                throw new RuntimeException(e);
-            }
-        }
-        try(Writer writer = Files.newBufferedWriter(jsonPath)) {
-            GSON.toJson(config, writer);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
+        CommentedConfigurationNode root = CommentedConfigurationNode.root();
+        config.fetch(root);
+        try {
+            loader.save(root);
+        } catch (ConfigurateException e) {
+            //TODO
+            e.printStackTrace();
         }
     }
 

+ 27 - 21
src/main/java/me/lortseam/completeconfig/data/Collection.java

@@ -1,12 +1,12 @@
 package me.lortseam.completeconfig.data;
 
-import lombok.AccessLevel;
 import lombok.Getter;
-import me.lortseam.completeconfig.api.ConfigGroup;
 import me.lortseam.completeconfig.api.ConfigEntryContainer;
+import me.lortseam.completeconfig.api.ConfigGroup;
+import me.lortseam.completeconfig.data.gui.TranslationIdentifier;
 import me.lortseam.completeconfig.exception.IllegalAnnotationTargetException;
 import net.minecraft.text.Text;
-import net.minecraft.text.TranslatableText;
+import org.spongepowered.configurate.CommentedConfigurationNode;
 
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -14,33 +14,27 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 
-public class Collection {
+public class Collection implements DataPart<ConfigEntryContainer> {
 
-    @Getter(AccessLevel.PACKAGE)
-    private final String translationKey;
+    private final TranslationIdentifier translation;
     @Getter
     private final EntryMap entries;
     @Getter
     private final CollectionMap collections;
 
-    Collection(String modTranslationKey, String parentTranslationKey, ConfigGroup group) {
-        String groupID = group.getConfigGroupID();
-        if (parentTranslationKey == null) {
-            translationKey = groupID;
-        } else {
-            translationKey = parentTranslationKey + "." + groupID;
-        }
-        entries = new EntryMap(modTranslationKey);
-        collections = new CollectionMap(modTranslationKey);
-        fill(group);
+    Collection(TranslationIdentifier translation) {
+        this.translation = translation;
+        entries = new EntryMap(translation);
+        collections = new CollectionMap(translation);
     }
 
     public Text getText() {
-        return new TranslatableText(translationKey);
+        return translation.translate();
     }
 
-    private void fill(ConfigEntryContainer container) {
-        entries.fill(this, container);
+    @Override
+    public void resolve(ConfigEntryContainer container) {
+        entries.resolve(container);
         List<ConfigEntryContainer> containers = new ArrayList<>();
         for (Class<? extends ConfigEntryContainer> clazz : container.getConfigClasses()) {
             containers.addAll(Arrays.stream(clazz.getDeclaredFields()).filter(field -> {
@@ -71,11 +65,23 @@ public class Collection {
         containers.addAll(Arrays.asList(container.getTransitiveConfigEntryContainers()));
         for (ConfigEntryContainer c : containers) {
             if (c instanceof ConfigGroup) {
-                collections.fill(translationKey, (ConfigGroup) c);
+                collections.resolve((ConfigGroup) c);
             } else {
-                fill(c);
+                resolve(c);
             }
         }
     }
 
+    @Override
+    public void apply(CommentedConfigurationNode node) {
+        entries.apply(node);
+        collections.apply(node);
+    }
+
+    @Override
+    public void fetch(CommentedConfigurationNode node) {
+        entries.fetch(node);
+        collections.fetch(node);
+    }
+
 }

+ 24 - 7
src/main/java/me/lortseam/completeconfig/data/CollectionMap.java

@@ -1,26 +1,43 @@
 package me.lortseam.completeconfig.data;
 
 import me.lortseam.completeconfig.api.ConfigGroup;
+import me.lortseam.completeconfig.data.gui.TranslationIdentifier;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.spongepowered.configurate.CommentedConfigurationNode;
 
-public class CollectionMap extends ConfigMap<Collection> {
+public class CollectionMap extends ConfigMap<Collection> implements DataPart<ConfigGroup> {
 
     private static final Logger LOGGER = LogManager.getLogger();
 
-    protected CollectionMap(String modTranslationKey) {
-        super(modTranslationKey);
+    protected CollectionMap(TranslationIdentifier translation) {
+        super(translation);
     }
 
-    protected boolean fill(String parentTranslationKey, ConfigGroup group) {
+    @Override
+    public void resolve(ConfigGroup group) {
         String groupID = group.getConfigGroupID();
-        Collection collection = new Collection(modTranslationKey, parentTranslationKey, group);
+        Collection collection = new Collection(translation.append(groupID));
+        collection.resolve(group);
         if (collection.getEntries().isEmpty() && collection.getCollections().isEmpty()) {
             LOGGER.warn("[CompleteConfig] Group " + groupID + " is empty!");
-            return false;
+            return;
         }
         putUnique(groupID, collection);
-        return true;
+    }
+
+    @Override
+    public void apply(CommentedConfigurationNode node) {
+        forEach((id, collection) -> {
+            CommentedConfigurationNode collectionNode = node.node(id);
+            if(collectionNode.virtual()) return;
+            collection.apply(collectionNode);
+        });
+    }
+
+    @Override
+    public void fetch(CommentedConfigurationNode node) {
+        forEach((id, collection) -> collection.fetch(node.node(id)));
     }
 
 }

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

@@ -2,6 +2,7 @@ package me.lortseam.completeconfig.data;
 
 import lombok.AccessLevel;
 import lombok.RequiredArgsConstructor;
+import me.lortseam.completeconfig.data.gui.TranslationIdentifier;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.LinkedHashMap;
@@ -9,7 +10,7 @@ import java.util.LinkedHashMap;
 @RequiredArgsConstructor(access = AccessLevel.PROTECTED)
 public abstract class ConfigMap<T> extends LinkedHashMap<String, T> {
 
-    protected final String modTranslationKey;
+    protected final TranslationIdentifier translation;
 
     void putUnique(String id, T value) {
         if (StringUtils.isBlank(id)) {

+ 13 - 0
src/main/java/me/lortseam/completeconfig/data/DataPart.java

@@ -0,0 +1,13 @@
+package me.lortseam.completeconfig.data;
+
+import org.spongepowered.configurate.CommentedConfigurationNode;
+
+interface DataPart<T> {
+
+    void resolve(T t);
+
+    void apply(CommentedConfigurationNode node);
+
+    void fetch(CommentedConfigurationNode node);
+
+}

+ 164 - 78
src/main/java/me/lortseam/completeconfig/data/Entry.java

@@ -1,82 +1,66 @@
 package me.lortseam.completeconfig.data;
 
-import com.google.common.collect.MoreCollectors;
 import lombok.AccessLevel;
-import lombok.AllArgsConstructor;
 import lombok.Getter;
-import lombok.Setter;
+import lombok.RequiredArgsConstructor;
+import me.lortseam.completeconfig.api.ConfigEntry;
 import me.lortseam.completeconfig.api.ConfigEntryContainer;
-import net.minecraft.client.resource.language.I18n;
+import me.lortseam.completeconfig.data.gui.TranslationIdentifier;
+import me.lortseam.completeconfig.exception.IllegalAnnotationParameterException;
+import me.lortseam.completeconfig.exception.IllegalAnnotationTargetException;
 import net.minecraft.text.Text;
-import net.minecraft.text.TranslatableText;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.spongepowered.configurate.CommentedConfigurationNode;
+import org.spongepowered.configurate.serialize.SerializationException;
 
 import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.util.*;
+import java.util.function.Consumer;
 
-public class Entry<T> {
+public class Entry<T> implements EntryAccessor<T>, DataPart<Field> {
 
     private static final Logger LOGGER = LogManager.getLogger();
-    private static final Set<Entry> ENTRIES = new HashSet<>();
+    private static final Map<Field, EntryAccessor> ENTRIES = new HashMap<>();
 
-    static Entry<?> of(Collection parent, String fieldName, Class<? extends ConfigEntryContainer> parentClass) {
+    static EntryAccessor<?> of(String fieldName, Class<? extends ConfigEntryContainer> parentClass) {
         try {
-            Field field = parentClass.getDeclaredField(fieldName);
-            if (!field.isAccessible()) {
-                field.setAccessible(true);
-            }
-            return of(parent, field);
+            return of(parentClass.getDeclaredField(fieldName));
         } catch (NoSuchFieldException e) {
             throw new RuntimeException(e);
         }
     }
 
-    private static <T> Entry<T> of(Collection parent, Field field) {
-        return ENTRIES.stream().filter(entry -> entry.field.equals(field)).collect(MoreCollectors.toOptional()).orElseGet(() -> {
-            Entry<T> entry = new Entry<>(parent, field, (Class<T>) field.getType());
-            ENTRIES.add(entry);
-            return entry;
-        });
-    }
-
-    static <T> Entry<T> of(Collection parent, Field field, ConfigEntryContainer parentObject) {
-        Entry<T> entry = of(parent, field);
-        entry.parentObject = parentObject;
-        entry.defaultValue = entry.getValue();
-        return entry;
+    static EntryAccessor<?> of(Field field) {
+        return ENTRIES.computeIfAbsent(field, absentField -> new Draft<>(field));
     }
 
-    @Getter(AccessLevel.PACKAGE)
-    private final Collection parent;
     @Getter
     private final Field field;
-    @Setter(AccessLevel.PACKAGE)
-    private String customID;
     @Getter
     private final Class<T> type;
-    private ConfigEntryContainer parentObject;
-    @Getter
-    private T defaultValue;
-    @Setter(AccessLevel.PACKAGE)
-    private String customTranslationKey;
-    @Setter(AccessLevel.PACKAGE)
-    private String[] customTooltipKeys;
+    private final ConfigEntryContainer parentObject;
+    private String customID;
     @Getter
-    private final Extras<T> extras = new Extras<>(this);
-    private final List<Listener> listeners = new ArrayList<>();
-    @Setter(AccessLevel.PACKAGE)
+    private final T defaultValue;
+    private final TranslationIdentifier parentTranslation;
+    private TranslationIdentifier customTranslation;
+    private TranslationIdentifier[] customTooltipTranslations;
     private boolean forceUpdate;
-    @Setter(AccessLevel.PACKAGE)
     private boolean requiresRestart;
+    @Getter
+    private final Extras<T> extras = new Extras<>(this);
+    private final List<Listener<T>> listeners = new ArrayList<>();
 
-    private Entry(Collection parent, Field field, Class<T> type) {
-        this.parent = parent;
+    private Entry(Field field, Class<T> type, ConfigEntryContainer parentObject, TranslationIdentifier parentTranslation) {
         this.field = field;
         this.type = type;
+        this.parentObject = parentObject;
+        defaultValue = getValue();
+        this.parentTranslation = parentTranslation;
     }
 
     public T getValue() {
@@ -120,81 +104,183 @@ public class Entry<T> {
     }
 
     private void set(T value) {
-        if (listeners.stream().noneMatch(listener -> listener.parentObject == parentObject) || forceUpdate) {
+        if (listeners.stream().noneMatch(listener -> listener.getParentObject() == parentObject) || forceUpdate) {
             try {
                 field.set(parentObject, value);
             } catch (IllegalAccessException e) {
                 throw new RuntimeException(e);
             }
         }
-        for (Listener listener : listeners) {
-            try {
-                listener.method.invoke(listener.parentObject, value);
-            } catch (IllegalAccessException | InvocationTargetException e) {
-                throw new RuntimeException(e);
-            }
+        for (Listener<T> listener : listeners) {
+            listener.invoke(value);
         }
     }
 
     void addListener(Method method, ConfigEntryContainer parentObject) {
-        listeners.add(new Listener(method, parentObject));
+        listeners.add(new Listener<>(method, parentObject));
     }
 
     String getID() {
         return customID != null ? customID : field.getName();
     }
 
-    String getTranslationKey() {
-        return customTranslationKey != null ? customTranslationKey : parent.getTranslationKey() + "." + getID();
+    TranslationIdentifier getTranslation() {
+        return customTranslation != null ? customTranslation : parentTranslation.append(getID());
     }
 
     public Text getText() {
-        return new TranslatableText(getTranslationKey());
+        return getTranslation().translate();
     }
 
     public Optional<Text[]> getTooltip() {
-        String[] keys = null;
-        if (customTooltipKeys != null) {
-            keys = customTooltipKeys;
+        TranslationIdentifier[] translations = null;
+        if (customTooltipTranslations != null) {
+            translations = customTooltipTranslations;
         } else {
-            String defaultTooltipTranslationKey = getTranslationKey() + ".tooltip";
-            if (I18n.hasTranslation(defaultTooltipTranslationKey)) {
-                keys = new String[] {defaultTooltipTranslationKey};
+            TranslationIdentifier defaultTooltipTranslation = getTranslation().append("tooltip");
+            if (defaultTooltipTranslation.exists()) {
+                translations = new TranslationIdentifier[] {defaultTooltipTranslation};
             } else {
-                List<String> defaultTooltipTranslationKeys = new ArrayList<>();
+                List<TranslationIdentifier> defaultTooltipTranslations = new ArrayList<>();
                 for(int i = 0;; i++) {
-                    String key = defaultTooltipTranslationKey + "." + i;
-                    if(I18n.hasTranslation(key)) {
-                        defaultTooltipTranslationKeys.add(key);
+                    TranslationIdentifier key = defaultTooltipTranslation.append(Integer.toString(i));
+                    if(key.exists()) {
+                        defaultTooltipTranslations.add(key);
                     } else {
-                        if (!defaultTooltipTranslationKeys.isEmpty()) {
-                            keys = defaultTooltipTranslationKeys.toArray(new String[0]);
+                        if (!defaultTooltipTranslations.isEmpty()) {
+                            translations = defaultTooltipTranslations.toArray(new TranslationIdentifier[0]);
                         }
                         break;
                     }
                 }
             }
         }
-        return keys != null ? Optional.of(Arrays.stream(keys).map(TranslatableText::new).toArray(Text[]::new)) : Optional.empty();
+        return translations != null ? Optional.of(Arrays.stream(translations).map(TranslationIdentifier::translate).toArray(Text[]::new)) : Optional.empty();
     }
 
-    <N extends Number> void setBounds(N min, N max, boolean slider) {
-        extras.setBounds(min, max, slider);
+    public boolean requiresRestart() {
+        return requiresRestart;
     }
 
-    void setEnumOptions(EnumOptions.DisplayType displayType) {
-        extras.setEnumOptions(displayType);
+    @Override
+    public void connect(Consumer<Entry<T>> modifier) {
+        modifier.accept(this);
     }
 
-    public boolean requiresRestart() {
-        return requiresRestart;
+    @Override
+    public void resolve(Field field) {
+        if (field.isAnnotationPresent(ConfigEntry.class)) {
+            ConfigEntry annotation = field.getDeclaredAnnotation(ConfigEntry.class);
+            String id = annotation.value();
+            if (!StringUtils.isBlank(id)) {
+                customID = id;
+            }
+            String customTranslationKey = annotation.customTranslationKey();
+            if (!StringUtils.isBlank(customTranslationKey)) {
+                customTranslation = parentTranslation.getModTranslation().appendKey(customTranslationKey);
+            }
+            String[] customTooltipKeys = annotation.customTooltipKeys();
+            if (customTooltipKeys.length > 0) {
+                if (Arrays.stream(customTooltipKeys).anyMatch(StringUtils::isBlank)) {
+                    throw new IllegalAnnotationParameterException("Entry tooltip key(s) must not be blank");
+                }
+                customTooltipTranslations = Arrays.stream(customTooltipKeys).map(key -> parentTranslation.getModTranslation().appendKey(key)).toArray(TranslationIdentifier[]::new);
+            }
+            forceUpdate = annotation.forceUpdate();
+            requiresRestart = annotation.requiresRestart();
+        }
+        if (field.isAnnotationPresent(ConfigEntry.Bounded.Integer.class)) {
+            if (field.getType() != int.class && field.getType() != Integer.class) {
+                throw new IllegalAnnotationTargetException("Cannot apply Integer bound to non Integer field " + field);
+            }
+            ConfigEntry.Bounded.Integer bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Integer.class);
+            extras.setBounds(bounds.min(), bounds.max(), bounds.slider());
+        }
+        if (field.isAnnotationPresent(ConfigEntry.Bounded.Long.class)) {
+            if (field.getType() != long.class && field.getType() != Long.class) {
+                throw new IllegalAnnotationTargetException("Cannot apply Long bound to non Long field " + field);
+            }
+            ConfigEntry.Bounded.Long bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Long.class);
+            extras.setBounds(bounds.min(), bounds.max(), bounds.slider());
+        }
+        if (field.isAnnotationPresent(ConfigEntry.Bounded.Float.class)) {
+            if (field.getType() != float.class && field.getType() != Float.class) {
+                throw new IllegalAnnotationTargetException("Cannot apply Float bound to non Float field " + field);
+            }
+            ConfigEntry.Bounded.Float bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Float.class);
+            extras.setBounds(bounds.min(), bounds.max(), false);
+        }
+        if (field.isAnnotationPresent(ConfigEntry.Bounded.Double.class)) {
+            if (field.getType() != double.class && field.getType() != Double.class) {
+                throw new IllegalAnnotationTargetException("Cannot apply Double bound to non Double field " + field);
+            }
+            ConfigEntry.Bounded.Double bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Double.class);
+            extras.setBounds(bounds.min(), bounds.max(), false);
+        }
+        if (Enum.class.isAssignableFrom(field.getType())) {
+            if (field.isAnnotationPresent(ConfigEntry.EnumOptions.class)) {
+                extras.setEnumOptions(field.getDeclaredAnnotation(ConfigEntry.EnumOptions.class).displayType());
+            } else {
+                extras.setEnumOptions(EnumOptions.DisplayType.DEFAULT);
+            }
+        } else if (field.isAnnotationPresent(ConfigEntry.EnumOptions.class)) {
+            throw new IllegalAnnotationTargetException("Cannot apply enum options to non enum field " + field);
+        }
+    }
+
+    @Override
+    public void apply(CommentedConfigurationNode node) {
+        try {
+            setValue(node.get(type));
+        } catch (SerializationException e) {
+            //TODO
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void fetch(CommentedConfigurationNode node) {
+        try {
+            //TODO: Fails when setting enum value
+            node.set(type, getValue());
+        } catch (SerializationException e) {
+            //TODO
+            e.printStackTrace();
+        }
     }
 
-    @AllArgsConstructor
-    private static class Listener {
+    @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
+    static class Draft<T> implements EntryAccessor<T> {
 
-        private final Method method;
-        private final ConfigEntryContainer parentObject;
+        static <T> Draft<T> of(Field field) {
+            EntryAccessor<T> accessor = (EntryAccessor<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<>();
+
+        @Override
+        public Class<T> getType() {
+            return (Class<T>) field.getType();
+        }
+
+        @Override
+        public void connect(Consumer<Entry<T>> modifier) {
+            modifiers.add(modifier);
+        }
+
+        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);
+            }
+            ENTRIES.put(field, entry);
+            return entry;
+        }
 
     }
 

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

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

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

@@ -4,24 +4,25 @@ import com.google.common.base.CaseFormat;
 import me.lortseam.completeconfig.api.ConfigEntry;
 import me.lortseam.completeconfig.api.ConfigEntryContainer;
 import me.lortseam.completeconfig.api.ConfigEntryListener;
+import me.lortseam.completeconfig.data.gui.TranslationIdentifier;
 import me.lortseam.completeconfig.exception.IllegalAnnotationParameterException;
-import me.lortseam.completeconfig.exception.IllegalAnnotationTargetException;
 import me.lortseam.completeconfig.exception.IllegalModifierException;
 import me.lortseam.completeconfig.exception.IllegalReturnTypeException;
-import org.apache.commons.lang3.StringUtils;
+import org.spongepowered.configurate.CommentedConfigurationNode;
 
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-public class EntryMap extends ConfigMap<Entry> {
+public class EntryMap extends ConfigMap<Entry> implements DataPart<ConfigEntryContainer> {
 
-    EntryMap(String modTranslationKey) {
-        super(modTranslationKey);
+    EntryMap(TranslationIdentifier translation) {
+        super(translation);
     }
 
-    void fill(Collection parent, ConfigEntryContainer container) {
+    @Override
+    public void resolve(ConfigEntryContainer container) {
         List<Entry> containerEntries = new ArrayList<>();
         for (Class<? extends ConfigEntryContainer> clazz : container.getConfigClasses()) {
             Arrays.stream(clazz.getDeclaredMethods()).filter(method -> !Modifier.isStatic(method.getModifiers()) && method.isAnnotationPresent(ConfigEntryListener.class)).forEach(method -> {
@@ -40,8 +41,8 @@ public class EntryMap extends ConfigMap<Entry> {
                 if (method.getParameterCount() != 1) {
                     throw new IllegalArgumentException("Listener method " + method + " has wrong number of parameters");
                 }
-                Entry<?> entry = Entry.of(parent, fieldName, fieldClass);
-                if (method.getParameterTypes()[0] != entry.getType()) {
+                EntryAccessor<?> accessor = Entry.of(fieldName, fieldClass);
+                if (method.getParameterTypes()[0] != accessor.getType()) {
                     throw new IllegalArgumentException("Listener method " + method + " has wrong argument type");
                 }
                 if (method.getReturnType() != Void.TYPE) {
@@ -50,7 +51,7 @@ public class EntryMap extends ConfigMap<Entry> {
                 if (!method.isAccessible()) {
                     method.setAccessible(true);
                 }
-                entry.addListener(method, container);
+                accessor.connect(entry -> entry.addListener(method, container));
             });
             List<Entry> clazzEntries = new ArrayList<>();
             Arrays.stream(clazz.getDeclaredFields()).filter(field -> {
@@ -68,66 +69,8 @@ public class EntryMap extends ConfigMap<Entry> {
                 if (!field.isAccessible()) {
                     field.setAccessible(true);
                 }
-                Entry<?> entry = Entry.of(parent, field, container);
-                if (field.isAnnotationPresent(ConfigEntry.class)) {
-                    ConfigEntry entryAnnotation = field.getDeclaredAnnotation(ConfigEntry.class);
-                    String id = entryAnnotation.value();
-                    if (!StringUtils.isBlank(id)) {
-                        entry.setCustomID(id);
-                    }
-                    String customTranslationKey = entryAnnotation.customTranslationKey();
-                    if (!StringUtils.isBlank(customTranslationKey)) {
-                        entry.setCustomTranslationKey(modTranslationKey + "."  + customTranslationKey);
-                    }
-                    String[] customTooltipKeys = entryAnnotation.customTooltipKeys();
-                    if (customTooltipKeys.length > 0) {
-                        for (String key : customTooltipKeys) {
-                            if (StringUtils.isBlank(key)) {
-                                throw new IllegalAnnotationParameterException("Tooltip key(s) of entry field " + field + " must not be blank");
-                            }
-                        }
-                        entry.setCustomTooltipKeys(Arrays.stream(customTooltipKeys).map(key -> modTranslationKey + "." + key).toArray(String[]::new));
-                    }
-                    entry.setForceUpdate(entryAnnotation.forceUpdate());
-                    entry.setRequiresRestart(entryAnnotation.requiresRestart());
-                }
-                if (field.isAnnotationPresent(ConfigEntry.Bounded.Integer.class)) {
-                    if (field.getType() != int.class && field.getType() != Integer.class) {
-                        throw new IllegalAnnotationTargetException("Cannot apply Integer bound to non Integer field " + field);
-                    }
-                    ConfigEntry.Bounded.Integer bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Integer.class);
-                    entry.setBounds(bounds.min(), bounds.max(), bounds.slider());
-                }
-                if (field.isAnnotationPresent(ConfigEntry.Bounded.Long.class)) {
-                    if (field.getType() != long.class && field.getType() != Long.class) {
-                        throw new IllegalAnnotationTargetException("Cannot apply Long bound to non Long field " + field);
-                    }
-                    ConfigEntry.Bounded.Long bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Long.class);
-                    entry.setBounds(bounds.min(), bounds.max(), bounds.slider());
-                }
-                if (field.isAnnotationPresent(ConfigEntry.Bounded.Float.class)) {
-                    if (field.getType() != float.class && field.getType() != Float.class) {
-                        throw new IllegalAnnotationTargetException("Cannot apply Float bound to non Float field " + field);
-                    }
-                    ConfigEntry.Bounded.Float bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Float.class);
-                    entry.setBounds(bounds.min(), bounds.max(), false);
-                }
-                if (field.isAnnotationPresent(ConfigEntry.Bounded.Double.class)) {
-                    if (field.getType() != double.class && field.getType() != Double.class) {
-                        throw new IllegalAnnotationTargetException("Cannot apply Double bound to non Double field " + field);
-                    }
-                    ConfigEntry.Bounded.Double bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Double.class);
-                    entry.setBounds(bounds.min(), bounds.max(), false);
-                }
-                if (Enum.class.isAssignableFrom(field.getType())) {
-                    if (field.isAnnotationPresent(ConfigEntry.EnumOptions.class)) {
-                        entry.setEnumOptions(field.getDeclaredAnnotation(ConfigEntry.EnumOptions.class).displayType());
-                    } else {
-                        entry.setEnumOptions(EnumOptions.DisplayType.getDefault());
-                    }
-                } else if (field.isAnnotationPresent(ConfigEntry.EnumOptions.class)) {
-                    throw new IllegalAnnotationTargetException("Cannot apply enum options to non enum field " + field);
-                }
+                Entry<?> entry = ((Entry.Draft<?>) Entry.of(field)).build(container, translation);
+                entry.resolve(field);
                 clazzEntries.add(entry);
             });
             containerEntries.addAll(0, clazzEntries);
@@ -137,4 +80,18 @@ public class EntryMap extends ConfigMap<Entry> {
         }
     }
 
+    @Override
+    public void apply(CommentedConfigurationNode node) {
+        forEach((id, entry) -> {
+            CommentedConfigurationNode entryNode = node.node(id);
+            if(entryNode.virtual()) return;
+            entry.apply(entryNode);
+        });
+    }
+
+    @Override
+    public void fetch(CommentedConfigurationNode node) {
+        forEach((id, entry) -> entry.fetch(node.node(id)));
+    }
+
 }

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

@@ -6,7 +6,6 @@ import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import me.lortseam.completeconfig.api.ConfigEntry;
 import net.minecraft.text.Text;
-import net.minecraft.text.TranslatableText;
 
 import java.util.function.Function;
 
@@ -18,27 +17,23 @@ public class EnumOptions {
     private final DisplayType displayType;
 
     public Function<Enum, Text> getNameProvider() {
-        return enumValue -> new TranslatableText(parent.getTranslationKey() + "." + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, enumValue.name()));
+        return enumValue -> parent.getTranslation().append(CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, enumValue.name())).translate();
     }
 
     public enum DisplayType {
 
         BUTTON, DROPDOWN;
 
-        private static final DisplayType defaultValue;
+        static final DisplayType DEFAULT;
 
         static {
             try {
-                defaultValue = (DisplayType) ConfigEntry.EnumOptions.class.getDeclaredMethod("displayType").getDefaultValue();
+                DEFAULT = (DisplayType) ConfigEntry.EnumOptions.class.getDeclaredMethod("displayType").getDefaultValue();
             } catch (NoSuchMethodException e) {
                 throw new RuntimeException(e);
             }
         }
 
-        public static DisplayType getDefault() {
-            return defaultValue;
-        }
-
     }
 
 }

+ 26 - 0
src/main/java/me/lortseam/completeconfig/data/Listener.java

@@ -0,0 +1,26 @@
+package me.lortseam.completeconfig.data;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import me.lortseam.completeconfig.api.ConfigEntryContainer;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+@AllArgsConstructor(access = AccessLevel.PACKAGE)
+public class Listener<T> {
+
+    private final Method method;
+    @Getter(AccessLevel.PACKAGE)
+    private final ConfigEntryContainer parentObject;
+
+    void invoke(T value) {
+        try {
+            method.invoke(parentObject, value);
+        } catch (IllegalAccessException | InvocationTargetException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}

+ 51 - 0
src/main/java/me/lortseam/completeconfig/data/gui/TranslationIdentifier.java

@@ -0,0 +1,51 @@
+package me.lortseam.completeconfig.data.gui;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import net.minecraft.client.resource.language.I18n;
+import net.minecraft.text.TranslatableText;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.util.regex.Pattern;
+
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+public final class TranslationIdentifier {
+
+    private final String modKey;
+    private final String[] keyParts;
+
+    public TranslationIdentifier(String modID) {
+        modKey = "config." + modID;
+        keyParts = new String[0];
+    }
+
+    private String getKey() {
+        StringBuilder builder = new StringBuilder(modKey);
+        for (String keyPart : keyParts) {
+            builder.append(".");
+            builder.append(keyPart);
+        }
+        return builder.toString();
+    }
+
+    public TranslationIdentifier getModTranslation() {
+        return new TranslationIdentifier(modKey, new String[0]);
+    }
+
+    public boolean exists() {
+        return I18n.hasTranslation(getKey());
+    }
+
+    public TranslatableText translate() {
+        return new TranslatableText(getKey());
+    }
+
+    public TranslationIdentifier append(String... keyParts) {
+        return new TranslationIdentifier(modKey, ArrayUtils.addAll(this.keyParts, keyParts));
+    }
+
+    public TranslationIdentifier appendKey(String key) {
+        return new TranslationIdentifier(modKey, key.split(Pattern.quote(".")));
+    }
+
+}

+ 1 - 2
src/main/java/me/lortseam/completeconfig/gui/cloth/ClothGuiBuilder.java

@@ -13,7 +13,6 @@ import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder;
 import net.fabricmc.api.EnvType;
 import net.fabricmc.api.Environment;
 import net.minecraft.client.gui.screen.Screen;
-import net.minecraft.text.TranslatableText;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -39,7 +38,7 @@ public class ClothGuiBuilder implements GuiBuilder {
     public Screen buildScreen(Screen parentScreen, Config config, Runnable savingRunnable) {
         ConfigBuilder builder = supplier.get();
         builder.setParentScreen(parentScreen)
-                .setTitle(new TranslatableText(config.getModTranslationKey() + ".title"))
+                .setTitle(config.getTranslation().append("title").translate())
                 .setSavingRunnable(savingRunnable);
         for(Collection collection : config.values()) {
             ConfigCategory configCategory = builder.getOrCreateCategory(collection.getText());

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

@@ -177,7 +177,7 @@ public class GuiRegistry {
        ), String.class);
        registerEnumProvider((GuiProvider<? extends Enum<?>>) entry -> build(
                builder -> builder
-                       .startEnumSelector(entry.getText(), (Class<Enum<?>>) entry.getField().getType(), entry.getValue())
+                       .startEnumSelector(entry.getText(), entry.getType(), entry.getValue())
                        .setDefaultValue(entry.getDefaultValue())
                        .setTooltip(entry.getTooltip())
                        .setEnumNameProvider(entry.getExtras().getEnumOptions().getNameProvider())
@@ -185,7 +185,7 @@ public class GuiRegistry {
                entry.requiresRestart()
        ), EnumOptions.DisplayType.BUTTON);
        registerEnumProvider((GuiProvider<? extends Enum>) entry -> {
-           List<Enum> enumValues = Arrays.asList(((Class<? extends Enum>) entry.getField().getType()).getEnumConstants());
+           List<Enum> enumValues = Arrays.asList(((Class<? extends Enum>) entry.getType()).getEnumConstants());
            return build(
                    builder -> builder
                            .startDropdownMenu(entry.getText(), DropdownMenuBuilder.TopCellElementBuilder.of(

+ 0 - 32
src/main/java/me/lortseam/completeconfig/serialization/CollectionDeserializer.java

@@ -1,32 +0,0 @@
-package me.lortseam.completeconfig.serialization;
-
-import com.google.gson.*;
-import com.google.gson.reflect.TypeToken;
-import me.lortseam.completeconfig.data.Collection;
-import me.lortseam.completeconfig.data.CollectionMap;
-import me.lortseam.completeconfig.data.EntryMap;
-
-import java.lang.reflect.Type;
-import java.util.Map;
-
-public class CollectionDeserializer implements JsonDeserializer<Collection> {
-
-    public static final Type TYPE = new TypeToken<Collection>() {}.getType();
-
-    @Override
-    public Collection deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
-        JsonObject collections = new JsonObject();
-        JsonObject entries = new JsonObject();
-        for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
-            if (entry.getValue().isJsonObject()) {
-                collections.add(entry.getKey(), entry.getValue());
-            } else {
-                entries.add(entry.getKey(), entry.getValue());
-            }
-        }
-        context.deserialize(collections, new TypeToken<CollectionMap>() {}.getType());
-        context.deserialize(entries, new TypeToken<EntryMap>() {}.getType());
-        return null;
-    }
-
-}

+ 0 - 53
src/main/java/me/lortseam/completeconfig/serialization/CollectionMapDeserializer.java

@@ -1,53 +0,0 @@
-package me.lortseam.completeconfig.serialization;
-
-import com.google.gson.*;
-import com.google.gson.reflect.TypeToken;
-import me.lortseam.completeconfig.data.Collection;
-import me.lortseam.completeconfig.data.CollectionMap;
-
-import java.lang.reflect.Type;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-public class CollectionMapDeserializer implements JsonDeserializer<CollectionMap> {
-
-    private static final Gson GSON = new Gson();
-    public static final Type TYPE = new TypeToken<CollectionMap>() {}.getType();
-
-    private final Map<String, Collection> configMap;
-    private final String collectionID;
-
-    public CollectionMapDeserializer(Map<String, Collection> configMap, String collectionID) {
-        this.configMap = configMap;
-        this.collectionID = collectionID;
-    }
-
-    private CollectionMapDeserializer(Map<String, Collection> configMap) {
-        this(configMap, null);
-    }
-
-    @Override
-    public CollectionMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
-        LinkedHashMap<String, JsonElement> map = GSON.fromJson(json, new TypeToken<LinkedHashMap<String, JsonElement>>() {}.getType());
-        if (collectionID == null) {
-            map.forEach(this::deserializeCollection);
-        } else {
-            deserializeCollection(collectionID, map.get(collectionID));
-        }
-        return null;
-    }
-
-    private void deserializeCollection(String collectionID, JsonElement element) {
-        Collection collection = configMap.get(collectionID);
-        if (collection == null) {
-            return;
-        }
-        new GsonBuilder()
-                .registerTypeAdapter(CollectionDeserializer.TYPE, new CollectionDeserializer())
-                .registerTypeAdapter(CollectionMapDeserializer.TYPE, new CollectionMapDeserializer(collection.getCollections()))
-                .registerTypeAdapter(EntryMapDeserializer.TYPE, new EntryMapDeserializer(collection.getEntries()))
-                .create()
-                .fromJson(element, Collection.class);
-    }
-
-}

+ 0 - 21
src/main/java/me/lortseam/completeconfig/serialization/CollectionSerializer.java

@@ -1,21 +0,0 @@
-package me.lortseam.completeconfig.serialization;
-
-import com.google.gson.*;
-import com.google.gson.reflect.TypeToken;
-import me.lortseam.completeconfig.data.Collection;
-
-import java.lang.reflect.Type;
-
-public class CollectionSerializer implements JsonSerializer<Collection> {
-
-    public static final Type TYPE = new TypeToken<Collection>() {}.getType();
-
-    @Override
-    public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) {
-        JsonObject jsonObject = new JsonObject();
-        src.getCollections().forEach((key, collection) -> jsonObject.add(key, context.serialize(collection)));
-        src.getEntries().forEach((key, entry) -> jsonObject.add(key, context.serialize(entry)));
-        return jsonObject;
-    }
-
-}

+ 0 - 36
src/main/java/me/lortseam/completeconfig/serialization/EntryDeserializer.java

@@ -1,36 +0,0 @@
-package me.lortseam.completeconfig.serialization;
-
-import com.google.gson.JsonDeserializationContext;
-import com.google.gson.JsonDeserializer;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParseException;
-import com.google.gson.reflect.TypeToken;
-import me.lortseam.completeconfig.data.Entry;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import java.lang.reflect.Type;
-
-public class EntryDeserializer<T> implements JsonDeserializer<Entry<T>> {
-
-    private static final Logger LOGGER = LogManager.getLogger();
-    public static final Type TYPE = new TypeToken<Entry<?>>() {}.getType();
-
-    private final Entry<T> configEntry;
-
-    public EntryDeserializer(Entry<T> configEntry) {
-        this.configEntry = configEntry;
-    }
-
-    @Override
-    public Entry<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
-        try {
-            T value = context.deserialize(json, configEntry.getType());
-            configEntry.setValue(value);
-        } catch (JsonParseException e) {
-            LOGGER.warn("[CompleteConfig] An error occurred while trying to load the config entry's value of field " + configEntry.getField() + ": " + e.getMessage());
-        }
-        return configEntry;
-    }
-
-}

+ 0 - 36
src/main/java/me/lortseam/completeconfig/serialization/EntryMapDeserializer.java

@@ -1,36 +0,0 @@
-package me.lortseam.completeconfig.serialization;
-
-import com.google.gson.*;
-import com.google.gson.reflect.TypeToken;
-import lombok.RequiredArgsConstructor;
-import me.lortseam.completeconfig.data.EntryMap;
-import me.lortseam.completeconfig.data.Entry;
-
-import java.lang.reflect.Type;
-import java.util.LinkedHashMap;
-
-@RequiredArgsConstructor
-public class EntryMapDeserializer implements JsonDeserializer<EntryMap> {
-
-    private static final Gson GSON = new Gson();
-    public static final Type TYPE = new TypeToken<EntryMap>() {}.getType();
-
-    private final EntryMap configMap;
-
-    @Override
-    public EntryMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
-        LinkedHashMap<String, JsonElement> map = GSON.fromJson(json, new TypeToken<LinkedHashMap<String, JsonElement>>() {}.getType());
-        map.forEach((entryID, element) -> {
-            Entry<?> entry = configMap.get(entryID);
-            if (entry == null) {
-                return;
-            }
-            new GsonBuilder()
-                    .registerTypeAdapter(EntryDeserializer.TYPE, new EntryDeserializer<>(entry))
-                    .create()
-                    .fromJson(element, new TypeToken<Entry<?>>() {}.getType());
-        });
-        return null;
-    }
-
-}

+ 0 - 19
src/main/java/me/lortseam/completeconfig/serialization/EntrySerializer.java

@@ -1,19 +0,0 @@
-package me.lortseam.completeconfig.serialization;
-
-import com.google.gson.JsonElement;
-import com.google.gson.JsonSerializationContext;
-import com.google.gson.JsonSerializer;
-import me.lortseam.completeconfig.data.Entry;
-
-import java.lang.reflect.Type;
-
-public class EntrySerializer implements JsonSerializer<Entry> {
-
-    public static final Type TYPE = Entry.class;
-
-    @Override
-    public JsonElement serialize(Entry entry, Type typeOfSrc, JsonSerializationContext context) {
-        return context.serialize(entry.getValue());
-    }
-
-}