소스 검색

Use YAML instead of JSON (closes #11)

Lortseam 4 년 전
부모
커밋
fea6591792

+ 2 - 0
build.gradle

@@ -19,6 +19,8 @@ dependencies {
 		exclude(group: "net.fabricmc.fabric-api")
 	}
 
+	implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:${project.jackson_version}"
+
 	compileOnly "org.projectlombok:lombok:${project.lombok_version}"
 	annotationProcessor "org.projectlombok:lombok:${project.lombok_version}"
 }

+ 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
+	jackson_version=2.12.0

+ 9 - 9
src/main/java/me/lortseam/completeconfig/Config.java

@@ -1,32 +1,32 @@
 package me.lortseam.completeconfig;
 
-import com.google.gson.GsonBuilder;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonSyntaxException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
 import me.lortseam.completeconfig.api.ConfigCategory;
 import me.lortseam.completeconfig.data.CollectionMap;
 import me.lortseam.completeconfig.serialization.CollectionMapDeserializer;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import java.io.IOException;
 import java.util.List;
 
 public class Config extends CollectionMap {
 
     private static final Logger LOGGER = LogManager.getLogger();
 
-    Config(String modID, List<ConfigCategory> topLevelCategories, JsonElement json) {
+    Config(String modID, List<ConfigCategory> topLevelCategories, JsonNode yaml) {
         super("config." + modID);
         for (ConfigCategory category : topLevelCategories) {
             if (!fill(modTranslationKey, category)) {
                 continue;
             }
             try {
-                new GsonBuilder()
-                        .registerTypeAdapter(CollectionMapDeserializer.TYPE, new CollectionMapDeserializer(this, category.getConfigCategoryID()))
-                        .create()
-                        .fromJson(json, CollectionMapDeserializer.TYPE);
-            } catch (JsonSyntaxException e) {
+                new YAMLMapper().registerModule(new SimpleModule()
+                        .addDeserializer(CollectionMapDeserializer.TYPE, new CollectionMapDeserializer(this, category.getConfigCategoryID()))
+                ).readValue(yaml.traverse(), CollectionMapDeserializer.TYPE);
+            } catch (IOException e) {
                 LOGGER.warn("[CompleteConfig] An error occurred while trying to load the config for category " + category.getClass());
             }
         }

+ 15 - 15
src/main/java/me/lortseam/completeconfig/ConfigHandler.java

@@ -1,6 +1,10 @@
 package me.lortseam.completeconfig;
 
-import com.google.gson.*;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.node.NullNode;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
 import me.lortseam.completeconfig.api.ConfigCategory;
 import me.lortseam.completeconfig.api.ConfigOwner;
 import me.lortseam.completeconfig.gui.GuiBuilder;
@@ -14,7 +18,6 @@ import org.apache.commons.lang3.ArrayUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
-import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.Writer;
@@ -25,11 +28,10 @@ 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 ObjectMapper MAPPER = new YAMLMapper().registerModule(new SimpleModule()
+            .addSerializer(CollectionSerializer.TYPE, new CollectionSerializer())
+            .addSerializer(EntrySerializer.TYPE, new EntrySerializer())
+    );
     private static final Logger LOGGER = LogManager.getLogger();
     private static final Map<Class<? extends ConfigOwner>, ConfigHandler> HANDLERS = new HashMap<>();
 
@@ -50,7 +52,7 @@ public final class ConfigHandler {
             return null;
         }
         String[] subPath = ArrayUtils.add(branch, 0, modID);
-        subPath[subPath.length - 1] = subPath[subPath.length - 1] + ".json";
+        subPath[subPath.length - 1] = subPath[subPath.length - 1] + ".yaml";
         Path jsonPath = Paths.get(FabricLoader.getInstance().getConfigDir().toString(), subPath);
         if (HANDLERS.values().stream().anyMatch(handler -> handler.jsonPath.equals(jsonPath))) {
             throw new IllegalArgumentException("A config of the mod " + modID + " with the specified branch " + Arrays.toString(branch) + " already exists!");
@@ -80,17 +82,15 @@ public final class ConfigHandler {
         this.guiBuilder = guiBuilder;
     }
 
-    private JsonElement load() {
+    private JsonNode 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) {
+                return MAPPER.readTree(new FileReader(jsonPath.toString()));
+            } catch (IOException e) {
                 LOGGER.warn("[CompleteConfig] An error occurred while trying to load the config " + jsonPath.toString());
             }
         }
-        return JsonNull.INSTANCE;
+        return NullNode.instance;
     }
 
     /**
@@ -124,7 +124,7 @@ public final class ConfigHandler {
             }
         }
         try(Writer writer = Files.newBufferedWriter(jsonPath)) {
-            GSON.toJson(config, writer);
+            MAPPER.writeValue(writer, config);
         } catch (IOException e) {
             throw new RuntimeException(e);
         }

+ 23 - 15
src/main/java/me/lortseam/completeconfig/serialization/CollectionDeserializer.java

@@ -1,31 +1,39 @@
 package me.lortseam.completeconfig.serialization;
 
-import com.google.gson.*;
-import com.google.gson.reflect.TypeToken;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 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;
+import java.io.IOException;
+import java.util.Iterator;
 
-public class CollectionDeserializer implements JsonDeserializer<Collection> {
+public class CollectionDeserializer extends JsonDeserializer<Collection> {
 
-    public static final Type TYPE = new TypeToken<Collection>() {}.getType();
+    public static final Class<Collection> TYPE = Collection.class;
 
     @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());
+    public Collection deserialize(JsonParser parser, DeserializationContext context) throws IOException {
+        ObjectNode collections = new ObjectNode(JsonNodeFactory.instance);
+        ObjectNode entries = new ObjectNode(JsonNodeFactory.instance);
+        ObjectNode collection = parser.readValueAsTree();
+        Iterator<String> iterator = collection.fieldNames();
+        while (iterator.hasNext()) {
+            String key = iterator.next();
+            JsonNode value = collection.findValue(key);
+            if (value.isObject()) {
+                collections.set(key, value);
             } else {
-                entries.add(entry.getKey(), entry.getValue());
+                entries.set(key, value);
             }
         }
-        context.deserialize(collections, new TypeToken<CollectionMap>() {}.getType());
-        context.deserialize(entries, new TypeToken<EntryMap>() {}.getType());
+        context.readValue(collections.traverse(), CollectionMap.class);
+        context.readValue(entries.traverse(), EntryMap.class);
         return null;
     }
 

+ 22 - 16
src/main/java/me/lortseam/completeconfig/serialization/CollectionMapDeserializer.java

@@ -1,18 +1,23 @@
 package me.lortseam.completeconfig.serialization;
 
-import com.google.gson.*;
-import com.google.gson.reflect.TypeToken;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
 import me.lortseam.completeconfig.data.Collection;
 import me.lortseam.completeconfig.data.CollectionMap;
 
-import java.lang.reflect.Type;
+import java.io.IOException;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
-public class CollectionMapDeserializer implements JsonDeserializer<CollectionMap> {
+public class CollectionMapDeserializer extends JsonDeserializer<CollectionMap> {
 
-    private static final Gson GSON = new Gson();
-    public static final Type TYPE = new TypeToken<CollectionMap>() {}.getType();
+    private static final YAMLMapper MAPPER = new YAMLMapper();
+    public static final Class<CollectionMap> TYPE = CollectionMap.class;
 
     private final Map<String, Collection> configMap;
     private final String collectionID;
@@ -27,27 +32,28 @@ public class CollectionMapDeserializer implements JsonDeserializer<CollectionMap
     }
 
     @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());
+    public CollectionMap deserialize(JsonParser parser, DeserializationContext context) throws IOException {
+        LinkedHashMap<String, JsonNode> map = MAPPER.readValue(parser, TypeFactory.defaultInstance().constructMapType(LinkedHashMap.class, String.class, JsonNode.class));
         if (collectionID == null) {
-            map.forEach(this::deserializeCollection);
+            for (Map.Entry<String, JsonNode> entry : map.entrySet()) {
+                deserializeCollection(entry.getKey(), entry.getValue());
+            }
         } else {
             deserializeCollection(collectionID, map.get(collectionID));
         }
         return null;
     }
 
-    private void deserializeCollection(String collectionID, JsonElement element) {
+    private void deserializeCollection(String collectionID, JsonNode node) throws IOException {
         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);
+        new YAMLMapper().registerModule(new SimpleModule()
+                .addDeserializer(CollectionDeserializer.TYPE, new CollectionDeserializer())
+                .addDeserializer(CollectionMapDeserializer.TYPE, new CollectionMapDeserializer(collection.getCollections()))
+                .addDeserializer(EntryMapDeserializer.TYPE, new EntryMapDeserializer(collection.getEntries()))
+        ).readValue(node.traverse(), Collection.class);
     }
 
 }

+ 19 - 10
src/main/java/me/lortseam/completeconfig/serialization/CollectionSerializer.java

@@ -1,21 +1,30 @@
 package me.lortseam.completeconfig.serialization;
 
-import com.google.gson.*;
-import com.google.gson.reflect.TypeToken;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
 import me.lortseam.completeconfig.data.Collection;
+import me.lortseam.completeconfig.data.Entry;
 
-import java.lang.reflect.Type;
+import java.io.IOException;
+import java.util.Map;
 
-public class CollectionSerializer implements JsonSerializer<Collection> {
+public class CollectionSerializer extends JsonSerializer<Collection> {
 
-    public static final Type TYPE = new TypeToken<Collection>() {}.getType();
+    public static final Class<Collection> TYPE = Collection.class;
 
     @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;
+    public void serialize(Collection value, JsonGenerator generator, SerializerProvider serializers) throws IOException {
+        generator.writeStartObject();
+        for (Map.Entry<String, Collection> entry : value.getCollections().entrySet()) {
+            generator.writeFieldName(entry.getKey());
+            serializers.defaultSerializeValue(entry.getValue(), generator);
+        }
+        for (Map.Entry<String, Entry> entry : value.getEntries().entrySet()) {
+            generator.writeFieldName(entry.getKey());
+            serializers.defaultSerializeValue(entry.getValue(), generator);
+        }
+        generator.writeEndObject();
     }
 
 }

+ 10 - 11
src/main/java/me/lortseam/completeconfig/serialization/EntryDeserializer.java

@@ -1,20 +1,19 @@
 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 com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
 import me.lortseam.completeconfig.data.Entry;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
-import java.lang.reflect.Type;
+import java.io.IOException;
 
-public class EntryDeserializer<T> implements JsonDeserializer<Entry<T>> {
+public class EntryDeserializer<T> extends JsonDeserializer<Entry<T>> {
 
     private static final Logger LOGGER = LogManager.getLogger();
-    public static final Type TYPE = new TypeToken<Entry<?>>() {}.getType();
+    public static final Class<Entry> TYPE = Entry.class;
 
     private final Entry<T> configEntry;
 
@@ -23,11 +22,11 @@ public class EntryDeserializer<T> implements JsonDeserializer<Entry<T>> {
     }
 
     @Override
-    public Entry<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+    public Entry<T> deserialize(JsonParser parser, DeserializationContext context) {
         try {
-            T value = context.deserialize(json, configEntry.getType());
+            T value = context.readValue(parser, configEntry.getType());
             configEntry.setValue(value);
-        } catch (JsonParseException e) {
+        } catch (IOException e) {
             LOGGER.warn("[CompleteConfig] An error occurred while trying to load the config entry's value of field " + configEntry.getField() + ": " + e.getMessage());
         }
         return configEntry;

+ 22 - 17
src/main/java/me/lortseam/completeconfig/serialization/EntryMapDeserializer.java

@@ -1,35 +1,40 @@
 package me.lortseam.completeconfig.serialization;
 
-import com.google.gson.*;
-import com.google.gson.reflect.TypeToken;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
 import lombok.RequiredArgsConstructor;
-import me.lortseam.completeconfig.data.EntryMap;
 import me.lortseam.completeconfig.data.Entry;
+import me.lortseam.completeconfig.data.EntryMap;
 
-import java.lang.reflect.Type;
+import java.io.IOException;
 import java.util.LinkedHashMap;
+import java.util.Map;
 
 @RequiredArgsConstructor
-public class EntryMapDeserializer implements JsonDeserializer<EntryMap> {
+public class EntryMapDeserializer extends JsonDeserializer<EntryMap> {
 
-    private static final Gson GSON = new Gson();
-    public static final Type TYPE = new TypeToken<EntryMap>() {}.getType();
+    private static final YAMLMapper MAPPER = new YAMLMapper();
+    public static final Class<EntryMap> TYPE = EntryMap.class;
 
     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);
+    public EntryMap deserialize(JsonParser parser, DeserializationContext context) throws IOException {
+        LinkedHashMap<String, JsonNode> map = MAPPER.readValue(parser, TypeFactory.defaultInstance().constructMapType(LinkedHashMap.class, String.class, JsonNode.class));
+        for (Map.Entry<String, JsonNode> mapEntry : map.entrySet()) {
+            Entry<?> entry = configMap.get(mapEntry.getKey());
             if (entry == null) {
-                return;
+                break;
             }
-            new GsonBuilder()
-                    .registerTypeAdapter(EntryDeserializer.TYPE, new EntryDeserializer<>(entry))
-                    .create()
-                    .fromJson(element, new TypeToken<Entry<?>>() {}.getType());
-        });
+            new YAMLMapper().registerModule(new SimpleModule()
+                    .addDeserializer(EntryDeserializer.TYPE, new EntryDeserializer<>(entry))
+            ).readValue(mapEntry.getValue().traverse(), Entry.class);
+        }
         return null;
     }
 

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

@@ -1,19 +1,19 @@
 package me.lortseam.completeconfig.serialization;
 
-import com.google.gson.JsonElement;
-import com.google.gson.JsonSerializationContext;
-import com.google.gson.JsonSerializer;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
 import me.lortseam.completeconfig.data.Entry;
 
-import java.lang.reflect.Type;
+import java.io.IOException;
 
-public class EntrySerializer implements JsonSerializer<Entry> {
+public class EntrySerializer extends JsonSerializer<Entry> {
 
-    public static final Type TYPE = Entry.class;
+    public static final Class<Entry> TYPE = Entry.class;
 
     @Override
-    public JsonElement serialize(Entry entry, Type typeOfSrc, JsonSerializationContext context) {
-        return context.serialize(entry.getValue());
+    public void serialize(Entry entry, JsonGenerator generator, SerializerProvider serializers) throws IOException {
+        serializers.defaultSerializeValue(entry.getValue(), generator);
     }
 
 }