diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ac8f8a6..03166f1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -4,9 +4,8 @@ minecraft = "1.20.4" yarn = "build.3" fabric-loader = "0.15.7" fabric-api = "0.96.4+1.20.4" -jf-commons = "1.6-SNAPSHOT" +jf-commons = "1.7-SNAPSHOT" modmenu = "9.0.0" -gson-compile = "1.4-SNAPSHOT" annotations = "24.1.0" javapoet = "1.13.0" @@ -16,12 +15,13 @@ commons-http-client = { module = "io.gitlab.jfronny:commons-http-client", versio commons-io = { module = "io.gitlab.jfronny:commons-io", version.ref="jf-commons" } commons-logger = { module = "io.gitlab.jfronny:commons-logger", version.ref="jf-commons" } commons-serialize = { module = "io.gitlab.jfronny:commons-serialize", version.ref="jf-commons" } -commons-serialize-gson = { module = "io.gitlab.jfronny:commons-serialize-gson", version.ref="jf-commons" } +commons-serialize-databind = { module = "io.gitlab.jfronny:commons-serialize-databind", version.ref="jf-commons" } +commons-serialize-json = { module = "io.gitlab.jfronny:commons-serialize-json", version.ref="jf-commons" } +commons-serialize-generator-core = { module = "io.gitlab.jfronny:commons-serialize-generator-core", version.ref="jf-commons" } commons-unsafe = { module = "io.gitlab.jfronny:commons-unsafe", version.ref="jf-commons" } modmenu = { module = "com.terraformersmc:modmenu", version.ref="modmenu" } -gson-compile-processor-core = { module = "io.gitlab.jfronny.gson:gson-compile-processor-core", version.ref="gson-compile" } annotations = { module = "org.jetbrains:annotations", version.ref="annotations" } javapoet = { module = "com.squareup:javapoet", version.ref="javapoet" } [bundles] -commons = ["commons", "commons-http-client", "commons-logger", "commons-io", "commons-serialize", "commons-serialize-gson"] \ No newline at end of file +commons = ["commons", "commons-http-client", "commons-logger", "commons-io", "commons-serialize", "commons-serialize-databind", "commons-serialize-json"] \ No newline at end of file diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java index 094be49..e60a4f8 100644 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/LibJf.java @@ -1,10 +1,12 @@ package io.gitlab.jfronny.libjf; +import io.gitlab.jfronny.commons.Serializer; import io.gitlab.jfronny.commons.logger.DelegateLogger; import io.gitlab.jfronny.commons.logger.HotswapLoggerFinder; import io.gitlab.jfronny.commons.logger.SystemLoggerPlus; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; -import io.gitlab.jfronny.libjf.gson.HiddenAnnotationExclusionStrategy; +import io.gitlab.jfronny.commons.serialize.databind.DatabindSerializer; +import io.gitlab.jfronny.commons.serialize.databind.ObjectMapper; +import io.gitlab.jfronny.commons.serialize.json.JsonTransport; import io.gitlab.jfronny.libjf.log.JULBridge; import io.gitlab.jfronny.libjf.log.SLF4JPlatformLogger; import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; @@ -13,10 +15,11 @@ import org.slf4j.LoggerFactory; public class LibJf implements PreLaunchEntrypoint { public static final String MOD_ID = "libjf"; public static final SystemLoggerPlus LOGGER = SystemLoggerPlus.forName(MOD_ID); + public static final ObjectMapper MAPPER = new ObjectMapper(); + public static final JsonTransport JSON_TRANSPORT = new JsonTransport(); static { - HiddenAnnotationExclusionStrategy.register(); - GsonHolders.registerSerializer(); + Serializer.setInstance(new DatabindSerializer<>(JSON_TRANSPORT, MAPPER)); } @Override diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ClientOnly.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ClientOnly.java deleted file mode 100644 index d09d721..0000000 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ClientOnly.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.gitlab.jfronny.libjf.gson; - -import java.lang.annotation.*; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ClientOnly { -} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/FabricLoaderGsonGenerator.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/FabricLoaderGsonGenerator.java deleted file mode 100644 index 8838515..0000000 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/FabricLoaderGsonGenerator.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.gitlab.jfronny.libjf.gson; - -import io.gitlab.jfronny.gson.*; -import net.fabricmc.loader.api.metadata.CustomValue; - -import java.util.Map; - -public class FabricLoaderGsonGenerator { - public static JsonElement toGson(CustomValue customValue) { - if (customValue == null) return null; - return switch (customValue.getType()) { - case OBJECT -> { - JsonObject jo = new JsonObject(); - for (Map.Entry value : customValue.getAsObject()) - jo.add(value.getKey(), toGson(value.getValue())); - yield jo; - } - case ARRAY -> { - JsonArray jo = new JsonArray(); - for (CustomValue value : customValue.getAsArray()) - jo.add(toGson(value)); - yield jo; - } - case STRING -> new JsonPrimitive(customValue.getAsString()); - case NUMBER -> new JsonPrimitive(customValue.getAsNumber()); - case BOOLEAN -> new JsonPrimitive(customValue.getAsBoolean()); - case NULL -> JsonNull.INSTANCE; - }; - } -} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/GsonAdapter.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/GsonAdapter.java deleted file mode 100644 index ae8179b..0000000 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/GsonAdapter.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.gitlab.jfronny.libjf.gson; - -import io.gitlab.jfronny.gson.GsonBuilder; - -public interface GsonAdapter { - void apply(GsonBuilder builder); -} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java deleted file mode 100644 index 41d99ec..0000000 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/HiddenAnnotationExclusionStrategy.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.gitlab.jfronny.libjf.gson; - -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; -import io.gitlab.jfronny.gson.ExclusionStrategy; -import io.gitlab.jfronny.gson.FieldAttributes; -import net.fabricmc.api.EnvType; -import net.fabricmc.loader.api.FabricLoader; - -public class HiddenAnnotationExclusionStrategy implements ExclusionStrategy { - public boolean shouldSkipClass(Class clazz) { - return false; - } - public boolean shouldSkipField(FieldAttributes fieldAttributes) { - return FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT - ? fieldAttributes.getAnnotation(ServerOnly.class) != null - : fieldAttributes.getAnnotation(ClientOnly.class) != null; - } - - public static void register() { - GsonHolders.applyTransform(builder -> builder.setExclusionStrategies(new HiddenAnnotationExclusionStrategy())); - } -} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ServerOnly.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ServerOnly.java deleted file mode 100644 index 4523b51..0000000 --- a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/gson/ServerOnly.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.gitlab.jfronny.libjf.gson; - -import java.lang.annotation.*; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ServerOnly { -} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/FabricLoaderDataMapper.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/FabricLoaderDataMapper.java new file mode 100644 index 0000000..8eda0f6 --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/FabricLoaderDataMapper.java @@ -0,0 +1,30 @@ +package io.gitlab.jfronny.libjf.serialize; + +import io.gitlab.jfronny.commons.serialize.emulated.DataElement; +import net.fabricmc.loader.api.metadata.CustomValue; + +import java.util.Map; + +public class FabricLoaderDataMapper { + public static DataElement toGson(CustomValue customValue) { + if (customValue == null) return null; + return switch (customValue.getType()) { + case OBJECT -> { + DataElement.Object jo = new DataElement.Object(); + for (Map.Entry value : customValue.getAsObject()) + jo.members().put(value.getKey(), toGson(value.getValue())); + yield jo; + } + case ARRAY -> { + DataElement.Array jo = new DataElement.Array(); + for (CustomValue value : customValue.getAsArray()) + jo.elements().add(toGson(value)); + yield jo; + } + case STRING -> new DataElement.Primitive.String(customValue.getAsString()); + case NUMBER -> new DataElement.Primitive.Number(customValue.getAsNumber()); + case BOOLEAN -> new DataElement.Primitive.Boolean(customValue.getAsBoolean()); + case NULL -> new DataElement.Null(); + }; + } +} diff --git a/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/SerializationMode.java b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/SerializationMode.java new file mode 100644 index 0000000..4bba7af --- /dev/null +++ b/libjf-base/src/main/java/io/gitlab/jfronny/libjf/serialize/SerializationMode.java @@ -0,0 +1,24 @@ +package io.gitlab.jfronny.libjf.serialize; + +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.SerializeWriter; +import io.gitlab.jfronny.commons.serialize.json.JsonWriter; + +public class SerializationMode { + public static > void asConfig(Reader reader) { + reader.setLenient(true) + .setSerializeSpecialFloatingPointValues(true); + } + + public static > void asConfig(Writer writer) { + writer.setLenient(true) + .setSerializeSpecialFloatingPointValues(true) + .setSerializeNulls(true); + if (writer instanceof JsonWriter jw) { + jw.setIndent(" ") + .setNewline("\n") + .setOmitQuotes(true) + .setCommentUnexpectedNames(true); + } + } +} diff --git a/libjf-config-compiler-plugin-v2/build.gradle.kts b/libjf-config-compiler-plugin-v2/build.gradle.kts index 30066b6..e0a2de9 100644 --- a/libjf-config-compiler-plugin-v2/build.gradle.kts +++ b/libjf-config-compiler-plugin-v2/build.gradle.kts @@ -14,11 +14,12 @@ repositories { } dependencies { - implementation(libs.gson.compile.processor.core) + implementation(libs.commons.serialize.generator.core) implementation(devProject(":libjf-config-core-v2")) implementation(libs.annotations) implementation(libs.commons) - implementation(libs.commons.serialize.gson) + implementation(libs.commons.serialize.databind) + implementation(libs.commons.serialize.json) implementation(libs.javapoet) testAnnotationProcessor(sourceSets.main.get().output) configurations.testAnnotationProcessor.get().extendsFrom(configurations.implementation.get()) diff --git a/libjf-config-compiler-plugin-v2/src/main/java/io/gitlab/jfronny/libjf/config/plugin/ConfigProcessor.java b/libjf-config-compiler-plugin-v2/src/main/java/io/gitlab/jfronny/libjf/config/plugin/ConfigProcessor.java index e2568b1..9bdc876 100644 --- a/libjf-config-compiler-plugin-v2/src/main/java/io/gitlab/jfronny/libjf/config/plugin/ConfigProcessor.java +++ b/libjf-config-compiler-plugin-v2/src/main/java/io/gitlab/jfronny/libjf/config/plugin/ConfigProcessor.java @@ -2,8 +2,8 @@ package io.gitlab.jfronny.libjf.config.plugin; import com.squareup.javapoet.*; import io.gitlab.jfronny.commons.StringFormatter; -import io.gitlab.jfronny.gson.compile.processor.core.*; -import io.gitlab.jfronny.gson.reflect.TypeToken; +import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken; +import io.gitlab.jfronny.commons.serialize.generator.core.*; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.api.v2.dsl.DSL; import io.gitlab.jfronny.libjf.config.api.v2.type.Type; diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java index a6c880a..e60eea1 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/EntryInfo.java @@ -1,6 +1,7 @@ package io.gitlab.jfronny.libjf.config.api.v2; -import io.gitlab.jfronny.gson.stream.*; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.SerializeWriter; import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.impl.dsl.DslEntryInfo; import org.jetbrains.annotations.ApiStatus; @@ -68,13 +69,13 @@ public interface EntryInfo { * Set this entry's value to that of the element * @param reader The reader to read from */ - void loadFromJson(JsonReader reader) throws IOException, IllegalAccessException; + > void loadFromJson(Reader reader) throws TEx, IllegalAccessException; /** * Write the currently cached value to the writer * @param writer The writer to write to */ - void writeTo(JsonWriter writer, String translationPrefix) throws IOException, IllegalAccessException; + > void writeTo(Writer writer, String translationPrefix) throws TEx, IllegalAccessException; /** * @return Get the width for this entry diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java index 31c752c..2791840 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/api/v2/dsl/Migration.java @@ -1,10 +1,10 @@ package io.gitlab.jfronny.libjf.config.api.v2.dsl; -import io.gitlab.jfronny.gson.stream.JsonReader; +import io.gitlab.jfronny.commons.serialize.SerializeReader; import java.io.IOException; @FunctionalInterface public interface Migration { - void apply(JsonReader reader) throws IOException; + > void apply(Reader reader) throws IOException; } diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/AuxiliaryMetadata.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/AuxiliaryMetadata.java index e6b8a0a..75223df 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/AuxiliaryMetadata.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/AuxiliaryMetadata.java @@ -1,16 +1,17 @@ package io.gitlab.jfronny.libjf.config.impl; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; +import io.gitlab.jfronny.commons.serialize.emulated.DataElement; import io.gitlab.jfronny.libjf.config.api.v2.Category; import io.gitlab.jfronny.libjf.config.api.v2.JfConfig; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; -import io.gitlab.jfronny.libjf.gson.FabricLoaderGsonGenerator; +import io.gitlab.jfronny.libjf.serialize.FabricLoaderDataMapper; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.metadata.CustomValue; import org.jetbrains.annotations.Nullable; import java.util.LinkedList; import java.util.List; +import java.util.Map; import static io.gitlab.jfronny.libjf.config.impl.ConfigCore.MODULE_ID; @@ -43,11 +44,30 @@ public class AuxiliaryMetadata { cv = cv.getAsObject().get("config"); } } - if (cv != null) metaRef.meta = GsonHolders.API.getGson().fromJson(FabricLoaderGsonGenerator.toGson(cv), AuxiliaryMetadata.class); + if (cv != null) metaRef.meta = read(FabricLoaderDataMapper.toGson(cv)); }); return metaRef.meta; } + public static AuxiliaryMetadata read(DataElement data) { + if (!(data instanceof DataElement.Object obj)) throw new IllegalArgumentException("AuxiliaryMetadata must be an object"); + AuxiliaryMetadata meta = new AuxiliaryMetadata(); + for (Map.Entry entry : obj.members().entrySet()) { + switch (entry.getKey()) { + case "referencedConfigs" -> { + if (!(entry.getValue() instanceof DataElement.Array arr)) throw new IllegalArgumentException("referencedConfigs must be an array"); + meta.referencedConfigs = new LinkedList<>(); + arr.elements().forEach(element -> { + if (!(element instanceof DataElement.Primitive.String str)) throw new IllegalArgumentException("referencedConfigs must be an array of strings"); + meta.referencedConfigs.add(str.value()); + }); + } + default -> throw new IllegalArgumentException("Unknown key in AuxiliaryMetadata: " + entry.getKey()); + } + } + return meta; + } + public List referencedConfigs; public void applyTo(CategoryBuilder builder) { diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java index 4babb6e..1c7f816 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; +import io.gitlab.jfronny.commons.serialize.SerializeReader; import io.gitlab.jfronny.commons.throwable.Coerce; -import io.gitlab.jfronny.gson.stream.JsonReader; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; @@ -21,7 +21,8 @@ public class CategoryBuilderImpl> i public final Map> presets = new LinkedHashMap<>(); public final List>> referencedConfigs = new LinkedList<>(); public final List> verifiers = new LinkedList<>(); - public final Map> migrations = new LinkedHashMap<>(); + @SuppressWarnings("rawtypes") // recursive types aren't really needed here + public final Map> migrations = new LinkedHashMap<>(); private boolean built = false; public CategoryBuilderImpl(String id, String categoryPath) { @@ -174,7 +175,7 @@ public class CategoryBuilderImpl> i public Builder addMigration(String element, Migration migration) { checkBuilt(); if (migrations.containsKey(element)) LibJf.LOGGER.warn("Duplicate migration registered for " + categoryPath + id + ": " + element + ", overriding"); - migrations.put(element, Coerce.consumer(migration::apply).addHandler(e -> LibJf.LOGGER.error("Could not apply migration for " + element, e))); + migrations.put(element, Coerce.consumer(migration::apply).addHandler(e -> LibJf.LOGGER.error("Could not apply migration for " + element, e))); return asBuilder(); } diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java index 26c9389..98ec729 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java @@ -1,12 +1,14 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; -import io.gitlab.jfronny.gson.*; -import io.gitlab.jfronny.gson.stream.*; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.Token; +import io.gitlab.jfronny.commons.serialize.json.JsonReader; +import io.gitlab.jfronny.commons.serialize.json.JsonWriter; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.impl.entrypoint.JfConfigSafe; import io.gitlab.jfronny.libjf.config.impl.watch.JfConfigWatchService; +import io.gitlab.jfronny.libjf.serialize.SerializationMode; import java.io.*; import java.nio.file.Files; @@ -19,7 +21,8 @@ public class DefaultConfigIO { // Actions cannot be cached since entries can change if (Files.exists(path)) { try (BufferedReader br = Files.newBufferedReader(path); - JsonReader jr = GsonHolders.CONFIG.getGson().newJsonReader(br)) { + JsonReader jr = new JsonReader(br)) { + SerializationMode.asConfig(jr); runActions(id, createActions(c), jr); } catch (Exception e) { LibJf.LOGGER.error("Could not read config for " + id, e); @@ -29,21 +32,21 @@ public class DefaultConfigIO { }); } - record Action(Consumer task, boolean required) { - public Action(Consumer task) { + record Action(Consumer task, boolean required) { + public Action(Consumer task) { this(task, true); } } - private static void runActions(String id, Map actions, JsonReader reader) { + private static > void runActions(String id, Map actions, Reader reader) { try { - if (reader.peek() != JsonToken.BEGIN_OBJECT) { + if (reader.peek() != Token.BEGIN_OBJECT) { LibJf.LOGGER.error("Invalid config: Not a JSON object for " + id); return; } Set appeared = new HashSet<>(); reader.beginObject(); - while (reader.peek() != JsonToken.END_OBJECT) { + while (reader.peek() != Token.END_OBJECT) { String name = reader.nextName(); if (!actions.containsKey(name)) { LibJf.LOGGER.warn("Unrecognized key in config for " + id + ": " + name); @@ -61,8 +64,8 @@ public class DefaultConfigIO { LibJf.LOGGER.error("Missing entry in config for " + id + ": " + name); } }); - } catch (IOException e) { - throw new JsonParseException("Could not read config", e); + } catch (Exception e) { + throw new IllegalStateException("Could not read config", e); } } @@ -71,7 +74,7 @@ public class DefaultConfigIO { category.getEntries().forEach(entry -> actions.putIfAbsent(entry.getName(), new Action(reader -> { try { entry.loadFromJson(reader); - } catch (IllegalAccessException | IOException e) { + } catch (Exception e) { LibJf.LOGGER.error("Could not set config entry value of " + entry.getName(), e); } }))); @@ -91,7 +94,8 @@ public class DefaultConfigIO { public static Consumer writer(String id) { return c -> c.getFilePath().ifPresent(path -> JfConfigWatchService.lock(path, () -> { try (BufferedWriter bw = Files.newBufferedWriter(path); - JsonWriter jw = GsonHolders.CONFIG.getGson().newJsonWriter(bw)) { + JsonWriter jw = new JsonWriter(bw)) { + SerializationMode.asConfig(jw); writeTo(jw, c); } catch (Exception e) { LibJf.LOGGER.error("Could not write config for " + id, e); diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java index 9eb471e..64b8255 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.gson.stream.JsonReader; +import io.gitlab.jfronny.commons.serialize.SerializeReader; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; import org.jetbrains.annotations.ApiStatus; @@ -17,7 +17,7 @@ public class DslConfigCategory implements ConfigCategory { private final List> entries; private final Map presets; private final List>> referencedConfigs; - @ApiStatus.Internal public final Map> migrations; + @ApiStatus.Internal public final Map> migrations; private final Map categories; private final Supplier root; private final List> verifiers; @@ -31,7 +31,7 @@ public class DslConfigCategory implements ConfigCategory { List> categories, Supplier root, List> verifiers, - Map> migrations) { + Map> migrations) { this.id = id; this.categoryPath = categoryPath; this.translationPrefix = translationPrefix; diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java index 6e7a294..1e7990d 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.gson.stream.JsonReader; +import io.gitlab.jfronny.commons.serialize.SerializeReader; import io.gitlab.jfronny.libjf.config.api.v2.*; import io.gitlab.jfronny.libjf.config.api.v2.dsl.CategoryBuilder; import org.jetbrains.annotations.Nullable; @@ -23,7 +23,7 @@ public class DslConfigInstance extends DslConfigCategory implements ConfigInstan List> categories, Supplier root, List> verifiers, - Map> migrations, + Map> migrations, Consumer load, Consumer write, @Nullable Path path) { diff --git a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java index 81c4f43..7a2454d 100644 --- a/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java +++ b/libjf-config-core-v2/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java @@ -1,16 +1,19 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; +import io.gitlab.jfronny.commons.Serializer; +import io.gitlab.jfronny.commons.serialize.MalformedDataException; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.SerializeWriter; +import io.gitlab.jfronny.commons.serialize.Token; +import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken; import io.gitlab.jfronny.commons.throwable.ThrowingConsumer; import io.gitlab.jfronny.commons.throwable.ThrowingSupplier; -import io.gitlab.jfronny.gson.stream.*; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.Entry; import io.gitlab.jfronny.libjf.config.api.v2.EntryInfo; import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.impl.entrypoint.JfConfigSafe; -import java.io.IOException; import java.lang.reflect.Field; import java.util.Arrays; import java.util.Objects; @@ -127,38 +130,42 @@ public class DslEntryInfo implements EntryInfo { } @Override - public void loadFromJson(JsonReader reader) throws IOException, IllegalAccessException { + public > void loadFromJson(Reader reader) throws TEx, IllegalAccessException { var next = reader.peek(); if (type.isBool()) { - if (next == JsonToken.BOOLEAN) setUnchecked(reader.nextBoolean()); + if (next == Token.BOOLEAN) setUnchecked(reader.nextBoolean()); else LibJf.LOGGER.error("Unexpected value for " + name + ": expected boolean but got " + next); } else if (type.isString()) { - if (next == JsonToken.STRING || next == JsonToken.NUMBER) setUnchecked(reader.nextString()); - else if (next == JsonToken.BOOLEAN) setUnchecked(Boolean.toString(reader.nextBoolean())); - else if (next == JsonToken.NULL) { + if (next == Token.STRING || next == Token.NUMBER) setUnchecked(reader.nextString()); + else if (next == Token.BOOLEAN) setUnchecked(Boolean.toString(reader.nextBoolean())); + else if (next == Token.NULL) { reader.nextNull(); setUnchecked(null); } else LibJf.LOGGER.error("Unexpected value for " + name + ": expected string but got " + next); } else if (type.isInt()) { - if (next == JsonToken.NUMBER) setUnchecked(reader.nextInt()); + if (next == Token.NUMBER) setUnchecked(reader.nextInt()); else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isLong()) { - if (next == JsonToken.NUMBER) setUnchecked(reader.nextLong()); + if (next == Token.NUMBER) setUnchecked(reader.nextLong()); else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isDouble()) { - if (next == JsonToken.NUMBER) { + if (next == Token.NUMBER) { setUnchecked(reader.nextDouble()); } else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isFloat()) { - if (next == JsonToken.NUMBER) setUnchecked((float) reader.nextDouble()); + if (next == Token.NUMBER) setUnchecked((float) reader.nextDouble()); else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isEnum()) { Type.TEnum e = (Type.TEnum) type; - if (next == JsonToken.STRING) setUnchecked(e.optionForString(reader.nextString())); + if (next == Token.STRING) setUnchecked(e.optionForString(reader.nextString())); else LibJf.LOGGER.error("Unexpected value for " + name + ": expected string but got " + next); } else { - setValue(GsonHolders.CONFIG.getGson().fromJson(reader, type.asClass())); + try { + setValue((T) LibJf.MAPPER.getAdapter(TypeToken.get(type.asClass())).deserialize(reader)); + } catch (MalformedDataException e) { + LibJf.LOGGER.error("Could not read " + name, e); + } } } @@ -169,7 +176,7 @@ public class DslEntryInfo implements EntryInfo { } @Override - public void writeTo(JsonWriter writer, String translationPrefix) throws IOException, IllegalAccessException { + public > void writeTo(Writer writer, String translationPrefix) throws TEx, IllegalAccessException { T value = getValue(); String commentText; if ((commentText = JfConfigSafe.TRANSLATION_SUPPLIER.apply(translationPrefix + getName() + ".tooltip")) != null) { @@ -179,7 +186,11 @@ public class DslEntryInfo implements EntryInfo { writer.comment("Valid: [" + Arrays.stream(((Type.TEnum)type).options()).map(Objects::toString).collect(Collectors.joining(", ")) + "]"); } writer.name(name); - GsonHolders.CONFIG.getGson().toJson(value, Objects.requireNonNullElse(type.asClass(), String.class), writer); + try { + LibJf.MAPPER.getAdapter((TypeToken) TypeToken.get(Objects.requireNonNullElse(type.asClass(), String.class))).serialize(value, writer); + } catch (MalformedDataException e) { + LibJf.LOGGER.error("Could not write " + name, e); + } } @Override diff --git a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/rci/entry/MirrorEntryInfoBase.java b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/rci/entry/MirrorEntryInfoBase.java index 7082a48..84f70d4 100644 --- a/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/rci/entry/MirrorEntryInfoBase.java +++ b/libjf-config-network-v0/src/main/java/io/gitlab/jfronny/libjf/config/impl/network/rci/entry/MirrorEntryInfoBase.java @@ -1,18 +1,14 @@ package io.gitlab.jfronny.libjf.config.impl.network.rci.entry; -import io.gitlab.jfronny.gson.stream.JsonReader; -import io.gitlab.jfronny.gson.stream.JsonWriter; +import io.gitlab.jfronny.commons.serialize.SerializeReader; +import io.gitlab.jfronny.commons.serialize.SerializeWriter; import io.gitlab.jfronny.libjf.config.api.v2.EntryInfo; -import io.gitlab.jfronny.libjf.config.api.v2.type.Type; import io.gitlab.jfronny.libjf.config.impl.network.rci.MirrorConfigCategory; import io.gitlab.jfronny.libjf.config.impl.network.rci.MirrorObject; import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; import net.fabricmc.fabric.api.networking.v1.PacketSender; import net.minecraft.network.PacketByteBuf; -import java.io.IOException; -import java.io.UnsupportedEncodingException; - public abstract class MirrorEntryInfoBase extends MirrorObject implements EntryInfo { protected final MirrorConfigCategory category; protected final String entryName; @@ -34,13 +30,13 @@ public abstract class MirrorEntryInfoBase extends MirrorObject implements Ent } @Override - public void loadFromJson(JsonReader reader) throws IOException, IllegalAccessException { - throw new UnsupportedEncodingException(); + public > void loadFromJson(Reader reader) { + throw new UnsupportedOperationException(); } @Override - public void writeTo(JsonWriter writer, String translationPrefix) throws IOException, IllegalAccessException { - throw new UnsupportedEncodingException(); + public > void writeTo(Writer writer, String translationPrefix) { + throw new UnsupportedOperationException(); } @Override @@ -51,7 +47,7 @@ public abstract class MirrorEntryInfoBase extends MirrorObject implements Ent } @Override - public void reset() throws IllegalAccessException { + public void reset() { PacketByteBuf buf = PacketByteBufs.create(); writePath(buf); sendRequest("resetEntry", buf); diff --git a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreenFactory.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreenFactory.java index 8cfeb05..7601ce9 100644 --- a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreenFactory.java +++ b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/TinyConfigScreenFactory.java @@ -1,6 +1,6 @@ package io.gitlab.jfronny.libjf.config.impl.ui.tiny; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; +import io.gitlab.jfronny.commons.Serializer; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.ConfigInstance; import io.gitlab.jfronny.libjf.config.api.v2.EntryInfo; @@ -13,6 +13,8 @@ import net.minecraft.client.resource.language.I18n; import net.minecraft.client.toast.SystemToast; import net.minecraft.text.Text; +import java.io.IOException; + // IDEA doesn't like this, but it does work in practice public class TinyConfigScreenFactory implements ConfigScreenFactory { @Override @@ -26,8 +28,9 @@ public class TinyConfigScreenFactory implements ConfigScreenFactory LibJf.MAPPER.serialize(value, writer)); + } catch (IllegalAccessException | IOException e) { throw new RuntimeException(e); } String key = config.getTranslationPrefix() + entry.getName(); @@ -38,7 +41,7 @@ public class TinyConfigScreenFactory implements ConfigScreenFactory { try { - entry.setValue(GsonHolders.CONFIG.getGson().fromJson(json, type.asClass())); + entry.setValue(Serializer.getInstance().deserialize(json, type.asClass())); config.write(); } catch (Throwable e) { LibJf.LOGGER.error("Could not write element", e); diff --git a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryInfoWidgetBuilder.java b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryInfoWidgetBuilder.java index 842add5..daa6e23 100644 --- a/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryInfoWidgetBuilder.java +++ b/libjf-config-ui-tiny/src/client/java/io/gitlab/jfronny/libjf/config/impl/ui/tiny/entry/EntryInfoWidgetBuilder.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.libjf.config.impl.ui.tiny.entry; +import io.gitlab.jfronny.commons.Serializer; import io.gitlab.jfronny.commons.ref.R; -import io.gitlab.jfronny.commons.serialize.gson.api.v2.GsonHolders; import io.gitlab.jfronny.commons.throwable.Try; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v2.ConfigCategory; @@ -171,7 +171,7 @@ public class EntryInfoWidgetBuilder { final String jsonified; if (state.tempValue == null) { try { - jsonified = GsonHolders.CONFIG.getGson().toJson(state.cachedValue); + jsonified = Serializer.getInstance().serialize(state.cachedValue); } catch (Throwable e) { LibJf.LOGGER.error("Could not stringify element", e); SystemToast.add( @@ -193,7 +193,7 @@ public class EntryInfoWidgetBuilder { jsonified, json -> { try { - state.updateCache(GsonHolders.CONFIG.getGson().fromJson(json, info.getValueType().asClass())); + state.updateCache(Serializer.getInstance().deserialize(json, info.getValueType().asClass())); state.tempValue = null; } catch (Throwable e) { LibJf.LOGGER.error("Could not write element", e); diff --git a/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/libretranslate/LibreTranslateService.java b/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/libretranslate/LibreTranslateService.java index a6aae00..628dc1d 100644 --- a/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/libretranslate/LibreTranslateService.java +++ b/libjf-translate-v1/src/main/java/io/gitlab/jfronny/libjf/translate/impl/libretranslate/LibreTranslateService.java @@ -1,7 +1,7 @@ package io.gitlab.jfronny.libjf.translate.impl.libretranslate; import io.gitlab.jfronny.commons.http.client.HttpClient; -import io.gitlab.jfronny.gson.reflect.TypeToken; +import io.gitlab.jfronny.commons.serialize.databind.api.TypeToken; import io.gitlab.jfronny.libjf.translate.api.TranslateException; import io.gitlab.jfronny.libjf.translate.impl.AbstractTranslateService; import io.gitlab.jfronny.libjf.translate.impl.libretranslate.model.*;