diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/EntryInfo.java b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/EntryInfo.java index 6f23b9a..cc2cfbb 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/EntryInfo.java +++ b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/EntryInfo.java @@ -1,7 +1,8 @@ package io.gitlab.jfronny.libjf.config.api.v1; import io.gitlab.jfronny.gson.JsonElement; -import io.gitlab.jfronny.gson.stream.JsonWriter; +import io.gitlab.jfronny.gson.JsonParseException; +import io.gitlab.jfronny.gson.stream.*; import io.gitlab.jfronny.libjf.config.api.v1.type.Type; import io.gitlab.jfronny.libjf.config.impl.dsl.DslEntryInfo; import org.jetbrains.annotations.ApiStatus; @@ -61,7 +62,20 @@ public interface EntryInfo { * Set this entry's value to that of the element * @param element The element to read from */ - void loadFromJson(JsonElement element) throws IllegalAccessException; + @Deprecated + default void loadFromJson(JsonElement element) throws IllegalAccessException { + try { + loadFromJson(new JsonTreeReader(element)); + } catch (IOException e) { + throw new JsonParseException("Could not read Json", e); + } + } + + /** + * Set this entry's value to that of the element + * @param reader The reader to read from + */ + void loadFromJson(JsonReader reader) throws IOException, IllegalAccessException; /** * Write the currently cached value to the writer diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java index 9475e0d..fa9c7b0 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java +++ b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/CategoryBuilder.java @@ -1,6 +1,7 @@ package io.gitlab.jfronny.libjf.config.api.v1.dsl; import io.gitlab.jfronny.gson.JsonElement; +import io.gitlab.jfronny.gson.stream.JsonReader; import io.gitlab.jfronny.libjf.config.api.v1.*; import io.gitlab.jfronny.libjf.config.api.v1.type.Type; import org.jetbrains.annotations.ApiStatus; @@ -38,7 +39,7 @@ public interface CategoryBuilder> { Builder value(String id, T def, double min, double max, Type type, int width, Supplier get, Consumer set); Builder value(EntryInfo entry); - @ApiStatus.Experimental Builder addMigration(String element, Consumer apply); + @ApiStatus.Experimental Builder addMigration(String element, Migration migration); String getId(); diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/Migration.java b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/Migration.java new file mode 100644 index 0000000..01973d8 --- /dev/null +++ b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/api/v1/dsl/Migration.java @@ -0,0 +1,10 @@ +package io.gitlab.jfronny.libjf.config.api.v1.dsl; + +import io.gitlab.jfronny.gson.stream.JsonReader; + +import java.io.IOException; + +@FunctionalInterface +public interface Migration { + void apply(JsonReader reader) throws IOException; +} diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java index bf1e6d4..eb5bb9a 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java +++ b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/CategoryBuilderImpl.java @@ -1,9 +1,11 @@ package io.gitlab.jfronny.libjf.config.impl.dsl; -import io.gitlab.jfronny.gson.JsonElement; +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.v1.*; import io.gitlab.jfronny.libjf.config.api.v1.dsl.CategoryBuilder; +import io.gitlab.jfronny.libjf.config.api.v1.dsl.Migration; import io.gitlab.jfronny.libjf.config.api.v1.type.Type; import java.util.*; @@ -19,7 +21,7 @@ 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<>(); + public final Map> migrations = new LinkedHashMap<>(); private boolean built = false; public CategoryBuilderImpl(String id, String categoryPath) { @@ -169,10 +171,10 @@ public class CategoryBuilderImpl> i } @Override - public Builder addMigration(String element, Consumer apply) { + 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, apply); + 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-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java index cc4d617..7af6aac 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java +++ b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DefaultConfigIO.java @@ -37,28 +37,30 @@ public class DefaultConfigIO { private static void runActions(String id, Map actions, JsonReader reader) { try { - if (reader.peek() == JsonToken.BEGIN_OBJECT) { - Set appeared = new HashSet<>(); - reader.beginObject(); - while (reader.peek() != JsonToken.END_OBJECT) { - String name = reader.nextName(); - if (!actions.containsKey(name)) { - LibJf.LOGGER.warn("Unrecognized key in config for " + id + ": " + name); - continue; - } - if (!appeared.add(name)) { - LibJf.LOGGER.warn("Duplicate key in config for " + id + ": " + name); - continue; - } - actions.get(name).task.accept(reader); + if (reader.peek() != JsonToken.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) { + String name = reader.nextName(); + if (!actions.containsKey(name)) { + LibJf.LOGGER.warn("Unrecognized key in config for " + id + ": " + name); + continue; } - reader.endObject(); - actions.forEach((name, action) -> { - if (action.required && !appeared.contains(name)) { - LibJf.LOGGER.error("Missing entry in config for " + id + ": " + name); - } - }); - } LibJf.LOGGER.error("Invalid config: Not a JSON object for " + id); + if (!appeared.add(name)) { + LibJf.LOGGER.warn("Duplicate key in config for " + id + ": " + name); + continue; + } + actions.get(name).task.accept(reader); + } + reader.endObject(); + actions.forEach((name, action) -> { + if (action.required && !appeared.contains(name)) { + LibJf.LOGGER.error("Missing entry in config for " + id + ": " + name); + } + }); } catch (IOException e) { throw new JsonParseException("Could not read config", e); } @@ -68,8 +70,8 @@ public class DefaultConfigIO { Map actions = new HashMap<>(); category.getEntries().forEach(entry -> actions.putIfAbsent(entry.getName(), new Action(reader -> { try { - entry.loadFromJson(JsonParser.parseReader(reader)); - } catch (IllegalAccessException e) { + entry.loadFromJson(reader); + } catch (IllegalAccessException | IOException e) { LibJf.LOGGER.error("Could not set config entry value of " + entry.getName(), e); } }))); @@ -80,9 +82,7 @@ public class DefaultConfigIO { }); if (category instanceof DslConfigCategory cat) { cat.migrations.forEach((id, migration) -> { - actions.putIfAbsent(id, new Action(reader -> { - migration.accept(JsonParser.parseReader(reader)); - }, false)); + actions.putIfAbsent(id, new Action(migration, false)); }); } return Map.copyOf(actions); diff --git a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java index 6a01bb6..b5e3d85 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigCategory.java +++ b/libjf-config-core-v1/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.JsonElement; +import io.gitlab.jfronny.gson.stream.JsonReader; import io.gitlab.jfronny.libjf.config.api.v1.*; import io.gitlab.jfronny.libjf.config.api.v1.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-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java index 050a4ac..d997e68 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslConfigInstance.java +++ b/libjf-config-core-v1/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.JsonElement; +import io.gitlab.jfronny.gson.stream.JsonReader; import io.gitlab.jfronny.libjf.config.api.v1.*; import io.gitlab.jfronny.libjf.config.api.v1.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-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java index 02bf342..d92cd9d 100644 --- a/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java +++ b/libjf-config-core-v1/src/main/java/io/gitlab/jfronny/libjf/config/impl/dsl/DslEntryInfo.java @@ -4,7 +4,7 @@ import io.gitlab.jfronny.commons.serialize.gson.api.v1.GsonHolders; import io.gitlab.jfronny.commons.throwable.ThrowingConsumer; import io.gitlab.jfronny.commons.throwable.ThrowingSupplier; import io.gitlab.jfronny.gson.JsonElement; -import io.gitlab.jfronny.gson.stream.JsonWriter; +import io.gitlab.jfronny.gson.stream.*; import io.gitlab.jfronny.libjf.LibJf; import io.gitlab.jfronny.libjf.config.api.v1.Entry; import io.gitlab.jfronny.libjf.config.api.v1.EntryInfo; @@ -128,38 +128,36 @@ public class DslEntryInfo implements EntryInfo { } @Override - public void loadFromJson(JsonElement element) throws IllegalAccessException { + public void loadFromJson(JsonReader reader) throws IOException, IllegalAccessException { + var next = reader.peek(); if (type.isBool()) { - if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isBoolean()) { - setUnchecked(element.getAsBoolean()); - } + if (next == JsonToken.BOOLEAN) setUnchecked(reader.nextBoolean()); + else LibJf.LOGGER.error("Unexpected value for " + name + ": expected boolean but got " + next); } else if (type.isString()) { - if (element.isJsonPrimitive()) { - setUnchecked(element.getAsString()); - } + 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) setUnchecked(null); + else LibJf.LOGGER.error("Unexpected value for " + name + ": expected string but got " + next); } else if (type.isInt()) { - if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) { - setUnchecked(element.getAsNumber().intValue()); - } + if (next == JsonToken.NUMBER) setUnchecked(reader.nextInt()); + else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isLong()) { - if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) { - setUnchecked(element.getAsNumber().longValue()); - } + if (next == JsonToken.NUMBER) setUnchecked(reader.nextLong()); + else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isDouble()) { - if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) { - setUnchecked(element.getAsNumber().doubleValue()); + if (next == JsonToken.NUMBER) { + setUnchecked(reader.nextDouble()); } + else LibJf.LOGGER.error("Unexpected value for " + name + ": expected number but got " + next); } else if (type.isFloat()) { - if (element.isJsonPrimitive() && element.getAsJsonPrimitive().isNumber()) { - setUnchecked(element.getAsNumber().floatValue()); - } + if (next == JsonToken.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 (element.isJsonPrimitive() && element.getAsJsonPrimitive().isString()) { - setUnchecked(e.optionForString(element.getAsString())); - } + if (next == JsonToken.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(element, type.asClass())); + setValue(GsonHolders.CONFIG.getGson().fromJson(reader, type.asClass())); } } diff --git a/libjf-config-reflect-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/reflect/TestConfigTweaker.java b/libjf-config-reflect-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/reflect/TestConfigTweaker.java index 1a96bb3..f1c74f3 100644 --- a/libjf-config-reflect-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/reflect/TestConfigTweaker.java +++ b/libjf-config-reflect-v1/src/testmod/java/io/gitlab/jfronny/libjf/config/test/reflect/TestConfigTweaker.java @@ -9,8 +9,8 @@ public class TestConfigTweaker { public static ConfigBuilder tweak(ConfigBuilder builder) { if (!Objects.equals("libjf-config-reflect-v1-testmod", builder.getId())) throw new IllegalStateException("No!"); LibJf.LOGGER.info("Called config tweaker"); - return builder.addMigration("joe", jsonElement -> { - TestConfig.disablePacks = jsonElement.getAsJsonPrimitive().getAsBoolean(); + return builder.addMigration("joe", reader -> { + TestConfig.disablePacks = reader.nextBoolean(); }); } }