From 05ff61a9d9b5d4d8337e73e28841515c1b235d3e Mon Sep 17 00:00:00 2001 From: Carm Date: Wed, 12 Feb 2025 04:25:29 +0800 Subject: [PATCH] feat(json): Implement json sources --- .../configuration/adapter/ValueAdapter.java | 4 +- .../adapter/ValueAdapterRegistry.java | 6 +- .../lib/configuration/adapter/ValueType.java | 42 ++++++- .../adapter/strandard/StandardAdapters.java | 10 +- .../builder/impl/AbstractSectionBuilder.java | 26 ++-- .../builder/impl/AbstractSourceBuilder.java | 12 +- .../builder/list/ConfigListBuilder.java | 2 +- .../builder/list/SectionListBuilder.java | 6 +- .../builder/value/ConfigValueBuilder.java | 8 +- .../builder/value/SectionValueBuilder.java | 6 +- .../configuration/function/ValueHandler.java | 5 + .../source/ConfigurationFactory.java | 112 ++++++++++++------ .../source/ConfigurationHolder.java | 21 ++-- .../loader/ConfigurationInitializer.java | 46 +++---- .../source/loader/PathGenerator.java | 16 +-- .../source/option/StandardOptions.java | 2 +- .../source/section/ConfigurationSource.java | 46 ------- ...tionSection.java => ConfigureSection.java} | 11 +- .../source/section/ConfigureSource.java | 97 +++++++++++++++ .../configuration/value/ValueManifest.java | 6 +- .../value/standard/ConfiguredMap.java | 4 +- .../value/standard/ConfiguredValue.java | 5 + core/src/test/java/AdaptTest.java | 14 ++- core/src/test/java/NameTest.java | 1 + .../java/cc/carm/test/config/LoaderTest.java | 14 ++- .../java/cc/carm/test/config/TestSection.java | 14 ++- .../java/cc/carm/test/config/TestSource.java | 53 ++------- demo/pom.xml | 7 ++ .../demo/DatabaseConfiguration.java | 2 +- .../demo/tests/ConfigurationTest.java | 30 +++-- .../demo/tests/conf/DemoConfiguration.java | 30 +++-- .../demo/tests/conf/TestConfiguration.java | 16 ++- .../tests/conf/TestInnerConfiguration.java | 4 +- .../demo/tests/model/TestModel.java | 3 +- .../source/FileConfigFactory.java | 39 ++++++ .../source/FileConfigSource.java | 25 ++-- pom.xml | 9 +- .../lib/configuration/EasyConfiguration.java | 36 ------ .../configuration/json/JSONConfigFactory.java | 72 +++++++++++ .../json/JSONConfigProvider.java | 73 ------------ .../configuration/json/JSONConfigSource.java | 109 ----------------- ...SONConfigWrapper.java => JSONSection.java} | 64 +++++----- .../lib/configuration/json/JSONSource.java | 80 +++++++++++++ .../src/test/java/config/JSONConfigTest.java | 26 ++-- 44 files changed, 656 insertions(+), 558 deletions(-) delete mode 100644 core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSource.java rename core/src/main/java/cc/carm/lib/configuration/source/section/{ConfigurationSection.java => ConfigureSection.java} (95%) create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSource.java rename providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigurationSection.java => core/src/test/java/cc/carm/test/config/TestSection.java (70%) create mode 100644 features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigFactory.java delete mode 100644 providers/gson/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java create mode 100644 providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigFactory.java delete mode 100644 providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java delete mode 100644 providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigSource.java rename providers/gson/src/main/java/cc/carm/lib/configuration/json/{JSONConfigWrapper.java => JSONSection.java} (58%) create mode 100644 providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSource.java diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapter.java index 190bbcd..9df8f70 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapter.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapter.java @@ -55,13 +55,13 @@ public class ValueAdapter @Override public Object serialize(@NotNull ConfigurationHolder holder, @NotNull ValueType type, @NotNull TYPE value) throws Exception { if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported"); - return serializer.serialize(provider, type, value); + return serializer.serialize(holder, type, value); } @Override public TYPE parse(@NotNull ConfigurationHolder holder, @NotNull ValueType type, @NotNull Object value) throws Exception { if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported"); - return deserializer.parse(provider, type, value); + return deserializer.parse(holder, type, value); } @Override diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapterRegistry.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapterRegistry.java index 1cf7861..f15d6f2 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapterRegistry.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapterRegistry.java @@ -101,7 +101,7 @@ public class ValueAdapterRegistry { @Contract("_,_,null -> null") public T deserialize(@NotNull ConfigurationHolder holder, @NotNull Class type, @Nullable Object source) throws Exception { - return deserialize(provider, ValueType.of(type), source); + return deserialize(holder, ValueType.of(type), source); } @Contract("_,_,null -> null") @@ -110,7 +110,7 @@ public class ValueAdapterRegistry { if (type.isInstance(source)) return type.cast(source); // Not required to deserialize ValueAdapter adapter = adapterOf(type); if (adapter == null) throw new RuntimeException("No adapter for type " + type); - return adapter.parse(provider, type, source); + return adapter.parse(holder, type, source); } @Contract("_,null -> null") @@ -119,7 +119,7 @@ public class ValueAdapterRegistry { ValueType type = ValueType.of(value); ValueAdapter adapter = adapterOf(type); if (adapter == null) return value; // No adapters, try to return the original value - return adapter.serialize(provider, type, value); + return adapter.serialize(holder, type, value); } diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueType.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueType.java index ca2edaf..3a889fa 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueType.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueType.java @@ -3,7 +3,6 @@ package cc.carm.lib.configuration.adapter; import org.jetbrains.annotations.NotNull; import java.lang.reflect.ParameterizedType; - import java.lang.reflect.Type; import java.util.Objects; @@ -12,12 +11,45 @@ import java.util.Objects; */ public abstract class ValueType { + public static final ValueType STRING = ofPrimitiveType(String.class); + public static final ValueType INTEGER = ofPrimitiveType(Integer.class); + public static final ValueType INTEGER_TYPE = ofPrimitiveType(int.class); + public static final ValueType LONG = ofPrimitiveType(Long.class); + public static final ValueType LONG_TYPE = ofPrimitiveType(long.class); + public static final ValueType DOUBLE = ofPrimitiveType(Double.class); + public static final ValueType DOUBLE_TYPE = ofPrimitiveType(double.class); + public static final ValueType FLOAT = ofPrimitiveType(Float.class); + public static final ValueType FLOAT_TYPE = ofPrimitiveType(float.class); + public static final ValueType BOOLEAN = ofPrimitiveType(Boolean.class); + public static final ValueType BOOLEAN_TYPE = ofPrimitiveType(boolean.class); + public static final ValueType BYTE = ofPrimitiveType(Byte.class); + public static final ValueType BYTE_TYPE = ofPrimitiveType(byte.class); + public static final ValueType SHORT = ofPrimitiveType(Short.class); + public static final ValueType SHORT_TYPE = ofPrimitiveType(short.class); + public static final ValueType CHAR = ofPrimitiveType(Character.class); + public static final ValueType CHAR_TYPE = ofPrimitiveType(char.class); + + public static final ValueType[] PRIMITIVE_TYPES = { + STRING, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, BYTE, SHORT, CHAR, + INTEGER_TYPE, LONG_TYPE, DOUBLE_TYPE, FLOAT_TYPE, BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE + }; + @SuppressWarnings("unchecked") public static ValueType of(@NotNull T value) { return of((Class) value.getClass()); } + @SuppressWarnings("unchecked") public static ValueType of(final Type type) { + if (type == null) throw new NullPointerException("Type cannot be null"); + if (type instanceof Class) { // Try handle primitive types + Class clazz = (Class) type; + for (ValueType valueType : PRIMITIVE_TYPES) { + if (valueType.getRawType() == clazz) { + return (ValueType) valueType; + } + } + } return new ValueType(type) { }; } @@ -54,6 +86,11 @@ public abstract class ValueType { return of(parameterizedType); } + private static ValueType ofPrimitiveType(Class clazz) { + return new ValueType(clazz) { + }; + } + private final Type type; protected ValueType() { @@ -139,6 +176,9 @@ public abstract class ValueType { if (obj instanceof ValueType) { return Objects.equals(type, ((ValueType) obj).type); } + if (obj instanceof Type) { + return Objects.equals(type, obj); + } return false; } diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/StandardAdapters.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/StandardAdapters.java index 3b713d5..4b332d5 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/StandardAdapters.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/StandardAdapters.java @@ -2,16 +2,16 @@ package cc.carm.lib.configuration.adapter.strandard; import cc.carm.lib.configuration.adapter.ValueAdapter; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.source.section.ConfigureSection; public interface StandardAdapters { - ValueAdapter SECTION_ADAPTER = new ValueAdapter<>( - ValueType.of(ConfigurationSection.class), + ValueAdapter SECTION_ADAPTER = new ValueAdapter<>( + ValueType.of(ConfigureSection.class), (provider, type, value) -> value, (provider, type, value) -> { - if (value instanceof ConfigurationSection) { - return (ConfigurationSection) value; + if (value instanceof ConfigureSection) { + return (ConfigureSection) value; } else throw new IllegalArgumentException("Value is not a ConfigurationSection"); } ); diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSectionBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSectionBuilder.java index e647a1e..894a97f 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSectionBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSectionBuilder.java @@ -5,7 +5,7 @@ import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.builder.CommonConfigBuilder; import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.function.ValueHandler; -import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.value.ConfigValue; import org.jetbrains.annotations.NotNull; @@ -21,39 +21,39 @@ public abstract class AbstractSectionBuilder< protected final @NotNull ValueType paramType; - protected @NotNull ValueHandler parser; - protected @NotNull ValueHandler> serializer; + protected @NotNull ValueHandler parser; + protected @NotNull ValueHandler> serializer; public AbstractSectionBuilder(@NotNull ValueType type, @NotNull ValueType paramType, - @NotNull ValueHandler parser, - @NotNull ValueHandler> serializer) { + @NotNull ValueHandler parser, + @NotNull ValueHandler> serializer) { super(type); this.paramType = paramType; this.parser = parser; this.serializer = serializer; } - public @NotNull SELF parse(DataFunction valueParser) { + public @NotNull SELF parse(DataFunction valueParser) { return parse((p, section) -> valueParser.handle(section)); } - public @NotNull SELF parse(ValueHandler valueParser) { + public @NotNull SELF parse(ValueHandler valueParser) { this.parser = valueParser; return self(); } - public @NotNull SELF serialize(DataFunction> serializer) { + public @NotNull SELF serialize(DataFunction> serializer) { return serialize((p, value) -> serializer.handle(value)); } - public @NotNull SELF serialize(ValueHandler> serializer) { + public @NotNull SELF serialize(ValueHandler> serializer) { this.serializer = serializer; return self(); } - public @NotNull SELF serialize(Consumer> serializer) { + public @NotNull SELF serialize(Consumer> serializer) { return serialize((p, value) -> { - Map map = new LinkedHashMap<>(); + Map map = new LinkedHashMap<>(); serializer.accept(map); return map; }); @@ -62,12 +62,12 @@ public abstract class AbstractSectionBuilder< protected ValueAdapter buildAdapter() { return new ValueAdapter<>(this.paramType) .parser((p, type, data) -> { - ConfigurationSection section = p.deserialize(ConfigurationSection.class, data); + ConfigureSection section = p.deserialize(ConfigureSection.class, data); if (section == null) return null; return this.parser.handle(p, section); }) .serializer((p, type, data) -> { - Map map = this.serializer.handle(p, data); + Map map = this.serializer.handle(p, data); return map == null || map.isEmpty() ? null : map; }); } diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSourceBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSourceBuilder.java index 2ec78b0..1a4c7b6 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSourceBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSourceBuilder.java @@ -49,13 +49,13 @@ public abstract class AbstractSourceBuilder< protected ValueAdapter buildAdapter() { return new ValueAdapter<>(this.paramType) - .parser((p, type, data) -> { - SOURCE source = p.deserialize(this.sourceType, data); - return this.valueParser.handle(p, source); + .parser((holder, type, data) -> { + SOURCE source = holder.deserialize(this.sourceType, data); + return this.valueParser.handle(holder, source); }) - .serializer((p, type, data) -> { - SOURCE source = this.valueSerializer.handle(p, data); - return p.serialize(source); + .serializer((holder, type, data) -> { + SOURCE source = this.valueSerializer.handle(holder, data); + return holder.serialize(source); }); } diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/list/ConfigListBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/list/ConfigListBuilder.java index e78082c..c2099da 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/list/ConfigListBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/list/ConfigListBuilder.java @@ -23,7 +23,7 @@ public class ConfigListBuilder { } public @NotNull SourceListBuilder fromString() { - return from(String.class); + return new SourceListBuilder<>(ValueType.STRING, type, ValueHandler.required(), ValueHandler.stringValue(), ArrayList::new); } public @NotNull SectionListBuilder fromSection() { diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/list/SectionListBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/list/SectionListBuilder.java index 929cfe9..356a0b9 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/list/SectionListBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/list/SectionListBuilder.java @@ -3,7 +3,7 @@ package cc.carm.lib.configuration.builder.list; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.builder.impl.AbstractSectionBuilder; import cc.carm.lib.configuration.function.ValueHandler; -import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.value.standard.ConfiguredList; import org.jetbrains.annotations.NotNull; @@ -15,8 +15,8 @@ public class SectionListBuilder extends AbstractSectionBuilder, V, Co protected @NotNull Supplier> constructor; public SectionListBuilder(@NotNull ValueType paramType, - @NotNull ValueHandler parser, - @NotNull ValueHandler> serializer, + @NotNull ValueHandler parser, + @NotNull ValueHandler> serializer, @NotNull Supplier> constructor) { super(new ValueType>() { }, paramType, parser, serializer); diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/value/ConfigValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/value/ConfigValueBuilder.java index c3ee264..cad8557 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/value/ConfigValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/ConfigValueBuilder.java @@ -2,7 +2,7 @@ package cc.carm.lib.configuration.builder.value; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.function.ValueHandler; -import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.source.section.ConfigureSection; import org.jetbrains.annotations.NotNull; import java.util.Map; @@ -30,7 +30,7 @@ public class ConfigValueBuilder { } public @NotNull SourceValueBuilder fromString() { - return from(String.class); + return from(ValueType.STRING, ValueHandler.required(), ValueHandler.stringValue()); } public @NotNull SectionValueBuilder fromSection() { @@ -38,8 +38,8 @@ public class ConfigValueBuilder { } public @NotNull SectionValueBuilder fromSection( - @NotNull ValueHandler valueParser, - @NotNull ValueHandler> valueSerializer + @NotNull ValueHandler valueParser, + @NotNull ValueHandler> valueSerializer ) { return new SectionValueBuilder<>(this.type, valueParser, valueSerializer); } diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/value/SectionValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/value/SectionValueBuilder.java index 52019ee..f9653e8 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/value/SectionValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/SectionValueBuilder.java @@ -3,7 +3,7 @@ package cc.carm.lib.configuration.builder.value; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.builder.impl.AbstractSectionBuilder; import cc.carm.lib.configuration.function.ValueHandler; -import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.value.standard.ConfiguredValue; import org.jetbrains.annotations.NotNull; @@ -12,8 +12,8 @@ import java.util.Map; public class SectionValueBuilder extends AbstractSectionBuilder, SectionValueBuilder> { public SectionValueBuilder(@NotNull ValueType type, - @NotNull ValueHandler parser, - @NotNull ValueHandler> serializer) { + @NotNull ValueHandler parser, + @NotNull ValueHandler> serializer) { super(type, type, parser, serializer); } diff --git a/core/src/main/java/cc/carm/lib/configuration/function/ValueHandler.java b/core/src/main/java/cc/carm/lib/configuration/function/ValueHandler.java index 6dac39b..6b67b61 100644 --- a/core/src/main/java/cc/carm/lib/configuration/function/ValueHandler.java +++ b/core/src/main/java/cc/carm/lib/configuration/function/ValueHandler.java @@ -50,6 +50,11 @@ public interface ValueHandler { return ConfigurationHolder::serialize; } + @Contract(pure = true) + static @NotNull ValueHandler stringValue() { + return (provider, input) -> String.valueOf(input); + } + @Contract(pure = true) static @NotNull ValueHandler fromObject(ValueType type) { return (provider, input) -> provider.deserialize(type, input); diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationFactory.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationFactory.java index 33ad652..8d93f88 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationFactory.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationFactory.java @@ -1,46 +1,38 @@ package cc.carm.lib.configuration.source; -import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; +import cc.carm.lib.configuration.adapter.*; +import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter; +import cc.carm.lib.configuration.adapter.strandard.StandardAdapters; +import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.loader.PathGenerator; +import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.option.ConfigurationOption; import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; -import cc.carm.lib.configuration.source.section.ConfigurationSource; +import cc.carm.lib.configuration.source.section.ConfigureSource; import org.jetbrains.annotations.NotNull; +import java.lang.annotation.Annotation; import java.util.function.Consumer; import java.util.function.Function; -public abstract class ConfigurationFactory, PROVIDER extends ConfigurationHolder, SELF> { - - protected Function loaderFunction = PROVIDER -> new ConfigurationInitializer(); - protected Consumer loaderConsumer = loader -> { - }; +public abstract class ConfigurationFactory< + SOURCE extends ConfigureSource, + HOLDER extends ConfigurationHolder, + SELF + > { protected ValueAdapterRegistry adapters = new ValueAdapterRegistry(); protected ConfigurationOptionHolder options = new ConfigurationOptionHolder(); + protected ConfigurationInitializer initializer = new ConfigurationInitializer(); + + public ConfigurationFactory() { + this.adapters.register(PrimitiveAdapter.ADAPTERS); + this.adapters.register(StandardAdapters.SECTION_ADAPTER); + } public abstract SELF self(); - public SELF loader(Function loaderFunction) { - this.loaderFunction = loaderFunction; - return self(); - } - - public SELF loader(ConfigurationInitializer loader) { - return loader(PROVIDER -> loader); - } - - public SELF loader(Consumer loaderConsumer) { - this.loaderConsumer = this.loaderConsumer.andThen(loaderConsumer); - return self(); - } - - public SELF pathGenerator(PathGenerator generator) { - return loader(loader -> { - loader.pathGenerator(generator); - }); - } public SELF adapters(ValueAdapterRegistry adapters) { this.adapters = adapters; @@ -52,18 +44,37 @@ public abstract class ConfigurationFactory adapter) { -// return adapter(a -> a.register(adapter)); -// } -// -// public SELF adapter(Class clazz, @NotNull ValueAdapter adapter) { -// return adapter(a -> a.register(clazz, adapter)); -// } -// -// public SELF adapter(Class baseClass, Class valueClass, -// ConfigDataFunction parser, ConfigDataFunction serializer) { -// return adapter(a -> a.register(baseClass, valueClass, parser, serializer)); -// } + public SELF adapter(@NotNull ValueAdapter adapter) { + return adapter(a -> a.register(adapter)); + } + + public SELF adapter(@NotNull ValueType type, @NotNull ValueSerializer serializer) { + return adapter(a -> a.register(type, serializer)); + } + + public SELF adapter(@NotNull ValueType type, @NotNull ValueParser parser) { + return adapter(a -> a.register(type, parser)); + } + + public SELF adapter(@NotNull Class from, @NotNull Class to, + @NotNull DataFunction parser, + @NotNull DataFunction serializer) { + return adapter(a -> a.register(from, to, parser, serializer)); + } + + public SELF adapter(@NotNull ValueType from, @NotNull ValueType to, + @NotNull DataFunction parser, + @NotNull DataFunction serializer) { + return adapter(a -> a.register(from, to, parser, serializer)); + } + + public SELF adapter(@NotNull ValueType type, @NotNull ValueSerializer serializer, @NotNull ValueParser parser) { + return adapter(a -> a.register(type, serializer, parser)); + } + + public SELF adapter(@NotNull Class type, @NotNull ValueSerializer serializer, @NotNull ValueParser parser) { + return adapter(ValueType.of(type), serializer, parser); + } public SELF options(ConfigurationOptionHolder options) { this.options = options; @@ -79,6 +90,29 @@ public abstract class ConfigurationFactory o.set(option, value)); } - public abstract @NotNull PROVIDER build(); + + public SELF initializer(ConfigurationInitializer initializer) { + this.initializer = initializer; + return self(); + } + + public SELF initializer(Consumer initializerConsumer) { + initializerConsumer.accept(initializer); + return self(); + } + + public SELF pathGenerator(PathGenerator generator) { + return initializer(loader -> { + loader.pathGenerator(generator); + }); + } + + public SELF metaAnnotation(@NotNull Class annotation, + @NotNull ConfigurationMetadata metadata, + @NotNull Function extractor) { + return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor)); + } + + public abstract @NotNull HOLDER build(); } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationHolder.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationHolder.java index 441456e..94592ab 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationHolder.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationHolder.java @@ -6,16 +6,15 @@ import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; -import cc.carm.lib.configuration.source.section.ConfigurationSource; +import cc.carm.lib.configuration.source.section.ConfigureSource; import cc.carm.lib.configuration.value.ValueManifest; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; -import java.util.Objects; -public class ConfigurationHolder> { +public abstract class ConfigurationHolder> { protected final @NotNull ValueAdapterRegistry adapters; protected final @NotNull ConfigurationOptionHolder options; @@ -23,8 +22,6 @@ public class ConfigurationHolder> { protected final @NotNull ConfigurationInitializer initializer; - protected @Nullable S source; - public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters, @NotNull ConfigurationOptionHolder options, @NotNull Map metadata, @@ -35,16 +32,14 @@ public class ConfigurationHolder> { this.metadata = metadata; } - public @NotNull S source() { - return Objects.requireNonNull(source, "Source is not initialized"); - } + public abstract @NotNull SOURCE config(); public void reload() throws Exception { - source().reload(); + config().reload(); } public void save() throws Exception { - source().save(); + config().save(); } public ConfigurationOptionHolder options() { @@ -83,7 +78,7 @@ public class ConfigurationHolder> { return adapters().serialize(this, value); } - public void load(Class configClass) { + public void initialize(Class configClass) { try { initializer.initialize(this, configClass); } catch (Exception e) { @@ -91,7 +86,7 @@ public class ConfigurationHolder> { } } - public void load(@NotNull Configuration config) { + public void initialize(@NotNull Configuration config) { try { initializer.initialize(this, config); } catch (Exception e) { @@ -99,7 +94,7 @@ public class ConfigurationHolder> { } } - public void load(@NotNull ValueManifest value) { + public void initialize(@NotNull ValueManifest value) { value.holder(this); } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationInitializer.java b/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationInitializer.java index 38c52f4..5ba01bb 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationInitializer.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationInitializer.java @@ -70,49 +70,49 @@ public class ConfigurationInitializer { public void registerAnnotation(@NotNull Class annotation, @NotNull ConfigurationMetadata metadata, @NotNull Function extractor) { - appendFieldInitializer((provider, path, field) -> { + appendFieldInitializer((holder, path, field) -> { A data = field.getAnnotation(annotation); if (data == null) return; - provider.metadata(path).setIfAbsent(metadata, extractor.apply(data)); + holder.metadata(path).setIfAbsent(metadata, extractor.apply(data)); }); - appendClassInitializer((provider, path, clazz) -> { + appendClassInitializer((holder, path, clazz) -> { A data = clazz.getAnnotation(annotation); if (data == null) return; - provider.metadata(path).setIfAbsent(metadata, extractor.apply(data)); + holder.metadata(path).setIfAbsent(metadata, extractor.apply(data)); }); } public @Nullable String getFieldPath(ConfigurationHolder holder, @Nullable String parentPath, @NotNull Field field) { - return pathGenerator.getFieldPath(provider, parentPath, field); + return pathGenerator.getFieldPath(holder, parentPath, field); } public @Nullable String getClassPath(ConfigurationHolder holder, @Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField) { - return pathGenerator.getClassPath(provider, parentPath, clazz, clazzField); + return pathGenerator.getClassPath(holder, parentPath, clazz, clazzField); } public void initialize(ConfigurationHolder holder, @NotNull Configuration config) throws Exception { - initializeInstance(provider, config, null, null); - if (provider.options().get(StandardOptions.SET_DEFAULTS)) provider.save(); + initializeInstance(holder, config, null, null); + if (holder.options().get(StandardOptions.SET_DEFAULTS)) holder.save(); } public void initialize(ConfigurationHolder holder, @NotNull Class clazz) throws Exception { - initializeStaticClass(provider, clazz, null, null); - if (provider.options().get(StandardOptions.SET_DEFAULTS)) provider.save(); + initializeStaticClass(holder, clazz, null, null); + if (holder.options().get(StandardOptions.SET_DEFAULTS)) holder.save(); } // 针对实例类的初始化方法 protected void initializeInstance(@NotNull ConfigurationHolder holder, @NotNull Configuration root, @Nullable String parentPath, @Nullable Field configField) { - String path = getClassPath(provider, parentPath, root.getClass(), configField); + String path = getClassPath(holder, parentPath, root.getClass(), configField); try { - this.classInitializer.whenInitialize(provider, path, root.getClass()); + this.classInitializer.whenInitialize(holder, path, root.getClass()); } catch (Exception e) { e.printStackTrace(); } - Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(provider, root, field, path)); + Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path)); } // 针对静态类的初始化方法 @@ -121,22 +121,22 @@ public class ConfigurationInitializer { @NotNull Class clazz, @Nullable String parentPath, @Nullable Field configField) { if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类 - String path = getClassPath(provider, parentPath, clazz, configField); + String path = getClassPath(holder, parentPath, clazz, configField); try { - this.classInitializer.whenInitialize(provider, path, (Class) clazz); + this.classInitializer.whenInitialize(holder, path, (Class) clazz); } catch (Exception e) { e.printStackTrace(); } for (Field field : clazz.getDeclaredFields()) { - initializeField(provider, clazz, field, path); + initializeField(holder, clazz, field, path); } - if (provider.options().get(StandardOptions.LOAD_SUB_CLASSES)) { + if (holder.options().get(StandardOptions.LOAD_SUB_CLASSES)) { Class[] classes = clazz.getDeclaredClasses(); for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。 - initializeStaticClass(provider, classes[i], path, null); + initializeStaticClass(holder, classes[i], path, null); } } } @@ -150,20 +150,20 @@ public class ConfigurationInitializer { if (object instanceof ConfigValue) { // 目标是 ConfigValue 实例,进行具体的初始化注入 ConfigValue value = (ConfigValue) object; - String path = getFieldPath(provider, parent, field); + String path = getFieldPath(holder, parent, field); if (path == null) return; - value.initialize(provider, path); + value.initialize(holder, path); try { - this.fieldInitializer.whenInitialize(provider, path, field); + this.fieldInitializer.whenInitialize(holder, path, field); } catch (Exception e) { e.printStackTrace(); } } else if (source instanceof Configuration && object instanceof Configuration) { // 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。 - initializeInstance(provider, (Configuration) object, parent, field); + initializeInstance(holder, (Configuration) object, parent, field); } else if (source instanceof Class && object instanceof Class) { // 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。 - initializeStaticClass(provider, (Class) object, parent, field); + initializeStaticClass(holder, (Class) object, parent, field); } // 以上判断实现以下规范: diff --git a/core/src/main/java/cc/carm/lib/configuration/source/loader/PathGenerator.java b/core/src/main/java/cc/carm/lib/configuration/source/loader/PathGenerator.java index 7eb552f..4312fd4 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/loader/PathGenerator.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/loader/PathGenerator.java @@ -40,8 +40,8 @@ public class PathGenerator { public @Nullable String getFieldPath(@NotNull ConfigurationHolder holder, @Nullable String parentPath, @NotNull Field field) { ConfigPath path = field.getAnnotation(ConfigPath.class); - if (path == null) return link(provider, parentPath, false, field.getName()); // No annotation, use field name. - else return link(provider, parentPath, path.root(), select(path.value(), field.getName())); + if (path == null) return link(holder, parentPath, false, field.getName()); // No annotation, use field name. + else return link(holder, parentPath, path.root(), select(path.value(), field.getName())); } public @Nullable String getClassPath(@NotNull ConfigurationHolder holder, @@ -52,14 +52,14 @@ public class PathGenerator { // and use filed information. ConfigPath clazzPath = clazz.getAnnotation(ConfigPath.class); - if (clazzPath != null) return link(provider, parentPath, clazzPath.root(), clazzPath.value()); + if (clazzPath != null) return link(holder, parentPath, clazzPath.root(), clazzPath.value()); if (clazzField == null) { - return link(provider, parentPath, false, clazz.getSimpleName()); // No field, use class name. + return link(holder, parentPath, false, clazz.getSimpleName()); // No field, use class name. } ConfigPath fieldPath = clazzField.getAnnotation(ConfigPath.class); - if (fieldPath == null) return link(provider, parentPath, false, clazzField.getName()); - else return getFieldPath(provider, parentPath, clazzField); + if (fieldPath == null) return link(holder, parentPath, false, clazzField.getName()); + else return getFieldPath(holder, parentPath, clazzField); } protected String select(String path, String defaultValue) { @@ -70,7 +70,7 @@ public class PathGenerator { protected @Nullable String link(@NotNull ConfigurationHolder holder, @Nullable String parent, boolean root, @Nullable String path) { if (path == null || path.isEmpty()) return root ? null : parent; - return root || parent == null ? covertPath(path) : parent + pathSeparator(provider) + covertPath(path); + return root || parent == null ? covertPath(path) : parent + pathSeparator(holder) + covertPath(path); } public static boolean isBlank(String path) { @@ -78,7 +78,7 @@ public class PathGenerator { } public static char pathSeparator(ConfigurationHolder holder) { - return provider.options().get(StandardOptions.PATH_SEPARATOR); + return holder.options().get(StandardOptions.PATH_SEPARATOR); } /** diff --git a/core/src/main/java/cc/carm/lib/configuration/source/option/StandardOptions.java b/core/src/main/java/cc/carm/lib/configuration/source/option/StandardOptions.java index ad6221e..1da01ad 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/option/StandardOptions.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/option/StandardOptions.java @@ -27,7 +27,7 @@ public interface StandardOptions { *
if false, the values will be parsed when calling * {@link cc.carm.lib.configuration.value.ConfigValue#get()} *
if true, the values will be parsed when - * {@link ConfigurationHolder#load(Configuration)}. + * {@link ConfigurationHolder#initialize(Configuration)}. */ ConfigurationOption PRELOAD = of(false); diff --git a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSource.java b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSource.java deleted file mode 100644 index 734746c..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSource.java +++ /dev/null @@ -1,46 +0,0 @@ -package cc.carm.lib.configuration.source.section; - -import cc.carm.lib.configuration.source.ConfigurationHolder; -import org.jetbrains.annotations.NotNull; - -public abstract class ConfigurationSource, ORIGINAL> - implements ConfigurationSection { - - protected final @NotNull ConfigurationHolder holder; - protected long lastUpdateMillis; - - protected ConfigurationSource(@NotNull ConfigurationHolder holder, - long lastUpdateMillis) { - this.holder = holder; - this.lastUpdateMillis = lastUpdateMillis; - } - - public @NotNull ConfigurationHolder holder() { - return holder; - } - - public void reload() throws Exception { - onReload(); // 调用重写的Reload方法 - this.lastUpdateMillis = System.currentTimeMillis(); - } - - protected abstract SELF self(); - - /** - * @return Original configuration object - */ - public abstract @NotNull ORIGINAL original(); - - public abstract void save() throws Exception; - - protected abstract void onReload() throws Exception; - - public long getLastUpdateMillis() { - return this.lastUpdateMillis; - } - - public boolean isExpired(long parsedTime) { - return getLastUpdateMillis() > parsedTime; - } - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSection.java b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java similarity index 95% rename from core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSection.java rename to core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java index 05a1afa..42e71a6 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSection.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java @@ -1,6 +1,7 @@ package cc.carm.lib.configuration.source.section; import cc.carm.lib.configuration.function.DataFunction; +import cc.carm.lib.configuration.source.option.StandardOptions; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -8,7 +9,13 @@ import org.jetbrains.annotations.Unmodifiable; import java.util.*; -public interface ConfigurationSection { +public interface ConfigureSection { + + @NotNull ConfigureSource source(); + + default char separator() { + return source().holder().options().get(StandardOptions.PATH_SEPARATOR); + } @NotNull default Set getKeys(boolean deep) { @@ -33,7 +40,7 @@ public interface ConfigurationSection { boolean isSection(@NotNull String path); @Nullable - ConfigurationSection getSection(@NotNull String path); + ConfigureSection getSection(@NotNull String path); @Nullable Object get(@NotNull String path); diff --git a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSource.java b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSource.java new file mode 100644 index 0000000..b2e7e4c --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSource.java @@ -0,0 +1,97 @@ +package cc.carm.lib.configuration.source.section; + +import cc.carm.lib.configuration.source.ConfigurationHolder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; + +public abstract class ConfigureSource< + SECTION extends ConfigureSection, ORIGINAL, + SELF extends ConfigureSource> + implements ConfigureSection { + + protected final @NotNull ConfigurationHolder holder; + protected long lastUpdateMillis; + + protected ConfigureSource(@NotNull ConfigurationHolder holder, long lastUpdateMillis) { + this.holder = holder; + this.lastUpdateMillis = lastUpdateMillis; + } + + public @NotNull ConfigurationHolder holder() { + return holder; + } + + + public void reload() throws Exception { + onReload(); // 调用重写的Reload方法 + this.lastUpdateMillis = System.currentTimeMillis(); + } + + protected abstract SELF self(); + + /** + * @return Original configuration object + */ + public abstract @NotNull ORIGINAL original(); + + /** + * @return Configuration section + */ + public abstract @NotNull SECTION section(); + + public abstract void save() throws Exception; + + protected abstract void onReload() throws Exception; + + public long getLastUpdateMillis() { + return this.lastUpdateMillis; + } + + public boolean isExpired(long parsedTime) { + return getLastUpdateMillis() > parsedTime; + } + + @Override + public @NotNull Map getValues(boolean deep) { + return section().getValues(deep); + } + + @Override + public void set(@NotNull String path, @Nullable Object value) { + section().set(path, value); + } + + @Override + public boolean contains(@NotNull String path) { + return section().contains(path); + } + + @Override + public boolean isList(@NotNull String path) { + return section().isList(path); + } + + @Override + public @Nullable List getList(@NotNull String path) { + return section().getList(path); + } + + @Override + public boolean isSection(@NotNull String path) { + return section().isSection(path); + } + + @Override + public @Nullable ConfigureSection getSection(@NotNull String path) { + return section().getSection(path); + } + + @Override + public @Nullable Object get(@NotNull String path) { + return section().get(path); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/ValueManifest.java b/core/src/main/java/cc/carm/lib/configuration/value/ValueManifest.java index d9a6530..ca48ab6 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/ValueManifest.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/ValueManifest.java @@ -3,7 +3,7 @@ package cc.carm.lib.configuration.value; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; -import cc.carm.lib.configuration.source.section.ConfigurationSource; +import cc.carm.lib.configuration.source.section.ConfigureSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -101,8 +101,8 @@ public class ValueManifest { throw new IllegalStateException("Value does not have a provider."); } - public @NotNull ConfigurationSource config() { - return holder().source(); + public @NotNull ConfigureSource config() { + return holder().config(); } public ConfigurationMetaHolder metadata() { diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java index f01a390..b6137de 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java @@ -4,7 +4,7 @@ import cc.carm.lib.configuration.adapter.ValueAdapter; import cc.carm.lib.configuration.adapter.ValueParser; import cc.carm.lib.configuration.adapter.ValueSerializer; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; @@ -58,7 +58,7 @@ public class ConfiguredMap extends CachedConfigValue> implements // If the value is expired, we need to update it Map map = createMap(); - ConfigurationSection section = config().getSection(path()); + ConfigureSection section = config().getSection(path()); if (section == null) return getDefaultFirst(map); Set keys = section.getKeys(false); diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java index 6565daf..770d76b 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java @@ -30,6 +30,11 @@ public class ConfiguredValue extends CachedConfigValue { return of(ValueType.of(type), () -> null); } + public static ConfiguredValue of(@NotNull Class type, @NotNull V defaults) { + return of(ValueType.of(type), () -> defaults); + } + + public static ConfiguredValue of(@NotNull Class type, @NotNull Supplier<@Nullable V> defaultSupplier) { return of(ValueType.of(type), defaultSupplier); } diff --git a/core/src/test/java/AdaptTest.java b/core/src/test/java/AdaptTest.java index 11b9039..bf55bcc 100644 --- a/core/src/test/java/AdaptTest.java +++ b/core/src/test/java/AdaptTest.java @@ -5,6 +5,7 @@ import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; import cc.carm.test.config.TestSource; +import org.jetbrains.annotations.NotNull; import org.junit.Test; import java.time.Duration; @@ -28,10 +29,17 @@ public class AdaptTest { data -> Duration.between(LocalTime.now(), data) ); - ConfigurationHolder provider = new ConfigurationHolder<>( - new TestSource(), registry, new ConfigurationOptionHolder(), + ConfigurationHolder provider = new ConfigurationHolder( + registry, new ConfigurationOptionHolder(), new ConcurrentHashMap<>(), new ConfigurationInitializer() - ); + ) { + final TestSource source = new TestSource(this, System.currentTimeMillis()); + + @Override + public @NotNull TestSource config() { + return source; + } + }; LocalTime v = registry.deserialize(provider, LocalTime.class, 600000L); Object d = registry.serialize(provider, v); diff --git a/core/src/test/java/NameTest.java b/core/src/test/java/NameTest.java index 9b4cce8..604057c 100644 --- a/core/src/test/java/NameTest.java +++ b/core/src/test/java/NameTest.java @@ -1,3 +1,4 @@ +import cc.carm.lib.configuration.source.loader.PathGenerator; import org.junit.Test; public class NameTest { diff --git a/core/src/test/java/cc/carm/test/config/LoaderTest.java b/core/src/test/java/cc/carm/test/config/LoaderTest.java index 5d0393e..fdffa23 100644 --- a/core/src/test/java/cc/carm/test/config/LoaderTest.java +++ b/core/src/test/java/cc/carm/test/config/LoaderTest.java @@ -6,6 +6,7 @@ import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; +import org.jetbrains.annotations.NotNull; import org.junit.Test; import java.util.concurrent.ConcurrentHashMap; @@ -14,10 +15,17 @@ public class LoaderTest { @Test public void test() throws Exception { - ConfigurationHolder provider = new ConfigurationHolder<>( - new TestSource(), new ValueAdapterRegistry(), new ConfigurationOptionHolder(), + ConfigurationHolder provider = new ConfigurationHolder( + new ValueAdapterRegistry(), new ConfigurationOptionHolder(), new ConcurrentHashMap<>(), new ConfigurationInitializer() - ); + ) { + final TestSource source = new TestSource(this, System.currentTimeMillis()); + + @Override + public @NotNull TestSource config() { + return source; + } + }; ConfigurationInitializer loader = new ConfigurationInitializer(); loader.initialize(provider, ROOT.class); diff --git a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigurationSection.java b/core/src/test/java/cc/carm/test/config/TestSection.java similarity index 70% rename from providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigurationSection.java rename to core/src/test/java/cc/carm/test/config/TestSection.java index bda7daf..2293a0e 100644 --- a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigurationSection.java +++ b/core/src/test/java/cc/carm/test/config/TestSection.java @@ -1,6 +1,7 @@ -package cc.carm.lib.configuration.json; +package cc.carm.test.config; -import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.source.section.ConfigureSection; +import cc.carm.lib.configuration.source.section.ConfigureSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -8,8 +9,11 @@ import java.util.Collections; import java.util.List; import java.util.Map; -public class JSONConfigurationSection implements ConfigurationSection { - +public class TestSection implements ConfigureSection { + @Override + public @NotNull ConfigureSource source() { + return null; + } @Override public @NotNull Map getValues(boolean deep) { @@ -42,7 +46,7 @@ public class JSONConfigurationSection implements ConfigurationSection { } @Override - public @Nullable ConfigurationSection getSection(@NotNull String path) { + public @Nullable ConfigureSection getSection(@NotNull String path) { return null; } diff --git a/core/src/test/java/cc/carm/test/config/TestSource.java b/core/src/test/java/cc/carm/test/config/TestSource.java index c836e4c..6a1d5e9 100644 --- a/core/src/test/java/cc/carm/test/config/TestSource.java +++ b/core/src/test/java/cc/carm/test/config/TestSource.java @@ -1,18 +1,16 @@ package cc.carm.test.config; -import cc.carm.lib.configuration.source.section.ConfigurationSection; -import cc.carm.lib.configuration.source.section.ConfigurationSource; +import cc.carm.lib.configuration.source.ConfigurationHolder; +import cc.carm.lib.configuration.source.section.ConfigureSource; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.List; import java.util.Map; -import java.util.Set; -public class TestSource extends ConfigurationSource> { +public class TestSource extends ConfigureSource, TestSource> { - public TestSource() { - super(System.currentTimeMillis()); + + public TestSource(@NotNull ConfigurationHolder holder, long lastUpdateMillis) { + super(holder, lastUpdateMillis); } @Override @@ -36,47 +34,12 @@ public class TestSource extends ConfigurationSource getKeys(boolean deep) { + public @NotNull TestSection section() { return null; } @Override - public @NotNull Map getValues(boolean deep) { - return null; - } - - @Override - public @Nullable Object get(@NotNull String path) { - return null; - } - - @Override - public void set(@NotNull String path, @Nullable Object value) { - - } - - @Override - public boolean contains(@NotNull String path) { - return false; - } - - @Override - public boolean isList(@NotNull String path) { - return false; - } - - @Override - public @Nullable List getList(@NotNull String path) { - return null; - } - - @Override - public boolean isSection(@NotNull String path) { - return false; - } - - @Override - public @Nullable ConfigurationSection getSection(@NotNull String path) { + public @NotNull ConfigureSource source() { return null; } } diff --git a/demo/pom.xml b/demo/pom.xml index 5a8324b..13700da 100644 --- a/demo/pom.xml +++ b/demo/pom.xml @@ -26,6 +26,13 @@ compile + + ${project.parent.groupId} + easyconfiguration-feature-commentable + ${project.parent.version} + compile + + diff --git a/demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java b/demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java index f9ebe6d..f35e99c 100644 --- a/demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java +++ b/demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.demo; -import cc.carm.lib.configuration.source.Configuration; +import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.value.ConfigValue; diff --git a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/ConfigurationTest.java b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/ConfigurationTest.java index b6c18df..b8420a5 100644 --- a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/ConfigurationTest.java +++ b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/ConfigurationTest.java @@ -3,9 +3,9 @@ package cc.carm.lib.configuration.demo.tests; import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration; import cc.carm.lib.configuration.demo.tests.conf.TestConfiguration; import cc.carm.lib.configuration.demo.tests.model.TestModel; +import cc.carm.lib.configuration.source.ConfigurationHolder; import org.jetbrains.annotations.TestOnly; -import java.util.LinkedHashMap; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; @@ -14,8 +14,12 @@ import java.util.stream.IntStream; public class ConfigurationTest { @TestOnly - public static void testDemo(ConfigurationProvider provider) { - provider.initialize(DemoConfiguration.class); + public static void testDemo(ConfigurationHolder holder) { + try { + holder.initializer().initialize(holder, DemoConfiguration.class); + } catch (Exception e) { + e.printStackTrace(); + } System.out.println("----------------------------------------------------"); @@ -48,21 +52,21 @@ public class ConfigurationTest { System.out.println(DemoConfiguration.MODEL_TEST.get()); DemoConfiguration.MODEL_TEST.set(TestModel.random()); - System.out.println("> Test Maps:"); - DemoConfiguration.USERS.forEach((k, v) -> System.out.println(k + ": " + v)); - LinkedHashMap data = new LinkedHashMap<>(); - for (int i = 1; i <= 5; i++) { - data.put(i, UUID.randomUUID()); - } - DemoConfiguration.USERS.set(data); +// System.out.println("> Test Maps:"); +// DemoConfiguration.USERS.forEach((k, v) -> System.out.println(k + ": " + v)); +// LinkedHashMap data = new LinkedHashMap<>(); +// for (int i = 1; i <= 5; i++) { +// data.put(i, UUID.randomUUID()); +// } +// DemoConfiguration.USERS.set(data); System.out.println("----------------------------------------------------"); } - public static void testInner(ConfigurationProvider provider) { + public static void testInner(ConfigurationHolder provider) { TestConfiguration TEST = new TestConfiguration(); - provider.initialize(TEST, true); + provider.initialize(TEST); System.out.println("> Test Inner value before:"); System.out.println(TEST.INNER.INNER_VALUE.getNotNull()); @@ -76,7 +80,7 @@ public class ConfigurationTest { } - public static void save(ConfigurationProvider provider) { + public static void save(ConfigurationHolder provider) { try { provider.save(); } catch (Exception e) { diff --git a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java index 76d30bd..2080ce8 100644 --- a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java +++ b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java @@ -1,15 +1,13 @@ package cc.carm.lib.configuration.demo.tests.conf; -import cc.carm.lib.configuration.source.Configuration; +import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.annotation.InlineComment; +import cc.carm.lib.configuration.demo.tests.model.TestModel; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.standard.ConfiguredList; -import cc.carm.lib.configuration.value.standard.ConfiguredMap; -import cc.carm.lib.configuration.value.standard.ConfiguredSection; import cc.carm.lib.configuration.value.standard.ConfiguredValue; -import cc.carm.lib.configuration.demo.tests.model.TestModel; import java.time.temporal.ChronoUnit; import java.util.Objects; @@ -37,22 +35,22 @@ public interface DemoConfiguration extends Configuration { @ConfigPath("user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。 @HeaderComment({"Section类型数据测试"}) // 通过注解给配置添加注释。 @InlineComment("Section数据也支持InlineComment注释") - ConfigValue MODEL_TEST = ConfiguredSection.builderOf(TestModel.class) + ConfigValue MODEL_TEST = ConfiguredValue.builderOf(TestModel.class).fromSection() .defaults(new TestModel("Carm", UUID.randomUUID())) - .parseValue((section, defaultValue) -> TestModel.deserialize(section)) - .serializeValue(TestModel::serialize).build(); + .parse((holder, section) -> TestModel.deserialize(section)) + .serialize(TestModel::serialize).build(); - @HeaderComment({"[ID - UUID]对照表", "", "用于测试Map类型的解析与序列化保存"}) - ConfiguredMap USERS = ConfiguredMap.builderOf(Integer.class, UUID.class) - .asLinkedMap().fromString() - .parseKey(Integer::parseInt) - .parseValue(v -> Objects.requireNonNull(UUID.fromString(v))) - .build(); +// @HeaderComment({"[ID - UUID]对照表", "", "用于测试Map类型的解析与序列化保存"}) +// ConfiguredMap USERS = ConfiguredMap.builderOf(Integer.class, UUID.class) +// .asLinkedMap().fromString() +// .parseKey(Integer::parseInt) +// .parseValue(v -> Objects.requireNonNull(UUID.fromString(v))) +// .build(); /** * 支持内部类的直接注册。 - * 注意,需要使用 {@link ConfigInitializer#initialize(Class, boolean, boolean)} 方法,并设定第三个参数为 true。 + * 注意,需要启用 {@link cc.carm.lib.configuration.source.option.StandardOptions#LOAD_SUB_CLASSES} */ class Sub implements Configuration { @@ -60,14 +58,14 @@ public interface DemoConfiguration extends Configuration { @InlineComment("This is an inline comment") public static final ConfigValue UUID_CONFIG_VALUE = ConfiguredValue .builderOf(UUID.class).fromString() - .parseValue((data, defaultValue) -> UUID.fromString(data)) + .parse((holder, data) -> UUID.fromString(data)) .build(); public static class That implements Configuration { public static final ConfiguredList OPERATORS = ConfiguredList .builderOf(UUID.class).fromString() - .parseValue(s -> Objects.requireNonNull(UUID.fromString(s))) + .parse(s -> Objects.requireNonNull(UUID.fromString(s))) .build(); } diff --git a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/TestConfiguration.java b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/TestConfiguration.java index 2f6c021..0252d51 100644 --- a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/TestConfiguration.java +++ b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/TestConfiguration.java @@ -1,13 +1,12 @@ package cc.carm.lib.configuration.demo.tests.conf; -import cc.carm.lib.configuration.source.Configuration; +import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.annotation.InlineComment; -import cc.carm.lib.configuration.value.ConfigValue; -import cc.carm.lib.configuration.value.standard.ConfiguredSection; -import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.lib.configuration.demo.tests.model.TestModel; +import cc.carm.lib.configuration.value.ConfigValue; +import cc.carm.lib.configuration.value.standard.ConfiguredValue; import java.util.UUID; @@ -15,16 +14,15 @@ public class TestConfiguration implements Configuration { public final TestInnerConfiguration INNER = new TestInnerConfiguration(); - public final ConfigValue CLASS_VALUE = ConfiguredValue.of(Double.class, 1.0D); + public final ConfigValue CLASS_VALUE = ConfiguredValue.of(1.0D); @ConfigPath("test.user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。 @HeaderComment({"Section类型数据测试"}) // 通过注解给配置添加注释。 @InlineComment("Section数据也支持InlineComment注释") - public final ConfigValue TEST_MODEL = ConfiguredSection - .builderOf(TestModel.class) + public final ConfigValue TEST_MODEL = ConfiguredValue.builderOf(TestModel.class).fromSection() .defaults(new TestModel("Carm", UUID.randomUUID())) - .parseValue((section, defaultValue) -> TestModel.deserialize(section)) - .serializeValue(TestModel::serialize).build(); + .parse((holder, section) -> TestModel.deserialize(section)) + .serialize((holder, data) -> data.serialize()).build(); } diff --git a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/TestInnerConfiguration.java b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/TestInnerConfiguration.java index 2d4a548..7c93b94 100644 --- a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/TestInnerConfiguration.java +++ b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/TestInnerConfiguration.java @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.demo.tests.conf; -import cc.carm.lib.configuration.source.Configuration; +import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue; @@ -8,6 +8,6 @@ import cc.carm.lib.configuration.value.standard.ConfiguredValue; @HeaderComment("Inner Test") public class TestInnerConfiguration implements Configuration { - public final ConfigValue INNER_VALUE = ConfiguredValue.of(Double.class, 1.0D); + public final ConfigValue INNER_VALUE = ConfiguredValue.of(1.0D); } diff --git a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/TestModel.java b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/TestModel.java index 9121742..0c9ef93 100644 --- a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/TestModel.java +++ b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/TestModel.java @@ -1,5 +1,6 @@ package cc.carm.lib.configuration.demo.tests.model; +import cc.carm.lib.configuration.source.section.ConfigureSection; import org.jetbrains.annotations.NotNull; import java.util.HashMap; @@ -32,7 +33,7 @@ public class TestModel extends AbstractModel { return map; } - public static TestModel deserialize(ConfigurationWrapper section) { + public static TestModel deserialize(ConfigureSection section) { String name = section.getString("name"); if (name == null) throw new NullPointerException("name is null"); String uuidString = section.getString("info.uuid"); diff --git a/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigFactory.java b/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigFactory.java new file mode 100644 index 0000000..20a33f3 --- /dev/null +++ b/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigFactory.java @@ -0,0 +1,39 @@ +package cc.carm.lib.configuration.source; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.nio.file.Path; + +public abstract class FileConfigFactory, + HOLDER extends ConfigurationHolder, SELF extends FileConfigFactory> + extends ConfigurationFactory { + + + protected @NotNull File file; + protected @Nullable String resourcePath; + + public FileConfigFactory(@NotNull File file) { + this.file = file; + } + + public SELF file(@NotNull File file) { + this.file = file; + return self(); + } + + public SELF file(@NotNull Path path) { + return file(path.toFile()); + } + + public SELF file(@NotNull File parent, @NotNull String fileName) { + return file(new File(parent, fileName)); + } + + public SELF resourcePath(@Nullable String resourcePath) { + this.resourcePath = resourcePath; + return self(); + } + +} diff --git a/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigSource.java b/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigSource.java index 0c28dee..5973156 100644 --- a/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigSource.java +++ b/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigSource.java @@ -2,7 +2,8 @@ package cc.carm.lib.configuration.source; import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.option.FileConfigOptions; -import cc.carm.lib.configuration.source.section.ConfigurationSource; +import cc.carm.lib.configuration.source.section.ConfigureSection; +import cc.carm.lib.configuration.source.section.ConfigureSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,8 +15,8 @@ import java.nio.file.Files; import java.util.Objects; import java.util.function.Consumer; -public abstract class FileConfigSource, ORIGINAL> - extends ConfigurationSource { +public abstract class FileConfigSource
> + extends ConfigureSource { protected final @NotNull File file; protected final @Nullable String resourcePath; @@ -27,6 +28,7 @@ public abstract class FileConfigSource R fileInputStream(@NotNull DataFunction loader) { - try (FileInputStream is = new FileInputStream(file)) { + protected R fileInputStream(@NotNull DataFunction loader) throws Exception { + try (InputStream is = Files.newInputStream(file.toPath())) { return loader.handle(is); - } catch (Exception e) { - e.printStackTrace(); - return null; } } - protected R fileReader(@NotNull DataFunction loader) { + protected R fileReader(@NotNull DataFunction loader) throws Exception { return fileInputStream(is -> loader.handle(new InputStreamReader(is, charset()))); } - protected void fileOutputStream(@NotNull Consumer stream) { - try (FileOutputStream os = new FileOutputStream(file)) { + protected void fileOutputStream(@NotNull Consumer stream) throws Exception { + try (OutputStream os = Files.newOutputStream(file.toPath())) { stream.accept(os); - } catch (Exception e) { - e.printStackTrace(); } } - protected void fileWriter(@NotNull Consumer writer) { + protected void fileWriter(@NotNull Consumer writer) throws Exception { fileOutputStream(os -> writer.accept(new OutputStreamWriter(os, charset()))); } diff --git a/pom.xml b/pom.xml index 29de05d..ac2a2a5 100644 --- a/pom.xml +++ b/pom.xml @@ -21,11 +21,12 @@ features/commentable features/file - - + providers/gson - - + + + + demo EasyConfiguration diff --git a/providers/gson/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java b/providers/gson/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java deleted file mode 100644 index 594ff50..0000000 --- a/providers/gson/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java +++ /dev/null @@ -1,36 +0,0 @@ -package cc.carm.lib.configuration; - -import cc.carm.lib.configuration.json.JSONConfigProvider; - -import java.io.File; -import java.io.IOException; - -public class EasyConfiguration { - - private EasyConfiguration() { - } - - public static JSONConfigProvider from(File file, String source) { - JSONConfigProvider provider = new JSONConfigProvider(file); - try { - provider.initializeFile(source); - provider.initializeConfig(); - } catch (IOException e) { - e.printStackTrace(); - } - return provider; - } - - public static JSONConfigProvider from(File file) { - return from(file, file.getName()); - } - - public static JSONConfigProvider from(String fileName) { - return from(fileName, fileName); - } - - public static JSONConfigProvider from(String fileName, String source) { - return from(new File(fileName), source); - } - -} diff --git a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigFactory.java b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigFactory.java new file mode 100644 index 0000000..5758188 --- /dev/null +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigFactory.java @@ -0,0 +1,72 @@ +package cc.carm.lib.configuration.json; + +import cc.carm.lib.configuration.source.ConfigurationHolder; +import cc.carm.lib.configuration.source.FileConfigFactory; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class JSONConfigFactory extends FileConfigFactory, JSONConfigFactory> { + + public static JSONConfigFactory from(@NotNull File file) { + return new JSONConfigFactory(file); + } + + public static JSONConfigFactory from(@NotNull File parent, @NotNull String configName) { + return new JSONConfigFactory(new File(parent, configName)); + } + + protected Supplier gsonSupplier = () -> JSONSource.DEFAULT_GSON; + + public JSONConfigFactory(@NotNull File file) { + super(file); + } + + @Override + public JSONConfigFactory self() { + return this; + } + + public JSONConfigFactory gson(@NotNull Supplier gsonSupplier) { + this.gsonSupplier = gsonSupplier; + return self(); + } + + public JSONConfigFactory gson(@NotNull Gson gson) { + return gson(() -> gson); + } + + public JSONConfigFactory gson(@NotNull Consumer builder) { + return gson(() -> { + GsonBuilder gsonBuilder = new GsonBuilder(); + builder.accept(gsonBuilder); + return gsonBuilder.create(); + }); + } + + + @Override + public @NotNull ConfigurationHolder build() { + Gson gson = gsonSupplier.get(); + if (gson == null) throw new NullPointerException("No Gson instance provided."); + + File configFile = this.file; + String sourcePath = this.resourcePath; + + return new ConfigurationHolder(this.adapters, this.options, new ConcurrentHashMap<>(), this.initializer) { + final JSONSource source = new JSONSource(this, 0, configFile, sourcePath, gson); + + @Override + public @NotNull JSONSource config() { + return source; + } + }; + } + + +} diff --git a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java deleted file mode 100644 index 976f712..0000000 --- a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java +++ /dev/null @@ -1,73 +0,0 @@ -package cc.carm.lib.configuration.json; - -import cc.carm.lib.configuration.source.comment.ConfigurationComments; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonSerializer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.LinkedHashMap; - -/** - * Some code comes from BungeeCord's implementation of the JsonConfiguration. - * - * @author md_5, CarmJos - */ -public class JSONConfigProvider extends FileConfigProvider { - - - - protected JSONConfigWrapper configuration; - protected ConfigInitializer initializer; - - public JSONConfigProvider(@NotNull File file) { - super(file); - this.initializer = new ConfigInitializer<>(this); - } - - public void initializeConfig() { - onReload(); - } - - @Override - public @NotNull JSONConfigWrapper getConfiguration() { - return this.configuration; - } - - @Override - protected void onReload() { - LinkedHashMap map = null; - - try (FileInputStream is = new FileInputStream(file)) { - map = gson.fromJson(new InputStreamReader(is, StandardCharsets.UTF_8), LinkedHashMap.class); - } catch (IOException e) { - e.printStackTrace(); - } - - if (map == null) map = new LinkedHashMap<>(); - - this.configuration = new JSONConfigWrapper(map); - } - - @Override - public @Nullable ConfigurationComments getComments() { - return null; - } - - @Override - public void save() throws Exception { - try (Writer writer = new OutputStreamWriter(Files.newOutputStream(file.toPath()), StandardCharsets.UTF_8)) { - gson.toJson(configuration.data, writer); - } - } - - @Override - public @NotNull ConfigInitializer> getInitializer() { - return this.initializer; - } - -} diff --git a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigSource.java b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigSource.java deleted file mode 100644 index 59499c6..0000000 --- a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigSource.java +++ /dev/null @@ -1,109 +0,0 @@ -package cc.carm.lib.configuration.json; - -import cc.carm.lib.configuration.source.ConfigurationHolder; -import cc.carm.lib.configuration.source.FileConfigSource; -import cc.carm.lib.configuration.source.section.ConfigurationSection; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializer; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -public class JSONConfigSource extends FileConfigSource { - - public static final @NotNull Gson DEFAULT_GSON = new GsonBuilder() - .serializeNulls().disableHtmlEscaping().setPrettyPrinting() - .registerTypeAdapter( - JSONConfigWrapper.class, - (JsonSerializer) (src, typeOfSrc, context) -> context.serialize(src.data) - ).create(); - - protected final @NotNull Gson gson; - - protected @Nullable JsonObject original; - - protected JSONConfigSource(@NotNull ConfigurationHolder holder, long lastUpdateMillis, - @NotNull File file, @Nullable String resourcePath, @NotNull Gson gson) { - super(holder, lastUpdateMillis, file, resourcePath); - this.gson = gson; - } - - public void initialize() { - try { - initializeFile(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public void initializeJson() { - this.original = fileReader(reader -> gson.fromJson(reader, JsonObject.class)); - - } - - @Override - protected JSONConfigSource self() { - return this; - } - - @Override - public @NotNull JsonObject original() { - return null; - } - - @Override - public void save() throws Exception { - - } - - @Override - protected void onReload() throws Exception { - - } - - @Override - public @NotNull Map getValues(boolean deep) { - return Collections.emptyMap(); - } - - @Override - public void set(@NotNull String path, @Nullable Object value) { - - } - - @Override - public boolean contains(@NotNull String path) { - return false; - } - - @Override - public boolean isList(@NotNull String path) { - return false; - } - - @Override - public @Nullable List getList(@NotNull String path) { - return Collections.emptyList(); - } - - @Override - public boolean isSection(@NotNull String path) { - return false; - } - - @Override - public @Nullable ConfigurationSection getSection(@NotNull String path) { - return null; - } - - @Override - public @Nullable Object get(@NotNull String path) { - return null; - } -} diff --git a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSection.java similarity index 58% rename from providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java rename to providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSection.java index 5cb0f88..e60231b 100644 --- a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSection.java @@ -1,31 +1,27 @@ package cc.carm.lib.configuration.json; +import cc.carm.lib.configuration.source.section.ConfigureSection; +import cc.carm.lib.configuration.source.section.ConfigureSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; -/** - * Some code comes from BungeeCord's implementation of the JsonConfiguration. - * - * @author md_5, CarmJos - */ -public class JSONConfigWrapper implements ConfigurationWrapper> { +public class JSONSection implements ConfigureSection { - private static final char SEPARATOR = '.'; + protected final ConfigureSource source; protected final Map data; - JSONConfigWrapper(Map map) { + public JSONSection(@NotNull ConfigureSource source, + @NotNull Map data) { + this.source = source; this.data = new LinkedHashMap<>(); - for (Map.Entry entry : map.entrySet()) { + for (Map.Entry entry : data.entrySet()) { String key = (entry.getKey() == null) ? "null" : entry.getKey().toString(); if (entry.getValue() instanceof Map) { - this.data.put(key, new JSONConfigWrapper((Map) entry.getValue())); + this.data.put(key, new JSONSection(source, (Map) entry.getValue())); } else { this.data.put(key, entry.getValue()); } @@ -33,7 +29,11 @@ public class JSONConfigWrapper implements ConfigurationWrapper getSource() { + public @NotNull ConfigureSource source() { + return this.source; + } + + public Map data() { return this.data; } @@ -54,10 +54,10 @@ public class JSONConfigWrapper implements ConfigurationWrapper) value); + value = new JSONSection(source(), (Map) value); } - JSONConfigWrapper section = getSectionFor(path); + JSONSection section = getSectionFor(path); if (section == this) { if (value == null) { this.data.remove(path); @@ -76,7 +76,7 @@ public class JSONConfigWrapper implements ConfigurationWrapper()); + section = new JSONSection(source(), new LinkedHashMap<>()); this.data.put(root, section); } - return (JSONConfigWrapper) section; + return (JSONSection) section; } private String getChild(String path) { - int index = path.indexOf(SEPARATOR); + int index = path.indexOf(separator()); return (index == -1) ? path : path.substring(index + 1); } - protected void mapChildrenValues(@NotNull Map output, @NotNull JSONConfigWrapper section, + protected void mapChildrenValues(@NotNull Map output, @NotNull JSONSection section, @Nullable String parent, boolean deep) { - for (Map.Entry entry : section.data.entrySet()) { - String path = (parent == null ? "" : parent + ".") + entry.getKey(); + for (Map.Entry entry : section.data().entrySet()) { + String path = (parent == null ? "" : parent + separator()) + entry.getKey(); output.remove(path); output.put(path, entry.getValue()); - if (deep && entry.getValue() instanceof JSONConfigWrapper) { - this.mapChildrenValues(output, (JSONConfigWrapper) entry.getValue(), path, true); + if (deep && entry.getValue() instanceof JSONSection) { + this.mapChildrenValues(output, (JSONSection) entry.getValue(), path, true); } } } diff --git a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSource.java b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSource.java new file mode 100644 index 0000000..a6465b2 --- /dev/null +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSource.java @@ -0,0 +1,80 @@ +package cc.carm.lib.configuration.json; + +import cc.carm.lib.configuration.source.ConfigurationHolder; +import cc.carm.lib.configuration.source.FileConfigSource; +import cc.carm.lib.configuration.source.section.ConfigureSource; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSerializer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.*; +import java.util.*; + +public class JSONSource extends FileConfigSource, JSONSource> { + + public static final @NotNull Gson DEFAULT_GSON = new GsonBuilder() + .serializeNulls().disableHtmlEscaping().setPrettyPrinting() + .registerTypeAdapter( + JSONSection.class, + (JsonSerializer) (src, typeOfSrc, context) -> context.serialize(src.data) + ).create(); + + protected final @NotNull Gson gson; + protected @Nullable JSONSection section; + + protected JSONSource(@NotNull ConfigurationHolder holder, long lastUpdateMillis, + @NotNull File file, @Nullable String resourcePath) { + this(holder, lastUpdateMillis, file, resourcePath, DEFAULT_GSON); + } + + protected JSONSource(@NotNull ConfigurationHolder holder, long lastUpdateMillis, + @NotNull File file, @Nullable String resourcePath, @NotNull Gson gson) { + super(holder, lastUpdateMillis, file, resourcePath); + this.gson = gson; + initialize(); + } + + public void initialize() { + try { + initializeFile(); + onReload(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + protected JSONSource self() { + return this; + } + + @Override + public @NotNull ConfigureSource source() { + return this; + } + + @Override + public @NotNull Map original() { + return section().data(); + } + + @Override + public @NotNull JSONSection section() { + return Objects.requireNonNull(this.section, "Section is not initialized"); + } + + @Override + public void save() throws Exception { + fileWriter(writer -> gson.toJson(original(), writer)); + } + + @Override + protected void onReload() throws Exception { + Map data = fileReader(reader -> gson.fromJson(reader, LinkedHashMap.class)); + if (data == null) data = new LinkedHashMap<>(); + this.section = new JSONSection(this, data); + this.lastUpdateMillis = System.currentTimeMillis(); // 更新时间 + } +} diff --git a/providers/gson/src/test/java/config/JSONConfigTest.java b/providers/gson/src/test/java/config/JSONConfigTest.java index 5980c3c..931f09d 100644 --- a/providers/gson/src/test/java/config/JSONConfigTest.java +++ b/providers/gson/src/test/java/config/JSONConfigTest.java @@ -1,28 +1,26 @@ package config; -import cc.carm.lib.configuration.EasyConfiguration; import cc.carm.lib.configuration.demo.tests.ConfigurationTest; -import cc.carm.lib.configuration.json.JSONConfigProvider; +import cc.carm.lib.configuration.json.JSONConfigFactory; +import cc.carm.lib.configuration.source.ConfigurationHolder; +import cc.carm.lib.configuration.source.option.StandardOptions; import org.junit.Test; +import java.io.File; + public class JSONConfigTest { - protected final JSONConfigProvider provider = EasyConfiguration.from("target/config.json", "config.json"); - + protected final ConfigurationHolder holder = JSONConfigFactory + .from(new File("target"), "config.json") + .option(StandardOptions.PATH_SEPARATOR, '-') + .build(); @Test public void onTest() { + ConfigurationTest.testDemo(this.holder); + ConfigurationTest.testInner(this.holder); - ConfigurationTest.testDemo(this.provider); - ConfigurationTest.testInner(this.provider); - - System.out.println("----------------------------------------------------"); - provider.getConfiguration().getValues(true).forEach((k, v) -> System.out.println(k + ": " + v)); - System.out.println("----------------------------------------------------"); - provider.getConfiguration().getValues(false).forEach((k, v) -> System.out.println(k + ": " + v)); - System.out.println("----------------------------------------------------"); - - ConfigurationTest.save(this.provider); + ConfigurationTest.save(this.holder); }