From 2ef1471f5997579959cca0efd439ab644db0fdfc Mon Sep 17 00:00:00 2001 From: carm Date: Mon, 15 Jan 2024 23:32:18 +0800 Subject: [PATCH 01/17] feat(parser): abstract value processor and parsers --- .../cc/carm/lib/configuration/core/parser/ValueParser.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 core/src/main/java/cc/carm/lib/configuration/core/parser/ValueParser.java diff --git a/core/src/main/java/cc/carm/lib/configuration/core/parser/ValueParser.java b/core/src/main/java/cc/carm/lib/configuration/core/parser/ValueParser.java new file mode 100644 index 0000000..c65d828 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/core/parser/ValueParser.java @@ -0,0 +1,4 @@ +package cc.carm.lib.configuration.core.parser; + +public class ValueParser { +} From c7fb51d6b26b7af34b60f90e1d19ad532feca604 Mon Sep 17 00:00:00 2001 From: carm Date: Tue, 16 Jan 2024 02:45:27 +0800 Subject: [PATCH 02/17] feat(adapter): Use registry to manage value adapters --- .../configuration/adapter/ValueAdapter.java | 45 +++++++++++ .../adapter/ValueAdapterRegistry.java | 79 +++++++++++++++++++ .../adapter/primitive/NumberAdapter.java | 24 ++++++ .../adapter/primitive/PrimitiveAdapter.java | 18 +++++ .../{core => }/annotation/ConfigPath.java | 2 +- .../{core => }/annotation/HeaderComment.java | 2 +- .../{core => }/annotation/InlineComment.java | 2 +- .../configuration/core/ConfigInitializer.java | 8 +- .../configuration/core/ConfigurationRoot.java | 8 -- .../core/builder/AbstractConfigBuilder.java | 4 +- .../core/builder/list/SourceListBuilder.java | 2 +- .../core/builder/map/SectionMapBuilder.java | 4 +- .../core/builder/map/SourceMapBuilder.java | 4 +- .../builder/value/SectionValueBuilder.java | 2 +- .../builder/value/SourceValueBuilder.java | 2 +- .../core/parser/ValueParser.java | 4 - .../core/source/ConfigurationProvider.java | 5 +- .../configuration/core/util/MapFactory.java | 67 ---------------- .../source/ConfigurationBuilder.java | 15 ++++ .../source/ConfigurationLoader.java | 4 + .../source/ConfigurationProvider.java | 6 ++ .../{core => }/value/ConfigValue.java | 2 +- .../{core => }/value/ValueManifest.java | 2 +- .../value/impl/CachedConfigValue.java | 6 +- .../{core => }/value/impl/ConfigValueMap.java | 4 +- .../standard}/ConfiguredList.java | 6 +- .../standard}/ConfiguredMap.java | 6 +- .../standard}/ConfiguredSection.java | 6 +- .../standard}/ConfiguredSectionMap.java | 6 +- .../standard}/ConfiguredValue.java | 6 +- core/src/test/java/AdaptTest.java | 31 ++++++++ .../demo/DatabaseConfiguration.java | 12 +-- .../demo/tests/conf/DemoConfiguration.java | 21 +++-- .../demo/tests/conf/TestConfiguration.java | 16 ++-- .../tests/conf/TestInnerConfiguration.java | 10 +-- .../lib/configuration/yaml/YAMLValue.java | 4 +- .../yaml/value/ConfiguredSerializable.java | 2 +- .../config/source/ModelConfiguration.java | 16 ++-- .../src/test/java/sample/SampleConfig.java | 10 +-- 39 files changed, 307 insertions(+), 166 deletions(-) create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapter.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapterRegistry.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/primitive/NumberAdapter.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java rename core/src/main/java/cc/carm/lib/configuration/{core => }/annotation/ConfigPath.java (95%) rename core/src/main/java/cc/carm/lib/configuration/{core => }/annotation/HeaderComment.java (94%) rename core/src/main/java/cc/carm/lib/configuration/{core => }/annotation/InlineComment.java (94%) delete mode 100644 core/src/main/java/cc/carm/lib/configuration/core/ConfigurationRoot.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/core/parser/ValueParser.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/core/util/MapFactory.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java rename core/src/main/java/cc/carm/lib/configuration/{core => }/value/ConfigValue.java (98%) rename core/src/main/java/cc/carm/lib/configuration/{core => }/value/ValueManifest.java (99%) rename core/src/main/java/cc/carm/lib/configuration/{core => }/value/impl/CachedConfigValue.java (88%) rename core/src/main/java/cc/carm/lib/configuration/{core => }/value/impl/ConfigValueMap.java (98%) rename core/src/main/java/cc/carm/lib/configuration/{core/value/type => value/standard}/ConfiguredList.java (97%) rename core/src/main/java/cc/carm/lib/configuration/{core/value/type => value/standard}/ConfiguredMap.java (86%) rename core/src/main/java/cc/carm/lib/configuration/{core/value/type => value/standard}/ConfiguredSection.java (94%) rename core/src/main/java/cc/carm/lib/configuration/{core/value/type => value/standard}/ConfiguredSectionMap.java (88%) rename core/src/main/java/cc/carm/lib/configuration/{core/value/type => value/standard}/ConfiguredValue.java (94%) create mode 100644 core/src/test/java/AdaptTest.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 new file mode 100644 index 0000000..738dc27 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapter.java @@ -0,0 +1,45 @@ +package cc.carm.lib.configuration.adapter; + +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; + +public abstract class ValueAdapter

{ + + protected final Class baseType; + protected final Class valueType; + + protected ValueAdapter(Class baseType, Class valueType) { + this.baseType = baseType; + this.valueType = valueType; + } + + public Class getBaseType() { + return baseType; + } + + public Class getValueType() { + return valueType; + } + + public abstract B serialize(@NotNull P provider, @NotNull V value) throws Exception; + + public abstract V deserialize(@NotNull P provider, @NotNull B data) throws Exception; + + public boolean isAdaptedFrom(Class clazz) { + return clazz.isAssignableFrom(valueType); + } + + public boolean isAdaptedFrom(Object object) { + return isAdaptedFrom(object.getClass()); + } + + protected final V deserializeObject(P provider, Object data) throws Exception { + return deserialize(provider, this.baseType.cast(data)); + } + + protected final B serializeObject(P provider, Object value) throws Exception { + return serialize(provider, this.valueType.cast(value)); + } + +} + 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 new file mode 100644 index 0000000..77eb729 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueAdapterRegistry.java @@ -0,0 +1,79 @@ +package cc.carm.lib.configuration.adapter; + +import cc.carm.lib.configuration.adapter.primitive.PrimitiveAdapter; +import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; + +public class ValueAdapterRegistry

{ + + protected final @NotNull P provider; + protected final Map, ValueAdapter> adapters = new HashMap<>(); + + public ValueAdapterRegistry(@NotNull P provider) { + this.provider = provider; + } + + public void register(@NotNull ValueAdapter adapter) { + adapters.put(adapter.valueType, adapter); + } + + public void register(Class baseClass, Class valueClass, + ConfigDataFunction parser, + ConfigDataFunction serializer) { + register(new ValueAdapter(baseClass, valueClass) { + @Override + public B serialize(@NotNull P provider, @NotNull V value) throws Exception { + return serializer.parse(value); + } + + @Override + public V deserialize(@NotNull P provider, @NotNull B data) throws Exception { + return parser.parse(data); + } + }); + } + + public void unregister(@NotNull Class typeClass) { + adapters.remove(typeClass); + } + + public T deserialize(Class type, Object value) throws Exception { + if (value == null) return null; + if (type == Object.class) return type.cast(value); + + ValueAdapter adapter = adapters.get(type); + if (adapter == null) throw new RuntimeException("No adapter for type " + type.getName()); + + // CHECK IF VALUE IS ADAPTED FROM GIVEN VALUE'S TYPE + if (adapter.isAdaptedFrom(value)) return type.cast(adapter.deserializeObject(provider, value)); + + // OTHERWISE, WE NEED TO DESERIALIZE ONE BY ONE + Object baseValue = deserialize(adapter.getBaseType(), value); + if (baseValue == null) return null; // Null check + + return type.cast(adapter.deserializeObject(provider, baseValue)); + } + + public Object serialize(T value) throws Exception { + if (value == null) return null; + + Class valueClass = value.getClass(); + ValueAdapter adapter = adapters.get(valueClass); + if (adapter == null) return value; // No adapters, try to return the original value + + if (adapter instanceof PrimitiveAdapter) { + // If the value is adapted from a primitive type, + // we should serialize it into object, then return. + return adapter.serializeObject(provider, value); + } + + // Otherwise, we need to serialize one by one. + return serialize(adapter.serializeObject(provider, value)); + } + + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/NumberAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/NumberAdapter.java new file mode 100644 index 0000000..fd535c0 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/NumberAdapter.java @@ -0,0 +1,24 @@ +package cc.carm.lib.configuration.adapter.primitive; + +import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; + +public abstract class NumberAdapter

extends PrimitiveAdapter { + + public static

NumberAdapter of(Class numberClass, + ConfigDataFunction function) { + return new NumberAdapter(numberClass) { + @Override + public T deserialize(@NotNull P provider, @NotNull Object data) throws Exception { + return function.parse(data); + } + }; + } + + protected NumberAdapter(Class valueType) { + super(valueType); + } + + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java new file mode 100644 index 0000000..1b80ea3 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java @@ -0,0 +1,18 @@ +package cc.carm.lib.configuration.adapter.primitive; + +import cc.carm.lib.configuration.adapter.ValueAdapter; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; + +public abstract class PrimitiveAdapter

extends ValueAdapter { + + protected PrimitiveAdapter(Class valueType) { + super(Object.class, valueType); + } + + @Override + public Object serialize(@NotNull P provider, @NotNull T value) throws Exception { + return value; + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/annotation/ConfigPath.java b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java similarity index 95% rename from core/src/main/java/cc/carm/lib/configuration/core/annotation/ConfigPath.java rename to core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java index 25fee49..01061e3 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/annotation/ConfigPath.java +++ b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.core.annotation; +package cc.carm.lib.configuration.annotation; import cc.carm.lib.configuration.core.ConfigInitializer; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/annotation/HeaderComment.java b/core/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java similarity index 94% rename from core/src/main/java/cc/carm/lib/configuration/core/annotation/HeaderComment.java rename to core/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java index 2089a46..284b290 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/annotation/HeaderComment.java +++ b/core/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.core.annotation; +package cc.carm.lib.configuration.annotation; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/annotation/InlineComment.java b/core/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java similarity index 94% rename from core/src/main/java/cc/carm/lib/configuration/core/annotation/InlineComment.java rename to core/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java index 1d3a750..d042da4 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/annotation/InlineComment.java +++ b/core/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.core.annotation; +package cc.carm.lib.configuration.annotation; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java b/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java index 1ea3f22..286b35e 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java @@ -1,10 +1,10 @@ package cc.carm.lib.configuration.core; -import cc.carm.lib.configuration.core.annotation.ConfigPath; -import cc.carm.lib.configuration.core.annotation.HeaderComment; -import cc.carm.lib.configuration.core.annotation.InlineComment; +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.core.source.ConfigurationProvider; -import cc.carm.lib.configuration.core.value.ConfigValue; +import cc.carm.lib.configuration.value.ConfigValue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/ConfigurationRoot.java b/core/src/main/java/cc/carm/lib/configuration/core/ConfigurationRoot.java deleted file mode 100644 index 8197290..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/core/ConfigurationRoot.java +++ /dev/null @@ -1,8 +0,0 @@ -package cc.carm.lib.configuration.core; - -/** - * The root node of the configuration file class, - * which is used to label and record the configuration information. - */ -public abstract class ConfigurationRoot implements Configuration { -} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java index eef1122..dc3dd81 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java @@ -1,8 +1,8 @@ package cc.carm.lib.configuration.core.builder; import cc.carm.lib.configuration.core.source.ConfigurationProvider; -import cc.carm.lib.configuration.core.value.ConfigValue; -import cc.carm.lib.configuration.core.value.ValueManifest; +import cc.carm.lib.configuration.value.ConfigValue; +import cc.carm.lib.configuration.value.ValueManifest; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java index 81ce353..e7e4367 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java @@ -2,7 +2,7 @@ package cc.carm.lib.configuration.core.builder.list; import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.value.type.ConfiguredList; +import cc.carm.lib.configuration.value.standard.ConfiguredList; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SectionMapBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SectionMapBuilder.java index e94fdbe..df57cf3 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SectionMapBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SectionMapBuilder.java @@ -3,8 +3,8 @@ package cc.carm.lib.configuration.core.builder.map; import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.configuration.core.value.ValueManifest; -import cc.carm.lib.configuration.core.value.type.ConfiguredSectionMap; +import cc.carm.lib.configuration.value.ValueManifest; +import cc.carm.lib.configuration.value.standard.ConfiguredSectionMap; import org.jetbrains.annotations.NotNull; import java.util.LinkedHashMap; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java index 90d6636..034f597 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java @@ -2,8 +2,8 @@ package cc.carm.lib.configuration.core.builder.map; import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.value.ValueManifest; -import cc.carm.lib.configuration.core.value.type.ConfiguredMap; +import cc.carm.lib.configuration.value.ValueManifest; +import cc.carm.lib.configuration.value.standard.ConfiguredMap; import org.jetbrains.annotations.NotNull; import java.util.Map; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java index ea29928..928860b 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java @@ -4,7 +4,7 @@ import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigValueParser; import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.configuration.core.value.type.ConfiguredSection; +import cc.carm.lib.configuration.value.standard.ConfiguredSection; import org.jetbrains.annotations.NotNull; import java.util.Map; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java index 203042a..57541fa 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java @@ -3,7 +3,7 @@ package cc.carm.lib.configuration.core.builder.value; import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigValueParser; -import cc.carm.lib.configuration.core.value.type.ConfiguredValue; +import cc.carm.lib.configuration.value.standard.ConfiguredValue; import org.jetbrains.annotations.NotNull; public class SourceValueBuilder extends CommonConfigBuilder> { diff --git a/core/src/main/java/cc/carm/lib/configuration/core/parser/ValueParser.java b/core/src/main/java/cc/carm/lib/configuration/core/parser/ValueParser.java deleted file mode 100644 index c65d828..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/core/parser/ValueParser.java +++ /dev/null @@ -1,4 +0,0 @@ -package cc.carm.lib.configuration.core.parser; - -public class ValueParser { -} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java b/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java index b628326..0252983 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java @@ -2,9 +2,8 @@ package cc.carm.lib.configuration.core.source; import cc.carm.lib.configuration.core.ConfigInitializer; import cc.carm.lib.configuration.core.Configuration; -import cc.carm.lib.configuration.core.Configuration; -import cc.carm.lib.configuration.core.value.ConfigValue; -import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; +import cc.carm.lib.configuration.value.ConfigValue; +import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Unmodifiable; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/util/MapFactory.java b/core/src/main/java/cc/carm/lib/configuration/core/util/MapFactory.java deleted file mode 100644 index 7fe98cc..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/core/util/MapFactory.java +++ /dev/null @@ -1,67 +0,0 @@ -package cc.carm.lib.configuration.core.util; - -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.TreeMap; - -public class MapFactory, K, V> { - - private final S map; - - protected MapFactory(S map) { - this.map = map; - } - - public MapFactory put(K key, V value) { - this.map.put(key, value); - return this; - } - - public MapFactory remove(K key) { - this.map.remove(key); - return this; - } - - public MapFactory clear() { - this.map.clear(); - return this; - } - - public S build() { - return get(); - } - - public S get() { - return map; - } - - public static MapFactory, K, V> hashMap() { - return new MapFactory<>(new HashMap<>()); - } - - public static MapFactory, K, V> hashMap(K firstKey, V firstValue) { - return MapFactory.hashMap().put(firstKey, firstValue); - } - - public static MapFactory, K, V> linkedMap() { - return of(new LinkedHashMap<>()); - } - - public static MapFactory, K, V> linkedMap(K firstKey, V firstValue) { - return MapFactory.linkedMap().put(firstKey, firstValue); - } - - public static , V> MapFactory, K, V> treeMap() { - return of(new TreeMap<>()); - } - - public static , V> MapFactory, K, V> treeMap(K firstKey, V firstValue) { - return MapFactory.treeMap().put(firstKey, firstValue); - } - - public static , K, V> MapFactory of(M map) { - return new MapFactory<>(map); - } - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java new file mode 100644 index 0000000..597bbcc --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java @@ -0,0 +1,15 @@ +package cc.carm.lib.configuration.source; + +import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; +import org.jetbrains.annotations.NotNull; + +public abstract class ConfigurationBuilder

{ + + protected ConfigurationLoader loader; + protected ValueAdapterRegistry

processors; + + + + public abstract @NotNull ConfigurationProvider build(); + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java new file mode 100644 index 0000000..79f0a5e --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java @@ -0,0 +1,4 @@ +package cc.carm.lib.configuration.source; + +public interface ConfigurationLoader { +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java new file mode 100644 index 0000000..89354f3 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java @@ -0,0 +1,6 @@ +package cc.carm.lib.configuration.source; + +public class ConfigurationProvider { + + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/ConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java similarity index 98% rename from core/src/main/java/cc/carm/lib/configuration/core/value/ConfigValue.java rename to core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java index f8028ca..8b6ecd7 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/ConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.core.value; +package cc.carm.lib.configuration.value; import cc.carm.lib.configuration.core.builder.ConfigBuilder; import cc.carm.lib.configuration.core.source.ConfigurationProvider; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/ValueManifest.java b/core/src/main/java/cc/carm/lib/configuration/value/ValueManifest.java similarity index 99% rename from core/src/main/java/cc/carm/lib/configuration/core/value/ValueManifest.java rename to core/src/main/java/cc/carm/lib/configuration/value/ValueManifest.java index cde0cc2..9dd4888 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/ValueManifest.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/ValueManifest.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.core.value; +package cc.carm.lib.configuration.value; import cc.carm.lib.configuration.core.ConfigInitializer; import cc.carm.lib.configuration.core.source.ConfigurationProvider; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/impl/CachedConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java similarity index 88% rename from core/src/main/java/cc/carm/lib/configuration/core/value/impl/CachedConfigValue.java rename to core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java index c5fcf0d..92cd162 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/impl/CachedConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java @@ -1,7 +1,7 @@ -package cc.carm.lib.configuration.core.value.impl; +package cc.carm.lib.configuration.value.impl; -import cc.carm.lib.configuration.core.value.ConfigValue; -import cc.carm.lib.configuration.core.value.ValueManifest; +import cc.carm.lib.configuration.value.ConfigValue; +import cc.carm.lib.configuration.value.ValueManifest; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/impl/ConfigValueMap.java b/core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java similarity index 98% rename from core/src/main/java/cc/carm/lib/configuration/core/value/impl/ConfigValueMap.java rename to core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java index b68304e..f45b057 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/impl/ConfigValueMap.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java @@ -1,9 +1,9 @@ -package cc.carm.lib.configuration.core.value.impl; +package cc.carm.lib.configuration.value.impl; import cc.carm.lib.configuration.core.builder.map.ConfigMapCreator; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.configuration.core.value.ValueManifest; +import cc.carm.lib.configuration.value.ValueManifest; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Unmodifiable; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredList.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java similarity index 97% rename from core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredList.java rename to core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java index 567be17..555d4b2 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredList.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java @@ -1,9 +1,9 @@ -package cc.carm.lib.configuration.core.value.type; +package cc.carm.lib.configuration.value.standard; import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.value.ValueManifest; -import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; +import cc.carm.lib.configuration.value.ValueManifest; +import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredMap.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java similarity index 86% rename from core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredMap.java rename to core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java index 75fe74b..5e4c086 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredMap.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java @@ -1,9 +1,9 @@ -package cc.carm.lib.configuration.core.value.type; +package cc.carm.lib.configuration.value.standard; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.configuration.core.value.ValueManifest; -import cc.carm.lib.configuration.core.value.impl.ConfigValueMap; +import cc.carm.lib.configuration.value.ValueManifest; +import cc.carm.lib.configuration.value.impl.ConfigValueMap; import org.jetbrains.annotations.NotNull; import java.util.Map; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredSection.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java similarity index 94% rename from core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredSection.java rename to core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java index 76d807e..718de8d 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredSection.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java @@ -1,11 +1,11 @@ -package cc.carm.lib.configuration.core.value.type; +package cc.carm.lib.configuration.value.standard; import cc.carm.lib.configuration.core.builder.value.SectionValueBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigValueParser; import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.configuration.core.value.ValueManifest; -import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; +import cc.carm.lib.configuration.value.ValueManifest; +import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredSectionMap.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java similarity index 88% rename from core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredSectionMap.java rename to core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java index 9d120e6..4d3a35c 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredSectionMap.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java @@ -1,9 +1,9 @@ -package cc.carm.lib.configuration.core.value.type; +package cc.carm.lib.configuration.value.standard; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.configuration.core.value.ValueManifest; -import cc.carm.lib.configuration.core.value.impl.ConfigValueMap; +import cc.carm.lib.configuration.value.ValueManifest; +import cc.carm.lib.configuration.value.impl.ConfigValueMap; import org.jetbrains.annotations.NotNull; import java.util.Map; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredValue.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java similarity index 94% rename from core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredValue.java rename to core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java index 6a95b39..6b962f4 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredValue.java @@ -1,10 +1,10 @@ -package cc.carm.lib.configuration.core.value.type; +package cc.carm.lib.configuration.value.standard; import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigValueParser; -import cc.carm.lib.configuration.core.value.ValueManifest; -import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; +import cc.carm.lib.configuration.value.ValueManifest; +import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/test/java/AdaptTest.java b/core/src/test/java/AdaptTest.java new file mode 100644 index 0000000..6600144 --- /dev/null +++ b/core/src/test/java/AdaptTest.java @@ -0,0 +1,31 @@ +import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; +import cc.carm.lib.configuration.adapter.primitive.NumberAdapter; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.junit.Test; + +import java.time.Duration; +import java.time.LocalTime; + +public class AdaptTest { + + @Test + public void test() throws Exception { + + ValueAdapterRegistry registry = new ValueAdapterRegistry<>(new ConfigurationProvider()); + registry.register(NumberAdapter.of(Long.class, data -> Long.parseLong(data.toString()))); + registry.register(NumberAdapter.of(long.class, data -> Long.parseLong(data.toString()))); + registry.register(Long.class, Duration.class, Duration::ofSeconds, Duration::getSeconds); + registry.register( + Duration.class, LocalTime.class, + duration -> LocalTime.now().plus(duration), + data -> Duration.between(data, LocalTime.now()) + ); + + LocalTime v = registry.deserialize(LocalTime.class, "600"); + Object d = registry.serialize(v); + + System.out.println(v); + System.out.println(d); + } + +} 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 0d93407..5e662ea 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,13 +1,13 @@ package cc.carm.lib.configuration.demo; -import cc.carm.lib.configuration.core.ConfigurationRoot; -import cc.carm.lib.configuration.core.annotation.ConfigPath; -import cc.carm.lib.configuration.core.annotation.HeaderComment; -import cc.carm.lib.configuration.core.value.ConfigValue; -import cc.carm.lib.configuration.core.value.type.ConfiguredValue; +import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.configuration.annotation.ConfigPath; +import cc.carm.lib.configuration.annotation.HeaderComment; +import cc.carm.lib.configuration.value.ConfigValue; +import cc.carm.lib.configuration.value.standard.ConfiguredValue; @HeaderComment({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"}) -public class DatabaseConfiguration extends ConfigurationRoot { +public class DatabaseConfiguration implements Configuration { @ConfigPath("driver") @HeaderComment({ 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 d288459..feef0a4 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 @@ -2,15 +2,14 @@ package cc.carm.lib.configuration.demo.tests.conf; import cc.carm.lib.configuration.core.ConfigInitializer; import cc.carm.lib.configuration.core.Configuration; -import cc.carm.lib.configuration.core.ConfigurationRoot; -import cc.carm.lib.configuration.core.annotation.ConfigPath; -import cc.carm.lib.configuration.core.annotation.HeaderComment; -import cc.carm.lib.configuration.core.annotation.InlineComment; -import cc.carm.lib.configuration.core.value.ConfigValue; -import cc.carm.lib.configuration.core.value.type.ConfiguredList; -import cc.carm.lib.configuration.core.value.type.ConfiguredMap; -import cc.carm.lib.configuration.core.value.type.ConfiguredSection; -import cc.carm.lib.configuration.core.value.type.ConfiguredValue; +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.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; @@ -56,7 +55,7 @@ public interface DemoConfiguration extends Configuration { * 支持内部类的直接注册。 * 注意,需要使用 {@link ConfigInitializer#initialize(Class, boolean, boolean)} 方法,并设定第三个参数为 true。 */ - class Sub extends ConfigurationRoot { + class Sub implements Configuration { @ConfigPath(value = "uuid-value", root = true) @InlineComment("This is an inline comment") @@ -65,7 +64,7 @@ public interface DemoConfiguration extends Configuration { .parseValue((data, defaultValue) -> UUID.fromString(data)) .build(); - public static class That extends ConfigurationRoot { + public static class That implements Configuration { public static final ConfiguredList OPERATORS = ConfiguredList .builderOf(UUID.class).fromString() 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 e9a3257..c242e4a 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,17 +1,17 @@ package cc.carm.lib.configuration.demo.tests.conf; -import cc.carm.lib.configuration.core.ConfigurationRoot; -import cc.carm.lib.configuration.core.annotation.ConfigPath; -import cc.carm.lib.configuration.core.annotation.HeaderComment; -import cc.carm.lib.configuration.core.annotation.InlineComment; -import cc.carm.lib.configuration.core.value.ConfigValue; -import cc.carm.lib.configuration.core.value.type.ConfiguredSection; -import cc.carm.lib.configuration.core.value.type.ConfiguredValue; +import cc.carm.lib.configuration.core.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 java.util.UUID; -public class TestConfiguration extends ConfigurationRoot { +public class TestConfiguration implements Configuration { public final TestInnerConfiguration INNER = new TestInnerConfiguration(); 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 8385a6a..ba61899 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,12 +1,12 @@ package cc.carm.lib.configuration.demo.tests.conf; -import cc.carm.lib.configuration.core.ConfigurationRoot; -import cc.carm.lib.configuration.core.annotation.HeaderComment; -import cc.carm.lib.configuration.core.value.ConfigValue; -import cc.carm.lib.configuration.core.value.type.ConfiguredValue; +import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.configuration.annotation.HeaderComment; +import cc.carm.lib.configuration.value.ConfigValue; +import cc.carm.lib.configuration.value.standard.ConfiguredValue; @HeaderComment("Inner Test") -public class TestInnerConfiguration extends ConfigurationRoot { +public class TestInnerConfiguration implements Configuration { public final ConfigValue INNER_VALUE = ConfiguredValue.of(Double.class, 1.0D); diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java index 25179cd..5e16ff3 100644 --- a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java +++ b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java @@ -1,8 +1,8 @@ package cc.carm.lib.configuration.yaml; import cc.carm.lib.configuration.core.source.ConfigurationProvider; -import cc.carm.lib.configuration.core.value.ValueManifest; -import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; +import cc.carm.lib.configuration.value.ValueManifest; +import cc.carm.lib.configuration.value.impl.CachedConfigValue; import cc.carm.lib.configuration.yaml.builder.YAMLConfigBuilder; import org.jetbrains.annotations.NotNull; diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java index 59f5536..454824b 100644 --- a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java +++ b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.yaml.value; -import cc.carm.lib.configuration.core.value.ValueManifest; +import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.yaml.YAMLValue; import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; import org.jetbrains.annotations.NotNull; diff --git a/impl/yaml/src/test/java/config/source/ModelConfiguration.java b/impl/yaml/src/test/java/config/source/ModelConfiguration.java index 61eab06..021c6a3 100644 --- a/impl/yaml/src/test/java/config/source/ModelConfiguration.java +++ b/impl/yaml/src/test/java/config/source/ModelConfiguration.java @@ -1,12 +1,12 @@ package config.source; -import cc.carm.lib.configuration.core.ConfigurationRoot; -import cc.carm.lib.configuration.core.annotation.ConfigPath; -import cc.carm.lib.configuration.core.annotation.HeaderComment; -import cc.carm.lib.configuration.core.value.ConfigValue; -import cc.carm.lib.configuration.core.value.type.ConfiguredList; -import cc.carm.lib.configuration.core.value.type.ConfiguredMap; -import cc.carm.lib.configuration.core.value.type.ConfiguredSectionMap; +import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.configuration.annotation.ConfigPath; +import cc.carm.lib.configuration.annotation.HeaderComment; +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.ConfiguredSectionMap; import cc.carm.lib.configuration.demo.tests.model.AbstractModel; import cc.carm.lib.configuration.yaml.value.ConfiguredSerializable; import config.model.AnyModel; @@ -14,7 +14,7 @@ import config.model.SomeModel; @HeaderComment("以下内容用于测试序列化") @ConfigPath("model-test") -public class ModelConfiguration extends ConfigurationRoot { +public class ModelConfiguration implements Configuration { public static final ConfigValue SOME_MODEL = ConfiguredSerializable.of( SomeModel.class, SomeModel.random() diff --git a/impl/yaml/src/test/java/sample/SampleConfig.java b/impl/yaml/src/test/java/sample/SampleConfig.java index 6e32128..7b71a42 100644 --- a/impl/yaml/src/test/java/sample/SampleConfig.java +++ b/impl/yaml/src/test/java/sample/SampleConfig.java @@ -1,11 +1,11 @@ package sample; import cc.carm.lib.configuration.core.Configuration; -import cc.carm.lib.configuration.core.annotation.ConfigPath; -import cc.carm.lib.configuration.core.annotation.HeaderComment; -import cc.carm.lib.configuration.core.annotation.InlineComment; -import cc.carm.lib.configuration.core.value.type.ConfiguredList; -import cc.carm.lib.configuration.core.value.type.ConfiguredValue; +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.standard.ConfiguredList; +import cc.carm.lib.configuration.value.standard.ConfiguredValue; import java.util.UUID; From d041828717f33e95c13929facfbebb1ab9629d7a Mon Sep 17 00:00:00 2001 From: carm Date: Tue, 16 Jan 2024 02:59:21 +0800 Subject: [PATCH 03/17] feat(adapter): Use registry to manage value adapters --- .../adapter/ValueAdapterRegistry.java | 5 ++-- .../adapter/primitive/NumberAdapter.java | 24 ------------------- .../adapter/primitive/PrimitiveAdapter.java | 12 ++++++++++ core/src/test/java/AdaptTest.java | 7 +++--- 4 files changed, 19 insertions(+), 29 deletions(-) delete mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/primitive/NumberAdapter.java 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 77eb729..5540d19 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 @@ -41,6 +41,7 @@ public class ValueAdapterRegistry

{ adapters.remove(typeClass); } + @SuppressWarnings("unchecked") public T deserialize(Class type, Object value) throws Exception { if (value == null) return null; if (type == Object.class) return type.cast(value); @@ -49,13 +50,13 @@ public class ValueAdapterRegistry

{ if (adapter == null) throw new RuntimeException("No adapter for type " + type.getName()); // CHECK IF VALUE IS ADAPTED FROM GIVEN VALUE'S TYPE - if (adapter.isAdaptedFrom(value)) return type.cast(adapter.deserializeObject(provider, value)); + if (adapter.isAdaptedFrom(value)) return (T) adapter.deserializeObject(provider, value); // OTHERWISE, WE NEED TO DESERIALIZE ONE BY ONE Object baseValue = deserialize(adapter.getBaseType(), value); if (baseValue == null) return null; // Null check - return type.cast(adapter.deserializeObject(provider, baseValue)); + return (T) adapter.deserializeObject(provider, baseValue); } public Object serialize(T value) throws Exception { diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/NumberAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/NumberAdapter.java deleted file mode 100644 index fd535c0..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/NumberAdapter.java +++ /dev/null @@ -1,24 +0,0 @@ -package cc.carm.lib.configuration.adapter.primitive; - -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.source.ConfigurationProvider; -import org.jetbrains.annotations.NotNull; - -public abstract class NumberAdapter

extends PrimitiveAdapter { - - public static

NumberAdapter of(Class numberClass, - ConfigDataFunction function) { - return new NumberAdapter(numberClass) { - @Override - public T deserialize(@NotNull P provider, @NotNull Object data) throws Exception { - return function.parse(data); - } - }; - } - - protected NumberAdapter(Class valueType) { - super(valueType); - } - - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java index 1b80ea3..4c484dd 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java @@ -1,11 +1,23 @@ package cc.carm.lib.configuration.adapter.primitive; import cc.carm.lib.configuration.adapter.ValueAdapter; +import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.NotNull; public abstract class PrimitiveAdapter

extends ValueAdapter { + public static

PrimitiveAdapter of(@NotNull Class clazz, + @NotNull ConfigDataFunction function) { + return new PrimitiveAdapter(clazz) { + @Override + public T deserialize(@NotNull P provider, @NotNull Object data) throws Exception { + return function.parse(data); + } + }; + } + + protected PrimitiveAdapter(Class valueType) { super(Object.class, valueType); } diff --git a/core/src/test/java/AdaptTest.java b/core/src/test/java/AdaptTest.java index 6600144..077dc9d 100644 --- a/core/src/test/java/AdaptTest.java +++ b/core/src/test/java/AdaptTest.java @@ -1,5 +1,5 @@ import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; -import cc.carm.lib.configuration.adapter.primitive.NumberAdapter; +import cc.carm.lib.configuration.adapter.primitive.PrimitiveAdapter; import cc.carm.lib.configuration.source.ConfigurationProvider; import org.junit.Test; @@ -12,8 +12,9 @@ public class AdaptTest { public void test() throws Exception { ValueAdapterRegistry registry = new ValueAdapterRegistry<>(new ConfigurationProvider()); - registry.register(NumberAdapter.of(Long.class, data -> Long.parseLong(data.toString()))); - registry.register(NumberAdapter.of(long.class, data -> Long.parseLong(data.toString()))); + registry.register(PrimitiveAdapter.of(Long.class, data -> Long.parseLong(data.toString()))); + registry.register(PrimitiveAdapter.of(Integer.class, data -> Integer.parseInt(data.toString()))); + registry.register(PrimitiveAdapter.of(long.class, data -> Long.parseLong(data.toString()))); registry.register(Long.class, Duration.class, Duration::ofSeconds, Duration::getSeconds); registry.register( Duration.class, LocalTime.class, From 2df33e34589ca3e756aba3d6ad95aa550e1a934a Mon Sep 17 00:00:00 2001 From: carm Date: Tue, 16 Jan 2024 03:50:08 +0800 Subject: [PATCH 04/17] feat(adapter): Finished adapters registry --- .../configuration/adapter/ValueAdapter.java | 31 +++++--- .../adapter/ValueAdapterRegistry.java | 28 +++++--- .../adapter/primitive/PrimitiveAdapter.java | 30 -------- .../adapter/strandard/EnumAdapter.java | 24 +++++++ .../adapter/strandard/PrimitiveAdapters.java | 70 +++++++++++++++++++ core/src/test/java/AdaptTest.java | 31 ++++++-- 6 files changed, 163 insertions(+), 51 deletions(-) delete mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.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 738dc27..c0782fa 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 @@ -3,27 +3,34 @@ package cc.carm.lib.configuration.adapter; import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.NotNull; +/** + * Value adapter, used to convert the value of the configuration file into the objects. + * + * @param

The type of the configuration provider. + * @param The type of the base data + * @param The type of the target value + */ public abstract class ValueAdapter

{ - protected final Class baseType; - protected final Class valueType; + protected final Class baseType; + protected final Class valueType; - protected ValueAdapter(Class baseType, Class valueType) { + protected ValueAdapter(Class baseType, Class valueType) { this.baseType = baseType; this.valueType = valueType; } - public Class getBaseType() { + public Class getBaseClass() { return baseType; } - public Class getValueType() { + public Class getValueClass() { return valueType; } public abstract B serialize(@NotNull P provider, @NotNull V value) throws Exception; - public abstract V deserialize(@NotNull P provider, @NotNull B data) throws Exception; + public abstract V deserialize(@NotNull P provider, @NotNull Class clazz, @NotNull B data) throws Exception; public boolean isAdaptedFrom(Class clazz) { return clazz.isAssignableFrom(valueType); @@ -33,12 +40,18 @@ public abstract class ValueAdapter

{ return isAdaptedFrom(object.getClass()); } - protected final V deserializeObject(P provider, Object data) throws Exception { - return deserialize(provider, this.baseType.cast(data)); + public boolean isAdapterOf(Class clazz) { + return valueType.isAssignableFrom(clazz); } + @SuppressWarnings("unchecked") + protected final V deserializeObject(P provider, Class valueClass, Object data) throws Exception { + return deserialize(provider, (Class) valueClass, (B) data); + } + + @SuppressWarnings("unchecked") protected final B serializeObject(P provider, Object value) throws Exception { - return serialize(provider, this.valueType.cast(value)); + return serialize(provider, (V) value); } } 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 5540d19..607aa0b 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 @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.adapter; -import cc.carm.lib.configuration.adapter.primitive.PrimitiveAdapter; +import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.NotNull; @@ -18,7 +18,11 @@ public class ValueAdapterRegistry

{ } public void register(@NotNull ValueAdapter adapter) { - adapters.put(adapter.valueType, adapter); + adapters.put(adapter.getValueClass(), adapter); + } + + public void register(Class clazz, @NotNull ValueAdapter adapter) { + adapters.put(clazz, adapter); } public void register(Class baseClass, Class valueClass, @@ -31,7 +35,7 @@ public class ValueAdapterRegistry

{ } @Override - public V deserialize(@NotNull P provider, @NotNull B data) throws Exception { + public V deserialize(@NotNull P provider, @NotNull Class clazz, @NotNull B data) throws Exception { return parser.parse(data); } }); @@ -46,17 +50,19 @@ public class ValueAdapterRegistry

{ if (value == null) return null; if (type == Object.class) return type.cast(value); - ValueAdapter adapter = adapters.get(type); + ValueAdapter adapter = getAdapter(type); if (adapter == null) throw new RuntimeException("No adapter for type " + type.getName()); // CHECK IF VALUE IS ADAPTED FROM GIVEN VALUE'S TYPE - if (adapter.isAdaptedFrom(value)) return (T) adapter.deserializeObject(provider, value); + if (adapter.isAdaptedFrom(value)) { + return (T) adapter.deserializeObject(provider, type, value); + } // OTHERWISE, WE NEED TO DESERIALIZE ONE BY ONE - Object baseValue = deserialize(adapter.getBaseType(), value); + Object baseValue = deserialize(adapter.getBaseClass(), value); if (baseValue == null) return null; // Null check - return (T) adapter.deserializeObject(provider, baseValue); + return (T) adapter.deserializeObject(provider, type, baseValue); } public Object serialize(T value) throws Exception { @@ -66,7 +72,7 @@ public class ValueAdapterRegistry

{ ValueAdapter adapter = adapters.get(valueClass); if (adapter == null) return value; // No adapters, try to return the original value - if (adapter instanceof PrimitiveAdapter) { + if (adapter instanceof PrimitiveAdapters) { // If the value is adapted from a primitive type, // we should serialize it into object, then return. return adapter.serializeObject(provider, value); @@ -76,5 +82,11 @@ public class ValueAdapterRegistry

{ return serialize(adapter.serializeObject(provider, value)); } + public ValueAdapter getAdapter(Class clazz) { + ValueAdapter byClass = adapters.get(clazz); + if (byClass != null) return byClass; + return adapters.values().stream().filter(adapter -> adapter.isAdapterOf(clazz)).findFirst().orElse(null); + } + } diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java deleted file mode 100644 index 4c484dd..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/primitive/PrimitiveAdapter.java +++ /dev/null @@ -1,30 +0,0 @@ -package cc.carm.lib.configuration.adapter.primitive; - -import cc.carm.lib.configuration.adapter.ValueAdapter; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.source.ConfigurationProvider; -import org.jetbrains.annotations.NotNull; - -public abstract class PrimitiveAdapter

extends ValueAdapter { - - public static

PrimitiveAdapter of(@NotNull Class clazz, - @NotNull ConfigDataFunction function) { - return new PrimitiveAdapter(clazz) { - @Override - public T deserialize(@NotNull P provider, @NotNull Object data) throws Exception { - return function.parse(data); - } - }; - } - - - protected PrimitiveAdapter(Class valueType) { - super(Object.class, valueType); - } - - @Override - public Object serialize(@NotNull P provider, @NotNull T value) throws Exception { - return value; - } - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java new file mode 100644 index 0000000..40bd3c4 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java @@ -0,0 +1,24 @@ +package cc.carm.lib.configuration.adapter.strandard; + +import cc.carm.lib.configuration.adapter.ValueAdapter; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public class EnumAdapter

extends ValueAdapter { + + public EnumAdapter() { + super(String.class, Enum.class); + } + + @Override + public String serialize(@NotNull P provider, @NotNull Enum value) throws Exception { + return value.name(); + } + + @Override + public Enum deserialize(@NotNull P provider, @NotNull Class clazz, @NotNull String data) throws Exception { + return Enum.valueOf(clazz, data); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java new file mode 100644 index 0000000..6062b7b --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java @@ -0,0 +1,70 @@ +package cc.carm.lib.configuration.adapter.strandard; + +import cc.carm.lib.configuration.adapter.ValueAdapter; +import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; + +public abstract class PrimitiveAdapters

extends ValueAdapter { + + public static

PrimitiveAdapters ofString() { + return of(String.class, o -> o instanceof String ? (String) o : o.toString()); + } + + public static

PrimitiveAdapters ofBoolean() { + return of(Boolean.class, o -> o instanceof Boolean ? (Boolean) o : Boolean.parseBoolean(o.toString())); + } + + public static

PrimitiveAdapters ofCharacter() { + return of(Character.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0)); + } + + public static

PrimitiveAdapters ofInteger() { + return ofNumber(Integer.class, Number::intValue, Integer::parseInt); + } + + public static

PrimitiveAdapters ofLong() { + return ofNumber(Long.class, Number::longValue, Long::parseLong); + } + + public static

PrimitiveAdapters ofDouble() { + return ofNumber(Double.class, Number::doubleValue, Double::parseDouble); + } + + public static

PrimitiveAdapters ofFloat() { + return ofNumber(Float.class, Number::floatValue, Float::parseFloat); + } + + public static

PrimitiveAdapters ofShort() { + return ofNumber(Short.class, Number::shortValue, Short::parseShort); + } + + public static

PrimitiveAdapters ofByte() { + return ofNumber(Byte.class, Number::byteValue, Byte::parseByte); + } + + protected PrimitiveAdapters(Class valueType) { + super(Object.class, valueType); + } + + @Override + public Object serialize(@NotNull P provider, @NotNull T value) throws Exception { + return value; + } + + public static

PrimitiveAdapters of(@NotNull Class clazz, + @NotNull ConfigDataFunction function) { + return new PrimitiveAdapters(clazz) { + @Override + public T deserialize(@NotNull P provider, @NotNull Class clazz, @NotNull Object data) throws Exception { + return function.parse(data); + } + }; + } + + public static

PrimitiveAdapters ofNumber(@NotNull Class numberClass, + @NotNull ConfigDataFunction castFunction, + @NotNull ConfigDataFunction parseFunction) { + return of(numberClass, o -> o instanceof Number ? castFunction.parse((Number) o) : parseFunction.parse(o.toString())); + } +} diff --git a/core/src/test/java/AdaptTest.java b/core/src/test/java/AdaptTest.java index 077dc9d..35be94b 100644 --- a/core/src/test/java/AdaptTest.java +++ b/core/src/test/java/AdaptTest.java @@ -1,5 +1,6 @@ import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; -import cc.carm.lib.configuration.adapter.primitive.PrimitiveAdapter; +import cc.carm.lib.configuration.adapter.strandard.EnumAdapter; +import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters; import cc.carm.lib.configuration.source.ConfigurationProvider; import org.junit.Test; @@ -12,9 +13,25 @@ public class AdaptTest { public void test() throws Exception { ValueAdapterRegistry registry = new ValueAdapterRegistry<>(new ConfigurationProvider()); - registry.register(PrimitiveAdapter.of(Long.class, data -> Long.parseLong(data.toString()))); - registry.register(PrimitiveAdapter.of(Integer.class, data -> Integer.parseInt(data.toString()))); - registry.register(PrimitiveAdapter.of(long.class, data -> Long.parseLong(data.toString()))); + registry.register(Long.class, PrimitiveAdapters.ofLong()); + registry.register(long.class, PrimitiveAdapters.ofLong()); + registry.register(Integer.class, PrimitiveAdapters.ofInteger()); + registry.register(int.class, PrimitiveAdapters.ofInteger()); + registry.register(Double.class, PrimitiveAdapters.ofDouble()); + registry.register(double.class, PrimitiveAdapters.ofDouble()); + registry.register(Float.class, PrimitiveAdapters.ofFloat()); + registry.register(float.class, PrimitiveAdapters.ofFloat()); + registry.register(Short.class, PrimitiveAdapters.ofShort()); + registry.register(short.class, PrimitiveAdapters.ofShort()); + registry.register(Byte.class, PrimitiveAdapters.ofByte()); + registry.register(byte.class, PrimitiveAdapters.ofByte()); + registry.register(Character.class, PrimitiveAdapters.ofCharacter()); + registry.register(char.class, PrimitiveAdapters.ofCharacter()); + registry.register(Boolean.class, PrimitiveAdapters.ofBoolean()); + registry.register(boolean.class, PrimitiveAdapters.ofBoolean()); + registry.register(String.class, PrimitiveAdapters.ofString()); + registry.register(new EnumAdapter<>()); + registry.register(Long.class, Duration.class, Duration::ofSeconds, Duration::getSeconds); registry.register( Duration.class, LocalTime.class, @@ -25,8 +42,14 @@ public class AdaptTest { LocalTime v = registry.deserialize(LocalTime.class, "600"); Object d = registry.serialize(v); + System.out.println(v); System.out.println(d); + System.out.println(registry.deserialize(TestEnum.class, "b")); + } + + enum TestEnum { + A, b, C } } From b912ea369c953a11a93a7aea0e30002e0705bc15 Mon Sep 17 00:00:00 2001 From: carm Date: Tue, 16 Jan 2024 23:25:21 +0800 Subject: [PATCH 05/17] feat(loader): Refactor loaders and metadata. --- commentable/pom.xml | 29 ++ .../annotation/HeaderComment.java | 0 .../annotation/InlineComment.java | 0 .../commentable/CommentableMetaTypes.java | 26 ++ .../commentable/CommentableOptions.java | 26 ++ .../commentable}/ConfigurationComments.java | 5 +- core/pom.xml | 13 + .../configuration/adapter/ValueAdapter.java | 10 +- .../adapter/ValueAdapterRegistry.java | 40 +-- .../adapter/ValueDeserializer.java | 18 ++ .../adapter/ValueSerializer.java | 18 ++ .../adapter/strandard/EnumAdapter.java | 5 + .../configuration/annotation/ConfigPath.java | 4 +- .../configuration/core/ConfigInitializer.java | 275 ------------------ .../lib/configuration/core/Configuration.java | 1 + .../core/source/ConfigurationProvider.java | 2 +- .../configuration/manifest/ValueManifest.java | 8 + .../source/ConfigurationBuilder.java | 78 ++++- .../source/ConfigurationLoader.java | 194 +++++++++++- .../source/ConfigurationProvider.java | 33 ++- .../source/path/PathGenerator.java | 33 +++ .../source/path/StandardPathGenerator.java | 74 +++++ .../standard/ConfigurationMetaTypes.java | 12 + .../source/standard/ConfigurationOptions.java | 30 ++ .../configuration/value/ValueManifest.java | 1 - core/src/test/java/AdaptTest.java | 13 +- core/src/test/java/NameTest.java | 1 - .../demo/tests/conf/DemoConfiguration.java | 1 - .../hocon/HOCONFileConfigProvider.java | 3 +- .../json/JSONConfigProvider.java | 3 +- .../configuration/sql/SQLConfigProvider.java | 3 +- .../yaml/YAMLConfigProvider.java | 4 +- pom.xml | 1 + 33 files changed, 632 insertions(+), 332 deletions(-) create mode 100644 commentable/pom.xml rename {core => commentable}/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java (100%) rename {core => commentable}/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java (100%) create mode 100644 commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java create mode 100644 commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableOptions.java rename {core/src/main/java/cc/carm/lib/configuration/core/source => commentable/src/main/java/cc/carm/lib/configuration/commentable}/ConfigurationComments.java (96%) create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/manifest/ValueManifest.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/path/PathGenerator.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/path/StandardPathGenerator.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationMetaTypes.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationOptions.java diff --git a/commentable/pom.xml b/commentable/pom.xml new file mode 100644 index 0000000..d58cdcb --- /dev/null +++ b/commentable/pom.xml @@ -0,0 +1,29 @@ + + + 4.0.0 + + cc.carm.lib + easyconfiguration-parent + 3.9.1 + + + ${project.jdk.version} + ${project.jdk.version} + UTF-8 + UTF-8 + + + easyconfiguration-commentable + + + + + ${project.groupId} + easyconfiguration-core + ${project.version} + + + + \ No newline at end of file diff --git a/core/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java b/commentable/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java similarity index 100% rename from core/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java rename to commentable/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java diff --git a/core/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java b/commentable/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java similarity index 100% rename from core/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java rename to commentable/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java diff --git a/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java b/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java new file mode 100644 index 0000000..372fe98 --- /dev/null +++ b/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java @@ -0,0 +1,26 @@ +package cc.carm.lib.configuration.commentable; + +import cc.carm.lib.configuration.annotation.HeaderComment; +import cc.carm.lib.configuration.annotation.InlineComment; +import cc.carm.lib.easyannotation.AnnotatedMetaType; + +import java.util.Arrays; +import java.util.List; + +public interface CommentableMetaTypes { + + /** + * Configuration's {@link HeaderComment} + */ + AnnotatedMetaType> HEADER_COMMENT = AnnotatedMetaType.of( + HeaderComment.class, h -> h.value().length == 0 ? null : Arrays.asList(h.value()) + ); + + /** + * Configuration's {@link InlineComment} + */ + AnnotatedMetaType INLINE_COMMENT = AnnotatedMetaType.of( + InlineComment.class, c -> c.value().isEmpty() ? null : c.value() + ); + +} diff --git a/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableOptions.java b/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableOptions.java new file mode 100644 index 0000000..7fcfc0d --- /dev/null +++ b/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableOptions.java @@ -0,0 +1,26 @@ +package cc.carm.lib.configuration.commentable; + +import cc.carm.lib.easyoptions.OptionType; + +import static cc.carm.lib.easyoptions.OptionType.of; + +public interface CommentableOptions { + + /** + * Whether to keep modified comments in configuration, + * that means we only set comments for values that are not exists in configuration. + */ + OptionType KEEP_COMMENTS = OptionType.of(true); + + /** + * Whether to comment values name that are not exists in configuration and no default value offered. + *
If true, a value without default value is not exists in configuration, we will comment its name, + *

e.g. a value named "foo" without default value will be put as: + *

+     * # Value comments
+     * # foo:
+     * 
+ */ + OptionType COMMENT_NO_DEFAULT = OptionType.of(true); + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationComments.java b/commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java similarity index 96% rename from core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationComments.java rename to commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java index e6775cb..c7b9ba0 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationComments.java +++ b/commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.core.source; +package cc.carm.lib.configuration.commentable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,7 +20,6 @@ public class ConfigurationComments { } public void setHeaderComments(@Nullable String path, @Nullable List comments) { - if (comments == null) { getHeaderComments().remove(path); } else { @@ -28,7 +27,6 @@ public class ConfigurationComments { } } - public void setInlineComment(@NotNull String path, @Nullable String comment) { if (comment == null) { getInlineComments().remove(path); @@ -47,5 +45,4 @@ public class ConfigurationComments { return getInlineComments().get(path); } - } diff --git a/core/pom.xml b/core/pom.xml index 5f9a61e..c3b88a3 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -18,6 +18,19 @@ easyconfiguration-core jar + + + cc.carm.lib + easyoptions + 1.0.0 + + + cc.carm.lib + easyannotation + 1.0.0 + + + 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 c0782fa..ab265d3 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 @@ -1,7 +1,6 @@ package cc.carm.lib.configuration.adapter; import cc.carm.lib.configuration.source.ConfigurationProvider; -import org.jetbrains.annotations.NotNull; /** * Value adapter, used to convert the value of the configuration file into the objects. @@ -10,7 +9,8 @@ import org.jetbrains.annotations.NotNull; * @param The type of the base data * @param The type of the target value */ -public abstract class ValueAdapter

{ +public abstract class ValueAdapter

+ implements ValueSerializer, ValueDeserializer { protected final Class baseType; protected final Class valueType; @@ -28,10 +28,6 @@ public abstract class ValueAdapter

{ return valueType; } - public abstract B serialize(@NotNull P provider, @NotNull V value) throws Exception; - - public abstract V deserialize(@NotNull P provider, @NotNull Class clazz, @NotNull B data) throws Exception; - public boolean isAdaptedFrom(Class clazz) { return clazz.isAssignableFrom(valueType); } @@ -41,7 +37,7 @@ public abstract class ValueAdapter

{ } public boolean isAdapterOf(Class clazz) { - return valueType.isAssignableFrom(clazz); + return clazz == valueType; } @SuppressWarnings("unchecked") 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 607aa0b..460e4ca 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 @@ -3,20 +3,17 @@ package cc.carm.lib.configuration.adapter; import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; public class ValueAdapterRegistry

{ - protected final @NotNull P provider; protected final Map, ValueAdapter> adapters = new HashMap<>(); - public ValueAdapterRegistry(@NotNull P provider) { - this.provider = provider; - } - public void register(@NotNull ValueAdapter adapter) { adapters.put(adapter.getValueClass(), adapter); } @@ -46,30 +43,31 @@ public class ValueAdapterRegistry

{ } @SuppressWarnings("unchecked") - public T deserialize(Class type, Object value) throws Exception { - if (value == null) return null; - if (type == Object.class) return type.cast(value); + @Contract("_,_,null -> null") + public T deserialize(@NotNull P provider, @NotNull Class type, @Nullable Object source) throws Exception { + if (source == null) return null; // Null check + if (type.isInstance(source)) return type.cast(source); // Not required to deserialize ValueAdapter adapter = getAdapter(type); if (adapter == null) throw new RuntimeException("No adapter for type " + type.getName()); - // CHECK IF VALUE IS ADAPTED FROM GIVEN VALUE'S TYPE - if (adapter.isAdaptedFrom(value)) { - return (T) adapter.deserializeObject(provider, type, value); + // Check if value is adapted from given value's type + if (adapter.isAdaptedFrom(source)) { + return (T) adapter.deserializeObject(provider, type, source); } - // OTHERWISE, WE NEED TO DESERIALIZE ONE BY ONE - Object baseValue = deserialize(adapter.getBaseClass(), value); + // Otherwise, we need to deserialize one by one. + Object baseValue = deserialize(provider, adapter.getBaseClass(), source); if (baseValue == null) return null; // Null check return (T) adapter.deserializeObject(provider, type, baseValue); } - public Object serialize(T value) throws Exception { - if (value == null) return null; + @Contract("_,null -> null") + public Object serialize(@NotNull P provider, @Nullable T value) throws Exception { + if (value == null) return null; // Null check - Class valueClass = value.getClass(); - ValueAdapter adapter = adapters.get(valueClass); + ValueAdapter adapter = getAdapter(value.getClass()); if (adapter == null) return value; // No adapters, try to return the original value if (adapter instanceof PrimitiveAdapters) { @@ -79,12 +77,14 @@ public class ValueAdapterRegistry

{ } // Otherwise, we need to serialize one by one. - return serialize(adapter.serializeObject(provider, value)); + return serialize(provider, adapter.serializeObject(provider, value)); } public ValueAdapter getAdapter(Class clazz) { - ValueAdapter byClass = adapters.get(clazz); - if (byClass != null) return byClass; + return adapters.getOrDefault(clazz, findAdapter(clazz)); + } + + public ValueAdapter findAdapter(Class clazz) { return adapters.values().stream().filter(adapter -> adapter.isAdapterOf(clazz)).findFirst().orElse(null); } diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java new file mode 100644 index 0000000..381d315 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java @@ -0,0 +1,18 @@ +package cc.carm.lib.configuration.adapter; + +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; + +/** + * Value deserializer, convert base data to target value. + * + * @param

Configuration provider + * @param The type of base data + * @param The type of target value + */ +@FunctionalInterface +public interface ValueDeserializer

{ + + V deserialize(@NotNull P provider, @NotNull Class clazz, @NotNull B data) throws Exception; + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java new file mode 100644 index 0000000..3161bf2 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java @@ -0,0 +1,18 @@ +package cc.carm.lib.configuration.adapter; + +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; + +/** + * Value serializer, convert target value to base data. + * + * @param

Configuration provider + * @param The type of base data + * @param The type of value + */ +@FunctionalInterface +public interface ValueSerializer

{ + + B serialize(@NotNull P provider, @NotNull V value) throws Exception; + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java index 40bd3c4..6f53595 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java @@ -21,4 +21,9 @@ public class EnumAdapter

extends ValueAdapter

clazz) { + return clazz.isEnum(); + } + } diff --git a/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java index 01061e3..252e6a4 100644 --- a/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java +++ b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java @@ -1,7 +1,5 @@ package cc.carm.lib.configuration.annotation; -import cc.carm.lib.configuration.core.ConfigInitializer; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -16,7 +14,7 @@ public @interface ConfigPath { /** * The path value of the current configuration. - * If not set,will generate the path by {@link ConfigInitializer#getPathFromName(String)}. + * If not set,will generate the path by {@link cc.carm.lib.configuration.source.path.PathGenerator}. * * @return The path value of the current configuration */ diff --git a/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java b/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java deleted file mode 100644 index 286b35e..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java +++ /dev/null @@ -1,275 +0,0 @@ -package cc.carm.lib.configuration.core; - -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.core.source.ConfigurationProvider; -import cc.carm.lib.configuration.value.ConfigValue; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.List; - -/** - * 配置文件类初始化方法 - * 用于初始化 {@link Configuration} 中的每个 {@link ConfigValue} 对象 - * - * @param {@link ConfigurationProvider} 配置文件的数据来源 - * @author CarmJos - */ -public class ConfigInitializer> { - - protected final @NotNull T provider; - - public ConfigInitializer(@NotNull T provider) { - this.provider = provider; - } - - /** - * 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。 - * - * @param clazz 配置文件类,须继承于 {@link Configuration} 。 - * @param saveDefaults 是否写入默认值(默认为 true)。 - */ - public void initialize(@NotNull Class clazz, boolean saveDefaults) { - initialize(clazz, saveDefaults, true); - } - - /** - * 初始化指定类的所有 {@link ConfigValue} 对象。 - * - * @param clazz 配置文件类,须继承于 {@link Configuration} 。 - * @param saveDefaults 是否写入默认值(默认为 true)。 - * @param loadSubClasses 是否加载内部子类(默认为 true)。 - */ - public void initialize(@NotNull Class clazz, - boolean saveDefaults, boolean loadSubClasses) { - initializeStaticClass( - clazz, null, null, - null, null, null, - saveDefaults, loadSubClasses - ); - if (saveDefaults) { - try { - provider.save(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - /** - * 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。 - * - * @param config 配置文件实例类,须实现 {@link Configuration} 。 - */ - public void initialize(@NotNull Configuration config) { - initialize(config, true); - } - - /** - * 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。 - * - * @param config 配置文件实例类,须实现 {@link Configuration} 。 - * @param saveDefaults 是否写入默认值(默认为 true)。 - */ - public void initialize(@NotNull Configuration config, boolean saveDefaults) { - initializeInstance( - config, null, null, - null, null, null, - saveDefaults - ); - if (saveDefaults) { - try { - provider.save(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - - // 针对实例类的初始化方法 - private void initializeInstance(@NotNull Configuration root, - @Nullable String parentPath, @Nullable String fieldName, - @Nullable ConfigPath fieldPath, - @Nullable HeaderComment fieldHeaderComments, - @Nullable InlineComment fieldInlineComments, - boolean saveDefaults) { - String path = getClassPath(root.getClass(), parentPath, fieldName, fieldPath); - this.provider.setHeaderComment(path, getClassHeaderComments(root.getClass(), fieldHeaderComments)); - if (path != null) this.provider.setInlineComment(path, readInlineComments(fieldInlineComments)); - - for (Field field : root.getClass().getDeclaredFields()) { - initializeField(root, field, path, saveDefaults, false); - } - } - - // 针对静态类的初始化方法 - private void initializeStaticClass(@NotNull Class clazz, - @Nullable String parentPath, @Nullable String fieldName, - @Nullable ConfigPath fieldPath, - @Nullable HeaderComment fieldHeaderComments, - @Nullable InlineComment fieldInlineComments, - boolean saveDefaults, boolean loadSubClasses) { - if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类 - String path = getClassPath(clazz, parentPath, fieldName, fieldPath); - this.provider.setHeaderComment(path, getClassHeaderComments(clazz, fieldHeaderComments)); - if (path != null) this.provider.setInlineComment(path, readInlineComments(fieldInlineComments)); - - for (Field field : clazz.getDeclaredFields()) { - initializeField(clazz, field, path, saveDefaults, loadSubClasses); - } - - if (!loadSubClasses) return; - Class[] classes = clazz.getDeclaredClasses(); - for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。 - initializeStaticClass( - classes[i], path, classes[i].getSimpleName(), - null, null, null, - saveDefaults, true - ); - } - } - - private void initializeField(@NotNull Object source, @NotNull Field field, - @Nullable String parent, boolean saveDefaults, boolean loadSubClasses) { - try { - field.setAccessible(true); - Object object = field.get(source); - - if (object instanceof ConfigValue) { - initializeValue( - (ConfigValue) object, getFieldPath(field, parent), - field.getAnnotation(HeaderComment.class), - field.getAnnotation(InlineComment.class), - saveDefaults - ); - } else if (source instanceof Configuration && object instanceof Configuration) { - // 当且仅当 源字段与字段 均为ConfigurationRoot实例时,才对目标字段进行下一步初始化加载。 - initializeInstance( - (Configuration) object, parent, field.getName(), - field.getAnnotation(ConfigPath.class), - field.getAnnotation(HeaderComment.class), - field.getAnnotation(InlineComment.class), - saveDefaults - ); - } else if (source instanceof Class && object instanceof Class) { - // 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。 - initializeStaticClass( - (Class) object, parent, field.getName(), - field.getAnnotation(ConfigPath.class), - field.getAnnotation(HeaderComment.class), - field.getAnnotation(InlineComment.class), - saveDefaults, loadSubClasses - ); - } - - // 以上判断实现以下规范: - // - 实例类中仅加载 ConfigValue实例 与 ConfigurationRoot实例 - // - 静态类中仅加载 静态ConfigValue实例 与 静态ConfigurationRoot类 - - } catch (IllegalAccessException ignored) { - } - } - - protected void initializeValue(@NotNull ConfigValue value, @NotNull String path, - @Nullable HeaderComment fieldHeaderComment, - @Nullable InlineComment fieldInlineComment, - boolean saveDefaults) { - value.initialize( - provider, saveDefaults, path, - readHeaderComments(fieldHeaderComment), - readInlineComments(fieldInlineComment) - ); - } - - protected static @Nullable List getClassHeaderComments(@NotNull Class clazz, - @Nullable HeaderComment fieldAnnotation) { - List classComments = readHeaderComments(clazz.getAnnotation(HeaderComment.class)); - if (classComments != null) return classComments; - else return readHeaderComments(fieldAnnotation); - } - - - protected static List readHeaderComments(@Nullable HeaderComment annotation) { - if (annotation == null) return null; - String[] value = annotation.value(); - return value.length > 0 ? Arrays.asList(value) : null; - } - - - protected static @Nullable String readInlineComments(@Nullable InlineComment annotation) { - if (annotation == null) return null; - String value = annotation.value(); - return value.length() > 0 ? value : null; - } - - protected static @Nullable String getClassPath(@Nullable Class clazz, - @Nullable String parentPath, - @Nullable String filedName, - @Nullable ConfigPath fieldAnnotation) { - @NotNull String parent = parentPath != null ? parentPath + "." : ""; - boolean fromRoot = false; - - // 先获取 Class 对应的路径注解 其优先度最高。 - if (clazz != null) { - ConfigPath clazzAnnotation = clazz.getAnnotation(ConfigPath.class); - if (clazzAnnotation != null) { - fromRoot = clazzAnnotation.root(); - if (clazzAnnotation.value().length() > 0) { - return (fromRoot ? "" : parent) + clazzAnnotation.value(); - } - } - } - - if (fieldAnnotation != null) { - fromRoot = fromRoot || fieldAnnotation.root(); - if (fieldAnnotation.value().length() > 0) { - return (fromRoot ? "" : parent) + fieldAnnotation.value(); - } - } - - // 再由 fieldName 获取路径 - if (filedName != null) return (fromRoot ? "" : parent) + getPathFromName(filedName); - else return null; // 不满足上述条件 且 无 fieldName,则说明是根路径。 - } - - protected static @NotNull String getFieldPath(@NotNull Field field, @Nullable String parentPath) { - @NotNull String parent = parentPath != null ? parentPath + "." : ""; - boolean fromRoot = false; - - // 先获取 Field 对应的路径注解 其优先度最高。 - ConfigPath pathAnnotation = field.getAnnotation(ConfigPath.class); - if (pathAnnotation != null) { - fromRoot = pathAnnotation.root(); - if (pathAnnotation.value().length() > 0) { - return (fromRoot ? "" : parent) + pathAnnotation.value(); - } - } - - // 最后再通过 fieldName 自动生成路径 - return (fromRoot ? "" : parent) + getPathFromName(field.getName()); - } - - /** - * 得到指定元素的配置名称。 - * 采用 全小写,以“-”链接 的命名规则。 - * - * @param name 源名称 - * @return 全小写,以“-”链接 的 路径名称 - */ - public static String getPathFromName(String name) { - return name.replaceAll("[A-Z]", "-$0") // 将驼峰转换为蛇形; - .replaceAll("-(.*)", "$1") // 若首字母也为大写,则也会被转换,需要去掉第一个横线 - .replaceAll("_-([A-Z])", "_$1") // 因为命名中可能包含 _,因此需要被特殊处理一下 - .replaceAll("([a-z])-([A-Z])", "$1_$2") // 然后将非全大写命名的内容进行转换 - .replace("-", "") // 移除掉多余的横线 - .replace("_", "-") // 将下划线替换为横线 - .toLowerCase(); // 最后转为全小写 - } - - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/Configuration.java b/core/src/main/java/cc/carm/lib/configuration/core/Configuration.java index 1ba41b9..f925a20 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/Configuration.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/Configuration.java @@ -5,4 +5,5 @@ package cc.carm.lib.configuration.core; * which is used to label and record the configuration information. */ public interface Configuration { + } diff --git a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java b/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java index 0252983..09de47b 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java @@ -1,7 +1,7 @@ package cc.carm.lib.configuration.core.source; -import cc.carm.lib.configuration.core.ConfigInitializer; import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.configuration.source.comment.ConfigurationComments; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/cc/carm/lib/configuration/manifest/ValueManifest.java b/core/src/main/java/cc/carm/lib/configuration/manifest/ValueManifest.java new file mode 100644 index 0000000..8ef68e2 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/manifest/ValueManifest.java @@ -0,0 +1,8 @@ +package cc.carm.lib.configuration.manifest; + +public class ValueManifest { + + + + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java index 597bbcc..188dae2 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java @@ -1,15 +1,85 @@ package cc.carm.lib.configuration.source; +import cc.carm.lib.configuration.adapter.ValueAdapter; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; +import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.source.path.PathGenerator; +import cc.carm.lib.easyoptions.OptionHolder; +import cc.carm.lib.easyoptions.OptionType; import org.jetbrains.annotations.NotNull; -public abstract class ConfigurationBuilder

{ +import java.util.function.Consumer; +import java.util.function.Function; - protected ConfigurationLoader loader; - protected ValueAdapterRegistry

processors; +public abstract class ConfigurationBuilder

, C> { + protected Function> loaderFunction = ConfigurationLoader::new; + protected Consumer> loaderConsumer = loader -> { + }; - public abstract @NotNull ConfigurationProvider build(); + protected ValueAdapterRegistry

adapters = new ValueAdapterRegistry<>(); + protected OptionHolder options = new OptionHolder(); + + public abstract C getThis(); + + public C loader(Function> loaderFunction) { + this.loaderFunction = loaderFunction; + return getThis(); + } + + public C loader(ConfigurationLoader

loader) { + return loader(p -> loader); + } + + public C loader(Consumer> loaderConsumer) { + this.loaderConsumer = this.loaderConsumer.andThen(loaderConsumer); + return getThis(); + } + + public C pathGenerator(PathGenerator

pathGenerator) { + return loader(loader -> { + loader.setPathGenerator(pathGenerator); + }); + } + + public C adapters(ValueAdapterRegistry

adapters) { + this.adapters = adapters; + return getThis(); + } + + public C adapter(Consumer> adapterRegistryConsumer) { + adapterRegistryConsumer.accept(adapters); + return getThis(); + } + + public C adapter(@NotNull ValueAdapter adapter) { + return adapter(a -> a.register(adapter)); + } + + public C adapter(Class clazz, @NotNull ValueAdapter adapter) { + return adapter(a -> a.register(clazz, adapter)); + } + + public C adapter(Class baseClass, Class valueClass, + ConfigDataFunction parser, ConfigDataFunction serializer) { + return adapter(a -> a.register(baseClass, valueClass, parser, serializer)); + } + + public C options(OptionHolder options) { + this.options = options; + return getThis(); + } + + public C option(Consumer optionsConsumer) { + optionsConsumer.accept(options); + return getThis(); + } + + public C option(OptionType option, O value) { + return option(o -> o.set(option, value)); + } + + public abstract @NotNull P build(); } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java index 79f0a5e..a56eae9 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java @@ -1,4 +1,196 @@ package cc.carm.lib.configuration.source; -public interface ConfigurationLoader { +import cc.carm.lib.configuration.annotation.ConfigPath; +import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.configuration.source.path.PathGenerator; +import cc.carm.lib.configuration.source.path.StandardPathGenerator; +import cc.carm.lib.configuration.value.ConfigValue; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; + +/** + * Configuration loader, + * used to load configuration values from {@link cc.carm.lib.configuration.core.Configuration} classes. + */ +public class ConfigurationLoader

> { + + protected final P provider; + protected PathGenerator

pathGenerator; + + public ConfigurationLoader(P provider) { + this(provider, StandardPathGenerator.of(provider)); + } + + public ConfigurationLoader(P provider, PathGenerator

pathGenerator) { + this.provider = provider; + this.pathGenerator = pathGenerator; + } + + public void setPathGenerator(PathGenerator

pathGenerator) { + this.pathGenerator = pathGenerator; + } + + public PathGenerator

getPathGenerator() { + return pathGenerator; + } + + /** + * 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。 + * + * @param clazz 配置文件类,须继承于 {@link Configuration} 。 + */ + public void initialize(@NotNull P provider, @NotNull Class clazz) { + initialize(clazz, saveDefaults, true); + } + + /** + * 初始化指定类的所有 {@link ConfigValue} 对象。 + * + * @param clazz 配置文件类,须继承于 {@link Configuration} 。 + * @param saveDefaults 是否写入默认值(默认为 true)。 + * @param loadSubClasses 是否加载内部子类(默认为 true)。 + */ + public void initialize(@NotNull Class clazz) { + initializeStaticClass( + clazz, null, null, + null, null, null, + saveDefaults, loadSubClasses + ); + if (saveDefaults) { + try { + provider.save(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。 + * + * @param config 配置文件实例类,须实现 {@link Configuration} 。 + */ + public void initialize(@NotNull Configuration config) { + initialize(config, true); + } + + /** + * 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。 + * + * @param config 配置文件实例类,须实现 {@link Configuration} 。 + * @param saveDefaults 是否写入默认值(默认为 true)。 + */ + public void initialize(@NotNull Configuration config, boolean saveDefaults) { + initializeInstance( + config, null, null, + null, null, null, + saveDefaults + ); + if (saveDefaults) { + try { + provider.save(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + + // 针对实例类的初始化方法 + private void initializeInstance(@NotNull Configuration root, + @Nullable String parentPath, @Nullable String fieldName, + @Nullable ConfigPath fieldPath, + @Nullable HeaderComment fieldHeaderComments, + @Nullable InlineComment fieldInlineComments, + boolean saveDefaults) { + String path = getClassPath(root.getClass(), parentPath, fieldName, fieldPath); + this.provider.setHeaderComment(path, getClassHeaderComments(root.getClass(), fieldHeaderComments)); + if (path != null) this.provider.setInlineComment(path, readInlineComments(fieldInlineComments)); + + for (Field field : root.getClass().getDeclaredFields()) { + initializeField(root, field, path, saveDefaults, false); + } + } + + // 针对静态类的初始化方法 + private void initializeStaticClass(@NotNull Class clazz, + @Nullable String parentPath, @Nullable String fieldName, + @Nullable ConfigPath fieldPath, + @Nullable HeaderComment fieldHeaderComments, + @Nullable InlineComment fieldInlineComments, + boolean saveDefaults, boolean loadSubClasses) { + if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类 + String path = getClassPath(clazz, parentPath, fieldName, fieldPath); + this.provider.setHeaderComment(path, getClassHeaderComments(clazz, fieldHeaderComments)); + if (path != null) this.provider.setInlineComment(path, readInlineComments(fieldInlineComments)); + + for (Field field : clazz.getDeclaredFields()) { + initializeField(clazz, field, path, saveDefaults, loadSubClasses); + } + + if (!loadSubClasses) return; + Class[] classes = clazz.getDeclaredClasses(); + for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。 + initializeStaticClass( + classes[i], path, classes[i].getSimpleName(), + null, null, null, + saveDefaults, true + ); + } + } + + private void initializeField(@NotNull Object source, @NotNull Field field, + @Nullable String parent, boolean saveDefaults, boolean loadSubClasses) { + try { + field.setAccessible(true); + Object object = field.get(source); + + if (object instanceof ConfigValue) { + initializeValue( + (ConfigValue) object, getFieldPath(field, parent), + field.getAnnotation(HeaderComment.class), + field.getAnnotation(InlineComment.class), + saveDefaults + ); + } else if (source instanceof Configuration && object instanceof Configuration) { + // 当且仅当 源字段与字段 均为ConfigurationRoot实例时,才对目标字段进行下一步初始化加载。 + initializeInstance( + (Configuration) object, parent, field.getName(), + field.getAnnotation(ConfigPath.class), + field.getAnnotation(HeaderComment.class), + field.getAnnotation(InlineComment.class), + saveDefaults + ); + } else if (source instanceof Class && object instanceof Class) { + // 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。 + initializeStaticClass( + (Class) object, parent, field.getName(), + field.getAnnotation(ConfigPath.class), + field.getAnnotation(HeaderComment.class), + field.getAnnotation(InlineComment.class), + saveDefaults, loadSubClasses + ); + } + + // 以上判断实现以下规范: + // - 实例类中仅加载 ConfigValue实例 与 ConfigurationRoot实例 + // - 静态类中仅加载 静态ConfigValue实例 与 静态ConfigurationRoot类 + + } catch (IllegalAccessException ignored) { + } + } + + protected void initializeValue(@NotNull ConfigValue value, @NotNull String path, + @Nullable HeaderComment fieldHeaderComment, + @Nullable InlineComment fieldInlineComment, + boolean saveDefaults) { + value.initialize( + provider, saveDefaults, path, + readHeaderComments(fieldHeaderComment), + readInlineComments(fieldInlineComment) + ); + } + } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java index 89354f3..fb662ed 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java @@ -1,6 +1,37 @@ package cc.carm.lib.configuration.source; -public class ConfigurationProvider { +import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; +import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.easyoptions.OptionHolder; +import cc.carm.lib.easyoptions.OptionType; +import org.jetbrains.annotations.NotNull; + +public abstract class ConfigurationProvider

> { + + protected @NotNull ConfigurationLoader

loader = new ConfigurationLoader<>(); + protected @NotNull ValueAdapterRegistry

adapters = new ValueAdapterRegistry<>(); + protected @NotNull OptionHolder options = new OptionHolder(); + + + public OptionHolder options() { + return options; + } + + public @NotNull T option(@NotNull OptionType option) { + return options.get(option); + } + + public void option(@NotNull OptionType option, @NotNull T value) { + options.set(option, value); + } + + public ConfigurationLoader

loader() { + return loader; + } + + public void load(Configuration configuration) { + loader().load(configuration); + } } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/path/PathGenerator.java b/core/src/main/java/cc/carm/lib/configuration/source/path/PathGenerator.java new file mode 100644 index 0000000..19d0a6d --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/path/PathGenerator.java @@ -0,0 +1,33 @@ +package cc.carm.lib.configuration.source.path; + +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; + +public interface PathGenerator

> { + + @Nullable String getFieldPath(@Nullable String parentPath, @NotNull Field field); + + @Nullable String getClassPath(@Nullable String parentPath, + @NotNull Class clazz, @Nullable Field clazzField); + + /** + * Get the configuration name of the specified element. + * Use the naming convention of all lowercase and "-" links. + * + * @param name source name + * @return the final path + */ + static String covertPathName(String name) { + return name.replaceAll("[A-Z]", "-$0") // 将驼峰形转换为蛇形; + .replaceAll("-(.*)", "$1") // 若首字母也为大写,则也会被转换,需要去掉第一个横线 + .replaceAll("_-([A-Z])", "_$1") // 因为命名中可能包含 _,因此需要被特殊处理一下 + .replaceAll("([a-z])-([A-Z])", "$1_$2") // 然后将非全大写命名的内容进行转换 + .replace("-", "") // 移除掉多余的横线 + .replace("_", "-") // 将下划线替换为横线 + .toLowerCase(); // 最后转为全小写 + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/path/StandardPathGenerator.java b/core/src/main/java/cc/carm/lib/configuration/source/path/StandardPathGenerator.java new file mode 100644 index 0000000..824db53 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/path/StandardPathGenerator.java @@ -0,0 +1,74 @@ +package cc.carm.lib.configuration.source.path; + +import cc.carm.lib.configuration.annotation.ConfigPath; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.standard.ConfigurationOptions; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.function.UnaryOperator; + +public class StandardPathGenerator

> implements PathGenerator

{ + + public static > StandardPathGenerator of(T provider) { + return of(provider, PathGenerator::covertPathName); + } + + public static > StandardPathGenerator of(T provider, UnaryOperator pathConverter) { + return new StandardPathGenerator<>(provider, pathConverter); + } + + protected final P provider; + protected UnaryOperator pathConverter; + + public StandardPathGenerator(P provider, UnaryOperator pathConverter) { + this.provider = provider; + this.pathConverter = pathConverter; + } + + public @NotNull UnaryOperator getPathConverter() { + return pathConverter; + } + + public void setPathConverter(UnaryOperator pathConverter) { + this.pathConverter = pathConverter; + } + + public String covertPath(String name) { + return pathConverter.apply(name); + } + + public char pathSeparator() { + return provider.option(ConfigurationOptions.PATH_SEPARATOR); + } + + protected String link(@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() + covertPath(path); + } + + @Override + public @Nullable String getFieldPath(@Nullable String parentPath, @NotNull Field field) { + ConfigPath path = field.getAnnotation(ConfigPath.class); + if (path == null) return link(parentPath, false, field.getName()); // No annotation, use field name. + else return link(parentPath, path.root(), path.value().isEmpty() ? field.getName() : path.value()); + } + + @Override + public @Nullable String getClassPath(@Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField) { + // For standard path generator, we generate path following by: + // 1. Check if the class has a ConfigPath annotation, if so, use the root and value as the path. + // 2. If the class defined as a field, check if the field has a ConfigPath annotation, + // and use filed information. + ConfigPath clazzPath = clazz.getAnnotation(ConfigPath.class); + + if (clazzPath != null) return link(parentPath, clazzPath.root(), clazzPath.value()); + if (clazzField == null) return parentPath; // No field, return same as parent. + + ConfigPath fieldPath = clazzField.getAnnotation(ConfigPath.class); + if (fieldPath == null) return link(parentPath, false, clazzField.getName()); + else return getFieldPath(parentPath, clazzField); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationMetaTypes.java b/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationMetaTypes.java new file mode 100644 index 0000000..90e4499 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationMetaTypes.java @@ -0,0 +1,12 @@ +package cc.carm.lib.configuration.source.standard; + +import cc.carm.lib.configuration.annotation.ConfigPath; +import cc.carm.lib.easyannotation.AnnotatedMetaType; + +public interface ConfigurationMetaTypes { + + AnnotatedMetaType PATH = AnnotatedMetaType.of(ConfigPath.class, ConfigPath::value); + + AnnotatedMetaType ROOT = AnnotatedMetaType.of(ConfigPath.class, ConfigPath::root); + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationOptions.java b/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationOptions.java new file mode 100644 index 0000000..88485b8 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationOptions.java @@ -0,0 +1,30 @@ +package cc.carm.lib.configuration.source.standard; + + +import cc.carm.lib.easyoptions.OptionType; + +import static cc.carm.lib.easyoptions.OptionType.of; + +public interface ConfigurationOptions { + + /** + * The configuration path separator. + */ + OptionType PATH_SEPARATOR = of('.'); + + /** + * Whether to copy files from resource if exists. + */ + OptionType COPY_DEFAULTS = of(true); + + /** + * Whether to save default values if offered and not exists in configuration. + */ + OptionType SAVE_DEFAULTS = of(true); + + /** + * Whether to load subclasses of configuration class. + */ + OptionType LOAD_SUB_CLASSES = of(true); + +} 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 9dd4888..e9caa02 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 @@ -1,6 +1,5 @@ package cc.carm.lib.configuration.value; -import cc.carm.lib.configuration.core.ConfigInitializer; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import org.jetbrains.annotations.NotNull; diff --git a/core/src/test/java/AdaptTest.java b/core/src/test/java/AdaptTest.java index 35be94b..b0e8d0d 100644 --- a/core/src/test/java/AdaptTest.java +++ b/core/src/test/java/AdaptTest.java @@ -12,7 +12,7 @@ public class AdaptTest { @Test public void test() throws Exception { - ValueAdapterRegistry registry = new ValueAdapterRegistry<>(new ConfigurationProvider()); + ValueAdapterRegistry registry = new ValueAdapterRegistry<>(); registry.register(Long.class, PrimitiveAdapters.ofLong()); registry.register(long.class, PrimitiveAdapters.ofLong()); registry.register(Integer.class, PrimitiveAdapters.ofInteger()); @@ -36,16 +36,19 @@ public class AdaptTest { registry.register( Duration.class, LocalTime.class, duration -> LocalTime.now().plus(duration), - data -> Duration.between(data, LocalTime.now()) + data -> Duration.between(LocalTime.now(), data) ); - LocalTime v = registry.deserialize(LocalTime.class, "600"); - Object d = registry.serialize(v); + ConfigurationProvider provider = new ConfigurationProvider(); + LocalTime v = registry.deserialize(provider, LocalTime.class, "600"); + Object d = registry.serialize(provider, v); System.out.println(v); System.out.println(d); - System.out.println(registry.deserialize(TestEnum.class, "b")); + System.out.println(registry.deserialize(provider, TestEnum.class, "b")); + System.out.println(registry.serialize(provider, TestEnum.C).getClass()); + } enum TestEnum { diff --git a/core/src/test/java/NameTest.java b/core/src/test/java/NameTest.java index e3eaab8..7a45698 100644 --- a/core/src/test/java/NameTest.java +++ b/core/src/test/java/NameTest.java @@ -1,4 +1,3 @@ -import cc.carm.lib.configuration.core.ConfigInitializer; import org.junit.Test; public class NameTest { 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 feef0a4..6b3875e 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,6 +1,5 @@ package cc.carm.lib.configuration.demo.tests.conf; -import cc.carm.lib.configuration.core.ConfigInitializer; import cc.carm.lib.configuration.core.Configuration; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.annotation.HeaderComment; diff --git a/impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONFileConfigProvider.java b/impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONFileConfigProvider.java index 9c44994..2f12e30 100644 --- a/impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONFileConfigProvider.java +++ b/impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONFileConfigProvider.java @@ -1,7 +1,6 @@ package cc.carm.lib.configuration.hocon; -import cc.carm.lib.configuration.core.ConfigInitializer; -import cc.carm.lib.configuration.core.source.ConfigurationComments; +import cc.carm.lib.configuration.source.comment.ConfigurationComments; import cc.carm.lib.configuration.core.source.impl.FileConfigProvider; import cc.carm.lib.configuration.hocon.exception.HOCONGetValueException; import cc.carm.lib.configuration.hocon.util.HOCONUtils; diff --git a/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java b/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java index f9df64e..bbf7c80 100644 --- a/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java +++ b/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java @@ -1,7 +1,6 @@ package cc.carm.lib.configuration.json; -import cc.carm.lib.configuration.core.ConfigInitializer; -import cc.carm.lib.configuration.core.source.ConfigurationComments; +import cc.carm.lib.configuration.source.comment.ConfigurationComments; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.source.impl.FileConfigProvider; import com.google.gson.Gson; diff --git a/impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java b/impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java index 453f54a..e896060 100644 --- a/impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java +++ b/impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java @@ -1,7 +1,6 @@ package cc.carm.lib.configuration.sql; -import cc.carm.lib.configuration.core.ConfigInitializer; -import cc.carm.lib.configuration.core.source.ConfigurationComments; +import cc.carm.lib.configuration.source.comment.ConfigurationComments; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.easysql.api.SQLManager; import cc.carm.lib.easysql.api.SQLQuery; diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java index d69b3aa..9815444 100644 --- a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java +++ b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java @@ -1,7 +1,6 @@ package cc.carm.lib.configuration.yaml; -import cc.carm.lib.configuration.core.ConfigInitializer; -import cc.carm.lib.configuration.core.source.ConfigurationComments; +import cc.carm.lib.configuration.source.comment.ConfigurationComments; import cc.carm.lib.configuration.core.source.impl.FileConfigProvider; import cc.carm.lib.yamlcommentupdater.CommentedYAML; import cc.carm.lib.yamlcommentupdater.CommentedYAMLWriter; @@ -26,6 +25,7 @@ public class YAMLConfigProvider extends FileConfigProvider i } public void initializeConfig() { + ConfigurationOptions this.configuration = YamlConfiguration.loadConfiguration(file); this.initializer = new ConfigInitializer<>(this); } diff --git a/pom.xml b/pom.xml index d3de07a..55f7c72 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,7 @@ impl/json impl/sql impl/hocon + commentable EasyConfiguration From da3d4d1fd23469609860b9687066e0605855a9da Mon Sep 17 00:00:00 2001 From: carm Date: Tue, 30 Jan 2024 18:01:36 +0800 Subject: [PATCH 06/17] feat(loader): Refactor loaders and metadata. --- .../commentable/CommentableMetaTypes.java | 26 - core/pom.xml | 7 +- .../{core => }/Configuration.java | 2 +- .../configuration/adapter/ValueAdapter.java | 10 +- .../adapter/ValueAdapterRegistry.java | 30 +- .../adapter/ValueDeserializer.java | 5 +- .../adapter/ValueSerializer.java | 5 +- .../adapter/strandard/EnumAdapter.java | 8 +- .../adapter/strandard/PrimitiveAdapters.java | 38 +- .../configuration/annotation/ConfigPath.java | 4 +- .../core/function/ConfigValueParser.java | 159 ------ .../core/source/ConfigurationProvider.java | 150 ------ .../core/source/ConfigurationWrapper.java | 73 --- .../core/source/impl/FileConfigProvider.java | 89 ---- .../function/ConfigDataFunction.java | 2 +- .../function/ConfigValueParser.java | 62 +++ .../loader/ConfigurationLoader.java | 107 ++++ .../configuration/loader/PathGenerator.java | 43 ++ .../loader/StandardPathGenerator.java | 86 ++++ .../configuration/manifest/ValueManifest.java | 8 - .../ConfigurationOptions.java | 11 +- ...Builder.java => ConfigurationFactory.java} | 30 +- .../source/ConfigurationLoader.java | 196 -------- .../source/ConfigurationProvider.java | 53 +- .../ConfigurationSection.java} | 124 +++-- .../source/ConfigurationSource.java | 41 ++ .../source/path/PathGenerator.java | 33 -- .../source/path/StandardPathGenerator.java | 74 --- .../standard/ConfigurationMetaTypes.java | 12 - .../lib/configuration/value/ConfigValue.java | 47 +- .../configuration/value/ValueManifest.java | 202 ++++---- .../value/impl/CachedConfigValue.java | 9 +- .../value/impl/ConfigValueMap.java | 427 ++++++++-------- .../value/meta/ValueMetaList.java | 11 + .../value/meta/ValueMetaType.java | 59 +++ .../value/standard/ConfiguredList.java | 458 +++++++++--------- .../value/standard/ConfiguredMap.java | 55 ++- .../value/standard/ConfiguredSection.java | 193 ++++---- .../value/standard/ConfiguredSectionMap.java | 63 ++- .../value/standard/ConfiguredValue.java | 45 +- core/src/main/old/ValueManifestv.java | 123 +++++ .../builder/AbstractConfigBuilder.java | 3 +- .../builder/CommonConfigBuilder.java | 4 +- .../core => old}/builder/ConfigBuilder.java | 10 +- .../builder/list/ConfigListBuilder.java | 4 +- .../builder/list/SourceListBuilder.java | 6 +- .../builder/map/ConfigMapBuilder.java | 4 +- .../builder/map/ConfigMapCreator.java | 2 +- .../builder/map/SectionMapBuilder.java | 7 +- .../builder/map/SourceMapBuilder.java | 6 +- .../builder/value/ConfigValueBuilder.java | 7 +- .../builder/value/SectionValueBuilder.java | 9 +- .../builder/value/SourceValueBuilder.java | 8 +- core/src/test/java/AdaptTest.java | 9 +- core/src/test/java/NameTest.java | 9 +- .../java/cc/carm/test/config/LoaderTest.java | 42 ++ .../java/cc/carm/test/config/TestSource.java | 82 ++++ .../demo/DatabaseConfiguration.java | 2 +- .../demo/tests/ConfigurationTest.java | 1 - .../demo/tests/conf/DemoConfiguration.java | 2 +- .../demo/tests/conf/TestConfiguration.java | 2 +- .../tests/conf/TestInnerConfiguration.java | 2 +- .../demo/tests/model/TestModel.java | 1 - features/commentable/pom.xml | 51 ++ .../annotation/HeaderComment.java | 0 .../annotation/InlineComment.java | 0 .../commentable/CommentableMetaTypes.java | 22 + .../commentable/ConfigurationComments.java | 0 .../option}/CommentableOptions.java | 4 +- {commentable => features/file}/pom.xml | 25 +- .../option/FileConfigOptions.java | 15 + .../source/FileConfigProvider.java | 87 ++++ .../source/FileConfigSource.java | 6 + pom.xml | 14 +- {impl/json => providers/gson}/README.md | 0 {impl/json => providers/gson}/pom.xml | 2 +- .../lib/configuration/EasyConfiguration.java | 0 .../json/JSONConfigProvider.java | 1 - .../configuration/json/JSONConfigWrapper.java | 1 - .../src/test/java/config/JSONConfigTest.java | 0 {impl => providers}/hocon/README.md | 0 {impl => providers}/hocon/pom.xml | 0 .../lib/configuration/EasyConfiguration.java | 0 .../hocon/HOCONConfigWrapper.java | 1 - .../hocon/HOCONFileConfigProvider.java | 0 .../exception/HOCONGetValueException.java | 0 .../configuration/hocon/util/HOCONUtils.java | 0 .../test/easyconfiguration/HOCONTest.java | 0 {impl => providers}/sql/README.md | 0 {impl => providers}/sql/pom.xml | 0 .../lib/configuration/EasyConfiguration.java | 0 .../configuration/sql/SQLConfigProvider.java | 1 - .../configuration/sql/SQLConfigWrapper.java | 1 - .../configuration/sql/SQLValueResolver.java | 0 .../lib/configuration/sql/SQLValueTypes.java | 0 .../src/test/java/config/SQLConfigTest.java | 0 .../sql/src/test/resources/log4j2.xml | 0 {impl => providers}/yaml/README.md | 0 {impl => providers}/yaml/pom.xml | 0 .../lib/configuration/EasyConfiguration.java | 0 .../yaml/YAMLConfigProvider.java | 0 .../yaml/YAMLSectionWrapper.java | 1 - .../lib/configuration/yaml/YAMLValue.java | 1 - .../yaml/builder/AbstractYAMLBuilder.java | 0 .../yaml/builder/YAMLConfigBuilder.java | 0 .../serializable/SerializableBuilder.java | 0 .../yaml/value/ConfiguredSerializable.java | 0 .../src/test/java/config/DemoConfigTest.java | 0 .../src/test/java/config/model/AnyModel.java | 0 .../src/test/java/config/model/SomeModel.java | 0 .../config/source/ModelConfiguration.java | 2 +- .../yaml/src/test/java/sample/Sample.java | 1 - .../src/test/java/sample/SampleConfig.java | 2 +- .../src/test/resources/test/test2/config.yml | 0 114 files changed, 1868 insertions(+), 1772 deletions(-) delete mode 100644 commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java rename core/src/main/java/cc/carm/lib/configuration/{core => }/Configuration.java (81%) delete mode 100644 core/src/main/java/cc/carm/lib/configuration/core/function/ConfigValueParser.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationWrapper.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/core/source/impl/FileConfigProvider.java rename core/src/main/java/cc/carm/lib/configuration/{core => }/function/ConfigDataFunction.java (99%) create mode 100644 core/src/main/java/cc/carm/lib/configuration/function/ConfigValueParser.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/loader/ConfigurationLoader.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/loader/PathGenerator.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/loader/StandardPathGenerator.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/manifest/ValueManifest.java rename core/src/main/java/cc/carm/lib/configuration/{source/standard => option}/ConfigurationOptions.java (56%) rename core/src/main/java/cc/carm/lib/configuration/source/{ConfigurationBuilder.java => ConfigurationFactory.java} (62%) delete mode 100644 core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java rename core/src/main/java/cc/carm/lib/configuration/{core/source/ConfigurationReader.java => source/ConfigurationSection.java} (53%) create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSource.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/source/path/PathGenerator.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/source/path/StandardPathGenerator.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationMetaTypes.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaList.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaType.java create mode 100644 core/src/main/old/ValueManifestv.java rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/AbstractConfigBuilder.java (94%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/CommonConfigBuilder.java (67%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/ConfigBuilder.java (82%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/list/ConfigListBuilder.java (94%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/list/SourceListBuilder.java (93%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/map/ConfigMapBuilder.java (95%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/map/ConfigMapCreator.java (95%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/map/SectionMapBuilder.java (93%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/map/SourceMapBuilder.java (95%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/value/ConfigValueBuilder.java (90%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/value/SectionValueBuilder.java (83%) rename core/src/main/{java/cc/carm/lib/configuration/core => old}/builder/value/SourceValueBuilder.java (90%) create mode 100644 core/src/test/java/cc/carm/test/config/LoaderTest.java create mode 100644 core/src/test/java/cc/carm/test/config/TestSource.java create mode 100644 features/commentable/pom.xml rename {commentable => features/commentable}/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java (100%) rename {commentable => features/commentable}/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java (100%) create mode 100644 features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java rename {commentable => features/commentable}/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java (100%) rename {commentable/src/main/java/cc/carm/lib/configuration/commentable => features/commentable/src/main/java/cc/carm/lib/configuration/option}/CommentableOptions.java (88%) rename {commentable => features/file}/pom.xml (54%) create mode 100644 features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java create mode 100644 features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigProvider.java create mode 100644 features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigSource.java rename {impl/json => providers/gson}/README.md (100%) rename {impl/json => providers/gson}/pom.xml (97%) rename {impl/json => providers/gson}/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java (100%) rename {impl/json => providers/gson}/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java (97%) rename {impl/json => providers/gson}/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java (98%) rename {impl/json => providers/gson}/src/test/java/config/JSONConfigTest.java (100%) rename {impl => providers}/hocon/README.md (100%) rename {impl => providers}/hocon/pom.xml (100%) rename {impl => providers}/hocon/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java (100%) rename {impl => providers}/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONConfigWrapper.java (98%) rename {impl => providers}/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONFileConfigProvider.java (100%) rename {impl => providers}/hocon/src/main/java/cc/carm/lib/configuration/hocon/exception/HOCONGetValueException.java (100%) rename {impl => providers}/hocon/src/main/java/cc/carm/lib/configuration/hocon/util/HOCONUtils.java (100%) rename {impl => providers}/hocon/src/test/java/online/flowerinsnow/test/easyconfiguration/HOCONTest.java (100%) rename {impl => providers}/sql/README.md (100%) rename {impl => providers}/sql/pom.xml (100%) rename {impl => providers}/sql/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java (100%) rename {impl => providers}/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java (98%) rename {impl => providers}/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigWrapper.java (98%) rename {impl => providers}/sql/src/main/java/cc/carm/lib/configuration/sql/SQLValueResolver.java (100%) rename {impl => providers}/sql/src/main/java/cc/carm/lib/configuration/sql/SQLValueTypes.java (100%) rename {impl => providers}/sql/src/test/java/config/SQLConfigTest.java (100%) rename {impl => providers}/sql/src/test/resources/log4j2.xml (100%) rename {impl => providers}/yaml/README.md (100%) rename {impl => providers}/yaml/pom.xml (100%) rename {impl => providers}/yaml/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java (100%) rename {impl => providers}/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java (100%) rename {impl => providers}/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java (97%) rename {impl => providers}/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java (93%) rename {impl => providers}/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/AbstractYAMLBuilder.java (100%) rename {impl => providers}/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/YAMLConfigBuilder.java (100%) rename {impl => providers}/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java (100%) rename {impl => providers}/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java (100%) rename {impl => providers}/yaml/src/test/java/config/DemoConfigTest.java (100%) rename {impl => providers}/yaml/src/test/java/config/model/AnyModel.java (100%) rename {impl => providers}/yaml/src/test/java/config/model/SomeModel.java (100%) rename {impl => providers}/yaml/src/test/java/config/source/ModelConfiguration.java (97%) rename {impl => providers}/yaml/src/test/java/sample/Sample.java (89%) rename {impl => providers}/yaml/src/test/java/sample/SampleConfig.java (95%) rename {impl => providers}/yaml/src/test/resources/test/test2/config.yml (100%) diff --git a/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java b/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java deleted file mode 100644 index 372fe98..0000000 --- a/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java +++ /dev/null @@ -1,26 +0,0 @@ -package cc.carm.lib.configuration.commentable; - -import cc.carm.lib.configuration.annotation.HeaderComment; -import cc.carm.lib.configuration.annotation.InlineComment; -import cc.carm.lib.easyannotation.AnnotatedMetaType; - -import java.util.Arrays; -import java.util.List; - -public interface CommentableMetaTypes { - - /** - * Configuration's {@link HeaderComment} - */ - AnnotatedMetaType> HEADER_COMMENT = AnnotatedMetaType.of( - HeaderComment.class, h -> h.value().length == 0 ? null : Arrays.asList(h.value()) - ); - - /** - * Configuration's {@link InlineComment} - */ - AnnotatedMetaType INLINE_COMMENT = AnnotatedMetaType.of( - InlineComment.class, c -> c.value().isEmpty() ? null : c.value() - ); - -} diff --git a/core/pom.xml b/core/pom.xml index c3b88a3..4a285d5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -22,12 +22,7 @@ cc.carm.lib easyoptions - 1.0.0 - - - cc.carm.lib - easyannotation - 1.0.0 + 1.1.0 diff --git a/core/src/main/java/cc/carm/lib/configuration/core/Configuration.java b/core/src/main/java/cc/carm/lib/configuration/Configuration.java similarity index 81% rename from core/src/main/java/cc/carm/lib/configuration/core/Configuration.java rename to core/src/main/java/cc/carm/lib/configuration/Configuration.java index f925a20..3596cf7 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/Configuration.java +++ b/core/src/main/java/cc/carm/lib/configuration/Configuration.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.core; +package cc.carm.lib.configuration; /** * The root interface of the configuration file interfaces, 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 ab265d3..deeb81d 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 @@ -5,12 +5,10 @@ import cc.carm.lib.configuration.source.ConfigurationProvider; /** * Value adapter, used to convert the value of the configuration file into the objects. * - * @param

The type of the configuration provider. * @param The type of the base data * @param The type of the target value */ -public abstract class ValueAdapter

- implements ValueSerializer, ValueDeserializer { +public abstract class ValueAdapter implements ValueSerializer, ValueDeserializer { protected final Class baseType; protected final Class valueType; @@ -36,17 +34,17 @@ public abstract class ValueAdapter

return isAdaptedFrom(object.getClass()); } - public boolean isAdapterOf(Class clazz) { + public boolean isAdaptedTo(Class clazz) { return clazz == valueType; } @SuppressWarnings("unchecked") - protected final V deserializeObject(P provider, Class valueClass, Object data) throws Exception { + protected final V deserializeObject(ConfigurationProvider provider, Class valueClass, Object data) throws Exception { return deserialize(provider, (Class) valueClass, (B) data); } @SuppressWarnings("unchecked") - protected final B serializeObject(P provider, Object value) throws Exception { + protected final B serializeObject(ConfigurationProvider provider, Object value) throws Exception { return serialize(provider, (V) value); } 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 460e4ca..3216c79 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 @@ -1,7 +1,7 @@ package cc.carm.lib.configuration.adapter; import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigDataFunction; import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -10,29 +10,29 @@ import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; -public class ValueAdapterRegistry

{ +public class ValueAdapterRegistry { - protected final Map, ValueAdapter> adapters = new HashMap<>(); + protected final Map, ValueAdapter> adapters = new HashMap<>(); - public void register(@NotNull ValueAdapter adapter) { + public void register(@NotNull ValueAdapter adapter) { adapters.put(adapter.getValueClass(), adapter); } - public void register(Class clazz, @NotNull ValueAdapter adapter) { + public void register(Class clazz, @NotNull ValueAdapter adapter) { adapters.put(clazz, adapter); } public void register(Class baseClass, Class valueClass, ConfigDataFunction parser, ConfigDataFunction serializer) { - register(new ValueAdapter(baseClass, valueClass) { + register(new ValueAdapter(baseClass, valueClass) { @Override - public B serialize(@NotNull P provider, @NotNull V value) throws Exception { + public B serialize(@NotNull ConfigurationProvider provider, @NotNull V value) throws Exception { return serializer.parse(value); } @Override - public V deserialize(@NotNull P provider, @NotNull Class clazz, @NotNull B data) throws Exception { + public V deserialize(@NotNull ConfigurationProvider provider, @NotNull Class clazz, @NotNull B data) throws Exception { return parser.parse(data); } }); @@ -44,11 +44,11 @@ public class ValueAdapterRegistry

{ @SuppressWarnings("unchecked") @Contract("_,_,null -> null") - public T deserialize(@NotNull P provider, @NotNull Class type, @Nullable Object source) throws Exception { + public T deserialize(@NotNull ConfigurationProvider provider, @NotNull Class type, @Nullable Object source) throws Exception { if (source == null) return null; // Null check if (type.isInstance(source)) return type.cast(source); // Not required to deserialize - ValueAdapter adapter = getAdapter(type); + ValueAdapter adapter = getAdapter(type); if (adapter == null) throw new RuntimeException("No adapter for type " + type.getName()); // Check if value is adapted from given value's type @@ -64,10 +64,10 @@ public class ValueAdapterRegistry

{ } @Contract("_,null -> null") - public Object serialize(@NotNull P provider, @Nullable T value) throws Exception { + public Object serialize(@NotNull ConfigurationProvider provider, @Nullable T value) throws Exception { if (value == null) return null; // Null check - ValueAdapter adapter = getAdapter(value.getClass()); + ValueAdapter adapter = getAdapter(value.getClass()); if (adapter == null) return value; // No adapters, try to return the original value if (adapter instanceof PrimitiveAdapters) { @@ -80,12 +80,12 @@ public class ValueAdapterRegistry

{ return serialize(provider, adapter.serializeObject(provider, value)); } - public ValueAdapter getAdapter(Class clazz) { + public ValueAdapter getAdapter(Class clazz) { return adapters.getOrDefault(clazz, findAdapter(clazz)); } - public ValueAdapter findAdapter(Class clazz) { - return adapters.values().stream().filter(adapter -> adapter.isAdapterOf(clazz)).findFirst().orElse(null); + public ValueAdapter findAdapter(Class clazz) { + return adapters.values().stream().filter(adapter -> adapter.isAdaptedTo(clazz)).findFirst().orElse(null); } diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java index 381d315..2f63ebb 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java @@ -6,13 +6,12 @@ import org.jetbrains.annotations.NotNull; /** * Value deserializer, convert base data to target value. * - * @param

Configuration provider * @param The type of base data * @param The type of target value */ @FunctionalInterface -public interface ValueDeserializer

{ +public interface ValueDeserializer { - V deserialize(@NotNull P provider, @NotNull Class clazz, @NotNull B data) throws Exception; + V deserialize(@NotNull ConfigurationProvider provider, @NotNull Class clazz, @NotNull B data) throws Exception; } diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java index 3161bf2..d27e8c9 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java @@ -6,13 +6,12 @@ import org.jetbrains.annotations.NotNull; /** * Value serializer, convert target value to base data. * - * @param

Configuration provider * @param The type of base data * @param The type of value */ @FunctionalInterface -public interface ValueSerializer

{ +public interface ValueSerializer { - B serialize(@NotNull P provider, @NotNull V value) throws Exception; + B serialize(@NotNull ConfigurationProvider provider, @NotNull V value) throws Exception; } diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java index 6f53595..ee4a3a4 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java @@ -5,24 +5,24 @@ import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.NotNull; @SuppressWarnings({"unchecked", "rawtypes"}) -public class EnumAdapter

extends ValueAdapter { +public class EnumAdapter extends ValueAdapter { public EnumAdapter() { super(String.class, Enum.class); } @Override - public String serialize(@NotNull P provider, @NotNull Enum value) throws Exception { + public String serialize(@NotNull ConfigurationProvider provider, @NotNull Enum value) throws Exception { return value.name(); } @Override - public Enum deserialize(@NotNull P provider, @NotNull Class clazz, @NotNull String data) throws Exception { + public Enum deserialize(@NotNull ConfigurationProvider provider, @NotNull Class clazz, @NotNull String data) throws Exception { return Enum.valueOf(clazz, data); } @Override - public boolean isAdapterOf(Class clazz) { + public boolean isAdaptedTo(Class clazz) { return clazz.isEnum(); } diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java index 6062b7b..5a36a73 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java @@ -1,45 +1,45 @@ package cc.carm.lib.configuration.adapter.strandard; import cc.carm.lib.configuration.adapter.ValueAdapter; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigDataFunction; import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.NotNull; -public abstract class PrimitiveAdapters

extends ValueAdapter { +public abstract class PrimitiveAdapters extends ValueAdapter { - public static

PrimitiveAdapters ofString() { + public static PrimitiveAdapters ofString() { return of(String.class, o -> o instanceof String ? (String) o : o.toString()); } - public static

PrimitiveAdapters ofBoolean() { + public static PrimitiveAdapters ofBoolean() { return of(Boolean.class, o -> o instanceof Boolean ? (Boolean) o : Boolean.parseBoolean(o.toString())); } - public static

PrimitiveAdapters ofCharacter() { + public static PrimitiveAdapters ofCharacter() { return of(Character.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0)); } - public static

PrimitiveAdapters ofInteger() { + public static PrimitiveAdapters ofInteger() { return ofNumber(Integer.class, Number::intValue, Integer::parseInt); } - public static

PrimitiveAdapters ofLong() { + public static PrimitiveAdapters ofLong() { return ofNumber(Long.class, Number::longValue, Long::parseLong); } - public static

PrimitiveAdapters ofDouble() { + public static PrimitiveAdapters ofDouble() { return ofNumber(Double.class, Number::doubleValue, Double::parseDouble); } - public static

PrimitiveAdapters ofFloat() { + public static PrimitiveAdapters ofFloat() { return ofNumber(Float.class, Number::floatValue, Float::parseFloat); } - public static

PrimitiveAdapters ofShort() { + public static PrimitiveAdapters ofShort() { return ofNumber(Short.class, Number::shortValue, Short::parseShort); } - public static

PrimitiveAdapters ofByte() { + public static PrimitiveAdapters ofByte() { return ofNumber(Byte.class, Number::byteValue, Byte::parseByte); } @@ -48,23 +48,23 @@ public abstract class PrimitiveAdapters

exte } @Override - public Object serialize(@NotNull P provider, @NotNull T value) throws Exception { + public Object serialize(@NotNull ConfigurationProvider provider, @NotNull T value) throws Exception { return value; } - public static

PrimitiveAdapters of(@NotNull Class clazz, - @NotNull ConfigDataFunction function) { - return new PrimitiveAdapters(clazz) { + public static PrimitiveAdapters of(@NotNull Class clazz, + @NotNull ConfigDataFunction function) { + return new PrimitiveAdapters(clazz) { @Override - public T deserialize(@NotNull P provider, @NotNull Class clazz, @NotNull Object data) throws Exception { + public T deserialize(@NotNull ConfigurationProvider provider, @NotNull Class clazz, @NotNull Object data) throws Exception { return function.parse(data); } }; } - public static

PrimitiveAdapters ofNumber(@NotNull Class numberClass, - @NotNull ConfigDataFunction castFunction, - @NotNull ConfigDataFunction parseFunction) { + public static PrimitiveAdapters ofNumber(@NotNull Class numberClass, + @NotNull ConfigDataFunction castFunction, + @NotNull ConfigDataFunction parseFunction) { return of(numberClass, o -> o instanceof Number ? castFunction.parse((Number) o) : parseFunction.parse(o.toString())); } } diff --git a/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java index 252e6a4..c843e17 100644 --- a/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java +++ b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java @@ -1,5 +1,7 @@ package cc.carm.lib.configuration.annotation; +import cc.carm.lib.configuration.loader.PathGenerator; + import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -14,7 +16,7 @@ public @interface ConfigPath { /** * The path value of the current configuration. - * If not set,will generate the path by {@link cc.carm.lib.configuration.source.path.PathGenerator}. + * If not set,will generate the path by {@link PathGenerator}. * * @return The path value of the current configuration */ diff --git a/core/src/main/java/cc/carm/lib/configuration/core/function/ConfigValueParser.java b/core/src/main/java/cc/carm/lib/configuration/core/function/ConfigValueParser.java deleted file mode 100644 index 7dc7762..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/core/function/ConfigValueParser.java +++ /dev/null @@ -1,159 +0,0 @@ -package cc.carm.lib.configuration.core.function; - - -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; -import java.util.UUID; - -@FunctionalInterface -public interface ConfigValueParser { - - @Nullable R parse(@NotNull T data, @Nullable R defaultValue) throws Exception; - - default ConfigValueParser andThen(@NotNull ConfigValueParser after) { - Objects.requireNonNull(after); - return ((data, defaultValue) -> { - R result = parse(data, null); - if (result == null) return defaultValue; - else return after.parse(result, defaultValue); - }); - } - - default ConfigValueParser compose(@NotNull ConfigDataFunction before) { - Objects.requireNonNull(before); - return ((data, defaultValue) -> { - T result = before.parse(data); - return parse(result, defaultValue); - }); - } - - - @Contract(pure = true) - static @NotNull ConfigValueParser identity() { - return (input, defaultValue) -> input; - } - - @Contract(pure = true) - static @NotNull ConfigValueParser toObject() { - return (input, defaultValue) -> input; - } - - @Contract(pure = true) - static @NotNull ConfigValueParser required() { - return (input, defaultValue) -> { - throw new IllegalArgumentException("Please specify the value parser."); - }; - } - - @Contract(pure = true) - static @NotNull ConfigValueParser castObject(Class valueClass) { - if (Number.class.isAssignableFrom(valueClass)) return castNumber(valueClass); - else return (input, defaultValue) -> { - if (Boolean.class.isAssignableFrom(valueClass) || boolean.class.isAssignableFrom(valueClass)) { - input = booleanValue().parse(input, (Boolean) defaultValue); - } else if (Enum.class.isAssignableFrom(valueClass) && input instanceof String) { - String enumName = (String) input; - input = valueClass.getDeclaredMethod("valueOf", String.class).invoke(null, enumName); - } else if (UUID.class.isAssignableFrom(valueClass) && input instanceof String) { - input = UUID.fromString((String) input); - } - - if (valueClass.isInstance(input)) return valueClass.cast(input); - else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName()); - }; - } - - - @Contract(pure = true) - static @NotNull ConfigValueParser castNumber(Class valueClass) { - return (input, defaultValue) -> { - if (Long.class.isAssignableFrom(valueClass) || long.class.isAssignableFrom(valueClass)) { - input = longValue().parse(input, (Long) defaultValue); - } else if (Integer.class.isAssignableFrom(valueClass) || int.class.isAssignableFrom(valueClass)) { - input = intValue().parse(input, (Integer) defaultValue); - } else if (Float.class.isAssignableFrom(valueClass) || float.class.isAssignableFrom(valueClass)) { - input = floatValue().parse(input, (Float) defaultValue); - } else if (Double.class.isAssignableFrom(valueClass) || double.class.isAssignableFrom(valueClass)) { - input = doubleValue().parse(input, (Double) defaultValue); - } else if (Byte.class.isAssignableFrom(valueClass) || byte.class.isAssignableFrom(valueClass)) { - input = byteValue().parse(input, (Byte) defaultValue); - } else if (Short.class.isAssignableFrom(valueClass) || short.class.isAssignableFrom(valueClass)) { - input = shortValue().parse(input, (Short) defaultValue); - } - if (valueClass.isInstance(input)) return valueClass.cast(input); - else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName()); - }; - } - - @Contract(pure = true) - static @NotNull ConfigValueParser parseString(Class valueClass) { - return (input, defaultValue) -> { - if (valueClass.isInstance(input)) return valueClass.cast(input); - else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName()); - }; - } - - @Contract(pure = true) - static @NotNull ConfigValueParser castToString() { - return (input, defaultValue) -> { - if (input instanceof String) return (String) input; - else return input.toString(); - }; - } - - @Contract(pure = true) - static @NotNull ConfigValueParser intValue() { - return (input, defaultValue) -> ConfigDataFunction.intValue().parse(input); - } - - @Contract(pure = true) - static @NotNull ConfigValueParser shortValue() { - return (input, defaultValue) -> ConfigDataFunction.shortValue().parse(input); - } - - @Contract(pure = true) - static @NotNull ConfigValueParser doubleValue() { - return (input, defaultValue) -> ConfigDataFunction.doubleValue().parse(input); - } - - @Contract(pure = true) - static @NotNull ConfigValueParser byteValue() { - return (input, defaultValue) -> ConfigDataFunction.byteValue().parse(input); - } - - @Contract(pure = true) - static @NotNull ConfigValueParser floatValue() { - return (input, defaultValue) -> ConfigDataFunction.floatValue().parse(input); - } - - @Contract(pure = true) - static @NotNull ConfigValueParser longValue() { - return (input, defaultValue) -> ConfigDataFunction.longValue().parse(input); - } - - @Contract(pure = true) - static @NotNull ConfigValueParser booleanValue() { - return (input, defaultValue) -> ConfigDataFunction.booleanValue().parse(input); - } - - @Contract(pure = true) - static @NotNull > ConfigValueParser enumValue(Class enumClass) { - return (input, defaultValue) -> { - if (input instanceof Enum) { - return enumClass.cast(input); - } else if (input instanceof String) { - return Enum.valueOf(enumClass, (String) input); - } else if (input instanceof Number) { - return enumClass.getEnumConstants()[((Number) input).intValue()]; - } else { - throw new IllegalArgumentException("Cannot cast value to " + enumClass.getName()); - } - }; - } - -} - - diff --git a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java b/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java deleted file mode 100644 index 09de47b..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java +++ /dev/null @@ -1,150 +0,0 @@ -package cc.carm.lib.configuration.core.source; - -import cc.carm.lib.configuration.core.Configuration; -import cc.carm.lib.configuration.source.comment.ConfigurationComments; -import cc.carm.lib.configuration.value.ConfigValue; -import cc.carm.lib.configuration.value.impl.CachedConfigValue; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Unmodifiable; - -import java.util.List; -import java.util.Optional; - -/** - * 配置文件提供者,用于为 {@link ConfigValue} 提供配置文件的源,以便实现读取、保存等操作。 - * - * @param 配置文件的原生功能类 - */ -public abstract class ConfigurationProvider> { - - protected long updateTime; - - protected ConfigurationProvider() { - this.updateTime = System.currentTimeMillis(); - } - - /** - * 得到配置文件的更新(最后加载)时间。 - * - * @return 更新时间 - */ - public long getUpdateTime() { - return updateTime; - } - - /** - * 用于 {@link CachedConfigValue} 判断缓存值是否过期(即缓存的时间早于配置文件的最后加载时间)。 - * - * @param time 缓存值时的时间戳 - * @return 缓存值是否过期 - */ - public boolean isExpired(long time) { - return getUpdateTime() > time; - } - - /** - * 得到配置文件的原生功能类。 - * - * @return 原生类 - */ - public abstract @NotNull W getConfiguration(); - - /** - * 重载当前配置文件。(将不会保存已修改的内容) - * - * @throws Exception 当重载出现错误时抛出 - */ - public void reload() throws Exception { - onReload(); // 调用重写的Reload方法 - this.updateTime = System.currentTimeMillis(); - } - - /** - * 将当前对配置文件的更改进行保存。 - * - * @throws Exception 当保存出现错误时抛出 - */ - public abstract void save() throws Exception; - - /** - * 针对于不同配置文件类型所执行的重载操作。 - * - * @throws Exception 当操作出现错误时抛出。 - */ - protected abstract void onReload() throws Exception; - - public abstract @Nullable ConfigurationComments getComments(); - - public void setHeaderComment(@Nullable String path, @Nullable List comments) { - if (getComments() == null) return; - getComments().setHeaderComments(path, comments); - } - - public void setInlineComment(@NotNull String path, @Nullable String comment) { - if (getComments() == null) return; - getComments().setInlineComment(path, comment); - } - - @Nullable - @Unmodifiable - public List getHeaderComment(@Nullable String path) { - return Optional.ofNullable(getComments()).map(c -> c.getHeaderComment(path)).orElse(null); - } - - public @Nullable String getInlineComment(@NotNull String path) { - return Optional.ofNullable(getComments()).map(c -> c.getInlineComment(path)).orElse(null); - } - - public abstract @NotNull ConfigInitializer> getInitializer(); - - /** - * 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。 - * - * @param configClazz 配置文件类,须继承于 {@link Configuration} 。 - */ - public void initialize(Class configClazz) { - initialize(configClazz, true); - } - - /** - * 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。 - * - * @param configClazz 配置文件类,须继承于 {@link Configuration} 。 - * @param saveDefaults 是否写入默认值(默认为 true)。 - */ - public void initialize(Class configClazz, boolean saveDefaults) { - this.getInitializer().initialize(configClazz, saveDefaults); - } - - /** - * 初始化指定类的所有 {@link ConfigValue} 对象。 - * - * @param configClazz 配置文件类,须继承于 {@link Configuration} 。 - * @param saveDefaults 是否写入默认值(默认为 true)。 - * @param loadSubClasses 是否加载内部子类(默认为 true)。 - */ - public void initialize(Class configClazz, boolean saveDefaults, boolean loadSubClasses) { - this.getInitializer().initialize(configClazz, saveDefaults, loadSubClasses); - } - - /** - * 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。 - * - * @param config 配置文件实例类,须实现 {@link Configuration} 。 - */ - public void initialize(@NotNull Configuration config) { - this.getInitializer().initialize(config, true); - } - - /** - * 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。 - * - * @param config 配置文件实例类,须实现 {@link Configuration} 。 - * @param saveDefaults 是否写入默认值(默认为 true)。 - */ - public void initialize(@NotNull Configuration config, boolean saveDefaults) { - this.getInitializer().initialize(config, saveDefaults); - } - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationWrapper.java b/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationWrapper.java deleted file mode 100644 index 478af95..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationWrapper.java +++ /dev/null @@ -1,73 +0,0 @@ -package cc.carm.lib.configuration.core.source; - -import cc.carm.lib.configuration.core.function.ConfigValueParser; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -public interface ConfigurationWrapper extends ConfigurationReader { - - @Override - default ConfigurationWrapper getWrapper() { - return this; - } - - @NotNull S getSource(); - - @NotNull - Set getKeys(boolean deep); - - @NotNull - Map getValues(boolean deep); - - void set(@NotNull String path, @Nullable Object value); - - boolean contains(@NotNull String path); - - default boolean isType(@NotNull String path, @NotNull Class typeClass) { - return typeClass.isInstance(get(path)); - } - - @Nullable Object get(@NotNull String path); - - default @Nullable T get(@NotNull String path, @NotNull Class clazz) { - return get(path, null, clazz); - } - - default @Nullable T get(@NotNull String path, @NotNull ConfigValueParser parser) { - return get(path, null, parser); - } - - @Contract("_,!null,_->!null") - default @Nullable T get(@NotNull String path, @Nullable T defaultValue, @NotNull Class clazz) { - return get(path, defaultValue, ConfigValueParser.castObject(clazz)); - } - - @Contract("_,!null,_->!null") - default @Nullable T get(@NotNull String path, @Nullable T defaultValue, - @NotNull ConfigValueParser parser) { - Object value = get(path); - if (value != null) { - try { - return parser.parse(value, defaultValue); - } catch (Exception e) { - e.printStackTrace(); - } - } - return defaultValue; - } - - boolean isList(@NotNull String path); - - @Nullable List getList(@NotNull String path); - - boolean isConfigurationSection(@NotNull String path); - - @Nullable - ConfigurationWrapper getConfigurationSection(@NotNull String path); - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/source/impl/FileConfigProvider.java b/core/src/main/java/cc/carm/lib/configuration/core/source/impl/FileConfigProvider.java deleted file mode 100644 index ffffd13..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/core/source/impl/FileConfigProvider.java +++ /dev/null @@ -1,89 +0,0 @@ -package cc.carm.lib.configuration.core.source.impl; - -import cc.carm.lib.configuration.core.source.ConfigurationProvider; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.net.URLConnection; -import java.nio.file.Files; -import java.util.Objects; - -public abstract class FileConfigProvider> extends ConfigurationProvider { - - protected final @NotNull File file; - - protected FileConfigProvider(@NotNull File file) { - this.file = file; - } - - public @NotNull File getFile() { - return file; - } - - public void initializeFile(@Nullable String sourcePath) throws IOException { - if (this.file.exists()) return; - - File parent = this.file.getParentFile(); - if (parent != null && !parent.exists() && !parent.mkdirs()) { - throw new IOException("Failed to create directory " + file.getParentFile().getAbsolutePath()); - } - - if (!this.file.createNewFile()) { - throw new IOException("Failed to create file " + file.getAbsolutePath()); - } - - if (sourcePath != null) { - try { - saveResource(sourcePath, true); - } catch (IllegalArgumentException ignored) { - } - } - } - - public void saveResource(@NotNull String resourcePath, boolean replace) - throws IOException, IllegalArgumentException { - Objects.requireNonNull(resourcePath, "ResourcePath cannot be null"); - if (resourcePath.isEmpty()) throw new IllegalArgumentException("ResourcePath cannot be empty"); - - resourcePath = resourcePath.replace('\\', '/'); - - URL url = this.getClass().getClassLoader().getResource(resourcePath); - if (url == null) throw new IllegalArgumentException("The resource '" + resourcePath + "' not exists"); - - File outDir = file.getParentFile(); - - if (!outDir.exists() && !outDir.mkdirs()) throw new IOException("Failed to create directory " + outDir); - if (!file.exists() || replace) { - try (OutputStream out = Files.newOutputStream(file.toPath())) { - URLConnection connection = url.openConnection(); - connection.setUseCaches(false); - try (InputStream in = connection.getInputStream()) { - byte[] buf = new byte[1024]; - int len; - while ((len = in.read(buf)) > 0) { - out.write(buf, 0, len); - } - } - } - } - } - - @Nullable - public InputStream getResource(@NotNull String filename) { - try { - URL url = this.getClass().getClassLoader().getResource(filename); - if (url == null) return null; - URLConnection connection = url.openConnection(); - connection.setUseCaches(false); - return connection.getInputStream(); - } catch (IOException ex) { - return null; - } - } -} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/function/ConfigDataFunction.java b/core/src/main/java/cc/carm/lib/configuration/function/ConfigDataFunction.java similarity index 99% rename from core/src/main/java/cc/carm/lib/configuration/core/function/ConfigDataFunction.java rename to core/src/main/java/cc/carm/lib/configuration/function/ConfigDataFunction.java index d40fda3..04d8cff 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/function/ConfigDataFunction.java +++ b/core/src/main/java/cc/carm/lib/configuration/function/ConfigDataFunction.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.core.function; +package cc.carm.lib.configuration.function; import org.jetbrains.annotations.Contract; diff --git a/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueParser.java b/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueParser.java new file mode 100644 index 0000000..9554776 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueParser.java @@ -0,0 +1,62 @@ +package cc.carm.lib.configuration.function; + + +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +@FunctionalInterface +public interface ConfigValueParser { + + @Nullable R parse(@NotNull ConfigurationProvider provider, + @NotNull T data, @Nullable R defaultValue) throws Exception; + + default ConfigValueParser andThen(@NotNull ConfigValueParser after) { + Objects.requireNonNull(after); + return ((provider, data, defaultValue) -> { + R result = parse(provider, data, null); + if (result == null) return defaultValue; + else return after.parse(provider, result, defaultValue); + }); + } + + default ConfigValueParser compose(@NotNull ConfigValueParser before) { + Objects.requireNonNull(before); + return ((provider, data, defaultValue) -> { + T result = before.parse(provider, data, null); + if (result == null) return null; + return parse(provider, result, defaultValue); + }); + } + + default ConfigValueParser compose(@NotNull ConfigDataFunction before) { + Objects.requireNonNull(before); + return ((provider, data, defaultValue) -> { + T result = before.parse(data); + return parse(provider, result, defaultValue); + }); + } + + @Contract(pure = true) + static @NotNull ConfigValueParser identity() { + return (provider, input, defaultValue) -> input; + } + + @Contract(pure = true) + static @NotNull ConfigValueParser toObject() { + return (provider, input, defaultValue) -> input; + } + + @Contract(pure = true) + static @NotNull ConfigValueParser required() { + return (provider, input, defaultValue) -> { + throw new IllegalArgumentException("Please specify the value parser."); + }; + } + +} + + diff --git a/core/src/main/java/cc/carm/lib/configuration/loader/ConfigurationLoader.java b/core/src/main/java/cc/carm/lib/configuration/loader/ConfigurationLoader.java new file mode 100644 index 0000000..d2d341a --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/loader/ConfigurationLoader.java @@ -0,0 +1,107 @@ +package cc.carm.lib.configuration.loader; + +import cc.carm.lib.configuration.Configuration; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.option.ConfigurationOptions; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.Arrays; + +/** + * Configuration loader, + * used to load configuration values from {@link Configuration} classes. + */ +public class ConfigurationLoader { + + protected PathGenerator pathGenerator; + + public ConfigurationLoader() { + this(StandardPathGenerator.of()); + } + + public ConfigurationLoader(PathGenerator pathGenerator) { + this.pathGenerator = pathGenerator; + } + + public void setPathGenerator(PathGenerator pathGenerator) { + this.pathGenerator = pathGenerator; + } + + public PathGenerator getPathGenerator() { + return pathGenerator; + } + + public @Nullable String getFieldPath(ConfigurationProvider provider, @Nullable String parentPath, @NotNull Field field) { + return pathGenerator.getFieldPath(provider, parentPath, field); + } + + public @Nullable String getClassPath(ConfigurationProvider provider, @Nullable String parentPath, + @NotNull Class clazz, @Nullable Field clazzField) { + return pathGenerator.getClassPath(provider, parentPath, clazz, clazzField); + } + + public void load(ConfigurationProvider provider, @NotNull Configuration config) throws Exception { + initializeInstance(provider, config, null, null); + if (provider.option(ConfigurationOptions.SET_DEFAULTS)) provider.save(); + } + + public void load(ConfigurationProvider provider, @NotNull Class clazz) throws Exception { + initializeStaticClass(provider, clazz, null, null); + if (provider.option(ConfigurationOptions.SET_DEFAULTS)) provider.save(); + } + + + // 针对实例类的初始化方法 + private void initializeInstance(@NotNull ConfigurationProvider provider, + @NotNull Configuration root, @Nullable String parentPath, @Nullable Field configField) { + String path = getClassPath(provider, parentPath, root.getClass(), configField); + Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(provider, root, field, path)); + } + + // 针对静态类的初始化方法 + private void initializeStaticClass(@NotNull ConfigurationProvider provider, + @NotNull Class clazz, @Nullable String parentPath, @Nullable Field configField) { + if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类 + String path = getClassPath(provider, parentPath, clazz, configField); + + for (Field field : clazz.getDeclaredFields()) { + initializeField(provider, clazz, field, path); + } + + if (!provider.option(ConfigurationOptions.LOAD_SUB_CLASSES)) return; + Class[] classes = clazz.getDeclaredClasses(); + for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。 + initializeStaticClass(provider, classes[i], path, null); + } + } + + private void initializeField(@NotNull ConfigurationProvider provider, + @NotNull Object source, @NotNull Field field, @Nullable String parent) { + try { + field.setAccessible(true); + Object object = field.get(source); +// +// if (object instanceof ConfigValue) { +// // 目标是 ConfigValue 实例,进行具体的初始化注入 +// +// } else + + if (source instanceof Configuration && object instanceof Configuration) { + // 当且仅当 源字段与字段 均为ConfigurationRoot实例时,才对目标字段进行下一步初始化加载。 + initializeInstance(provider, (Configuration) object, parent, field); + } else if (source instanceof Class && object instanceof Class) { + // 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。 + initializeStaticClass(provider, (Class) object, parent, field); + } + + // 以上判断实现以下规范: + // - 实例类中仅加载 ConfigValue实例 与 ConfigurationRoot实例 + // - 静态类中仅加载 静态ConfigValue实例 与 静态ConfigurationRoot类 + + } catch (IllegalAccessException ignored) { + } + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/loader/PathGenerator.java b/core/src/main/java/cc/carm/lib/configuration/loader/PathGenerator.java new file mode 100644 index 0000000..d2ad485 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/loader/PathGenerator.java @@ -0,0 +1,43 @@ +package cc.carm.lib.configuration.loader; + +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; + +public interface PathGenerator { + + @Nullable String getFieldPath(@NotNull ConfigurationProvider provider, + @Nullable String parentPath, @NotNull Field field); + + @Nullable String getClassPath(@NotNull ConfigurationProvider provider, + @Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField); + + /** + * Get the configuration name of the specified element. + * Use the naming convention of all lowercase and "-" links. + * + * @param name source name + * @return the final path + */ + static String covertPathName(String name) { + return name + // Replace all uppercase letters with dashes + .replaceAll("[A-Z]", "-$0") + // If the first letter is also capitalized, + // it will also be converted and the first dash will need to be removed + .replaceAll("-(.*)", "$1") + // Because the name may contain _, it needs to be treated a little differently + .replaceAll("_-([A-Z])", "_$1") + // The content that is not named in all caps is then converted + .replaceAll("([a-z])-([A-Z])", "$1_$2") + // Remove any extra horizontal lines + .replace("-", "") + // Replace the underscore with a dash + .replace("_", "-") + // Finally, convert it to all lowercase + .toLowerCase(); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/loader/StandardPathGenerator.java b/core/src/main/java/cc/carm/lib/configuration/loader/StandardPathGenerator.java new file mode 100644 index 0000000..4513647 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/loader/StandardPathGenerator.java @@ -0,0 +1,86 @@ +package cc.carm.lib.configuration.loader; + +import cc.carm.lib.configuration.annotation.ConfigPath; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.option.ConfigurationOptions; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.function.UnaryOperator; + +public class StandardPathGenerator implements PathGenerator { + + public static StandardPathGenerator of() { + return of(PathGenerator::covertPathName); + } + + public static StandardPathGenerator of(UnaryOperator pathConverter) { + return new StandardPathGenerator(pathConverter); + } + + protected UnaryOperator pathConverter; + + public StandardPathGenerator(UnaryOperator pathConverter) { + this.pathConverter = pathConverter; + } + + public @NotNull UnaryOperator getPathConverter() { + return pathConverter; + } + + public void setPathConverter(UnaryOperator pathConverter) { + this.pathConverter = pathConverter; + } + + public String covertPath(String name) { + return pathConverter.apply(name); + } + + public char pathSeparator(ConfigurationProvider provider) { + return provider.option(ConfigurationOptions.PATH_SEPARATOR); + } + + @Override + public @Nullable String getFieldPath(@NotNull ConfigurationProvider provider, + @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())); + } + + @Override + public @Nullable String getClassPath(@NotNull ConfigurationProvider provider, + @Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField) { + // For standard path generator, we generate path following by: + // 1. Check if the class has a ConfigPath annotation, if so, use the root and value as the path. + // 2. If the class defined as a field, check if the field has a ConfigPath annotation, + // and use filed information. + ConfigPath clazzPath = clazz.getAnnotation(ConfigPath.class); + + if (clazzPath != null) return link(provider, parentPath, clazzPath.root(), clazzPath.value()); + if (clazzField == null) { + return link(provider, 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); + } + + protected String select(String path, String defaultValue) { + if (path == null || path.isEmpty()) return defaultValue; + else return isBlank(path) ? null : path; + } + + protected boolean isBlank(String path) { + return path == null || path.replace(" ", "").isEmpty(); + } + + protected @Nullable String link(@NotNull ConfigurationProvider provider, @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); + } + + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/manifest/ValueManifest.java b/core/src/main/java/cc/carm/lib/configuration/manifest/ValueManifest.java deleted file mode 100644 index 8ef68e2..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/manifest/ValueManifest.java +++ /dev/null @@ -1,8 +0,0 @@ -package cc.carm.lib.configuration.manifest; - -public class ValueManifest { - - - - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationOptions.java b/core/src/main/java/cc/carm/lib/configuration/option/ConfigurationOptions.java similarity index 56% rename from core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationOptions.java rename to core/src/main/java/cc/carm/lib/configuration/option/ConfigurationOptions.java index 88485b8..6e17d6c 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationOptions.java +++ b/core/src/main/java/cc/carm/lib/configuration/option/ConfigurationOptions.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.source.standard; +package cc.carm.lib.configuration.option; import cc.carm.lib.easyoptions.OptionType; @@ -13,14 +13,9 @@ public interface ConfigurationOptions { OptionType PATH_SEPARATOR = of('.'); /** - * Whether to copy files from resource if exists. + * Whether to set & save default values if offered and not exists in configuration. */ - OptionType COPY_DEFAULTS = of(true); - - /** - * Whether to save default values if offered and not exists in configuration. - */ - OptionType SAVE_DEFAULTS = of(true); + OptionType SET_DEFAULTS = of(true); /** * Whether to load subclasses of configuration class. diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationFactory.java similarity index 62% rename from core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java rename to core/src/main/java/cc/carm/lib/configuration/source/ConfigurationFactory.java index 188dae2..2e7b229 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationFactory.java @@ -2,8 +2,9 @@ package cc.carm.lib.configuration.source; import cc.carm.lib.configuration.adapter.ValueAdapter; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.source.path.PathGenerator; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.loader.ConfigurationLoader; +import cc.carm.lib.configuration.loader.PathGenerator; import cc.carm.lib.easyoptions.OptionHolder; import cc.carm.lib.easyoptions.OptionType; import org.jetbrains.annotations.NotNull; @@ -11,53 +12,52 @@ import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; import java.util.function.Function; -public abstract class ConfigurationBuilder

, C> { +public abstract class ConfigurationFactory

, C> { - - protected Function> loaderFunction = ConfigurationLoader::new; - protected Consumer> loaderConsumer = loader -> { + protected Function loaderFunction = p -> new ConfigurationLoader(); + protected Consumer loaderConsumer = loader -> { }; - protected ValueAdapterRegistry

adapters = new ValueAdapterRegistry<>(); + protected ValueAdapterRegistry adapters = new ValueAdapterRegistry(); protected OptionHolder options = new OptionHolder(); public abstract C getThis(); - public C loader(Function> loaderFunction) { + public C loader(Function loaderFunction) { this.loaderFunction = loaderFunction; return getThis(); } - public C loader(ConfigurationLoader

loader) { + public C loader(ConfigurationLoader loader) { return loader(p -> loader); } - public C loader(Consumer> loaderConsumer) { + public C loader(Consumer loaderConsumer) { this.loaderConsumer = this.loaderConsumer.andThen(loaderConsumer); return getThis(); } - public C pathGenerator(PathGenerator

pathGenerator) { + public C pathGenerator(PathGenerator pathGenerator) { return loader(loader -> { loader.setPathGenerator(pathGenerator); }); } - public C adapters(ValueAdapterRegistry

adapters) { + public C adapters(ValueAdapterRegistry adapters) { this.adapters = adapters; return getThis(); } - public C adapter(Consumer> adapterRegistryConsumer) { + public C adapter(Consumer adapterRegistryConsumer) { adapterRegistryConsumer.accept(adapters); return getThis(); } - public C adapter(@NotNull ValueAdapter adapter) { + public C adapter(@NotNull ValueAdapter adapter) { return adapter(a -> a.register(adapter)); } - public C adapter(Class clazz, @NotNull ValueAdapter adapter) { + public C adapter(Class clazz, @NotNull ValueAdapter adapter) { return adapter(a -> a.register(clazz, adapter)); } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java deleted file mode 100644 index a56eae9..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationLoader.java +++ /dev/null @@ -1,196 +0,0 @@ -package cc.carm.lib.configuration.source; - -import cc.carm.lib.configuration.annotation.ConfigPath; -import cc.carm.lib.configuration.core.Configuration; -import cc.carm.lib.configuration.source.path.PathGenerator; -import cc.carm.lib.configuration.source.path.StandardPathGenerator; -import cc.carm.lib.configuration.value.ConfigValue; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Field; - -/** - * Configuration loader, - * used to load configuration values from {@link cc.carm.lib.configuration.core.Configuration} classes. - */ -public class ConfigurationLoader

> { - - protected final P provider; - protected PathGenerator

pathGenerator; - - public ConfigurationLoader(P provider) { - this(provider, StandardPathGenerator.of(provider)); - } - - public ConfigurationLoader(P provider, PathGenerator

pathGenerator) { - this.provider = provider; - this.pathGenerator = pathGenerator; - } - - public void setPathGenerator(PathGenerator

pathGenerator) { - this.pathGenerator = pathGenerator; - } - - public PathGenerator

getPathGenerator() { - return pathGenerator; - } - - /** - * 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。 - * - * @param clazz 配置文件类,须继承于 {@link Configuration} 。 - */ - public void initialize(@NotNull P provider, @NotNull Class clazz) { - initialize(clazz, saveDefaults, true); - } - - /** - * 初始化指定类的所有 {@link ConfigValue} 对象。 - * - * @param clazz 配置文件类,须继承于 {@link Configuration} 。 - * @param saveDefaults 是否写入默认值(默认为 true)。 - * @param loadSubClasses 是否加载内部子类(默认为 true)。 - */ - public void initialize(@NotNull Class clazz) { - initializeStaticClass( - clazz, null, null, - null, null, null, - saveDefaults, loadSubClasses - ); - if (saveDefaults) { - try { - provider.save(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - /** - * 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。 - * - * @param config 配置文件实例类,须实现 {@link Configuration} 。 - */ - public void initialize(@NotNull Configuration config) { - initialize(config, true); - } - - /** - * 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。 - * - * @param config 配置文件实例类,须实现 {@link Configuration} 。 - * @param saveDefaults 是否写入默认值(默认为 true)。 - */ - public void initialize(@NotNull Configuration config, boolean saveDefaults) { - initializeInstance( - config, null, null, - null, null, null, - saveDefaults - ); - if (saveDefaults) { - try { - provider.save(); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - - // 针对实例类的初始化方法 - private void initializeInstance(@NotNull Configuration root, - @Nullable String parentPath, @Nullable String fieldName, - @Nullable ConfigPath fieldPath, - @Nullable HeaderComment fieldHeaderComments, - @Nullable InlineComment fieldInlineComments, - boolean saveDefaults) { - String path = getClassPath(root.getClass(), parentPath, fieldName, fieldPath); - this.provider.setHeaderComment(path, getClassHeaderComments(root.getClass(), fieldHeaderComments)); - if (path != null) this.provider.setInlineComment(path, readInlineComments(fieldInlineComments)); - - for (Field field : root.getClass().getDeclaredFields()) { - initializeField(root, field, path, saveDefaults, false); - } - } - - // 针对静态类的初始化方法 - private void initializeStaticClass(@NotNull Class clazz, - @Nullable String parentPath, @Nullable String fieldName, - @Nullable ConfigPath fieldPath, - @Nullable HeaderComment fieldHeaderComments, - @Nullable InlineComment fieldInlineComments, - boolean saveDefaults, boolean loadSubClasses) { - if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类 - String path = getClassPath(clazz, parentPath, fieldName, fieldPath); - this.provider.setHeaderComment(path, getClassHeaderComments(clazz, fieldHeaderComments)); - if (path != null) this.provider.setInlineComment(path, readInlineComments(fieldInlineComments)); - - for (Field field : clazz.getDeclaredFields()) { - initializeField(clazz, field, path, saveDefaults, loadSubClasses); - } - - if (!loadSubClasses) return; - Class[] classes = clazz.getDeclaredClasses(); - for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。 - initializeStaticClass( - classes[i], path, classes[i].getSimpleName(), - null, null, null, - saveDefaults, true - ); - } - } - - private void initializeField(@NotNull Object source, @NotNull Field field, - @Nullable String parent, boolean saveDefaults, boolean loadSubClasses) { - try { - field.setAccessible(true); - Object object = field.get(source); - - if (object instanceof ConfigValue) { - initializeValue( - (ConfigValue) object, getFieldPath(field, parent), - field.getAnnotation(HeaderComment.class), - field.getAnnotation(InlineComment.class), - saveDefaults - ); - } else if (source instanceof Configuration && object instanceof Configuration) { - // 当且仅当 源字段与字段 均为ConfigurationRoot实例时,才对目标字段进行下一步初始化加载。 - initializeInstance( - (Configuration) object, parent, field.getName(), - field.getAnnotation(ConfigPath.class), - field.getAnnotation(HeaderComment.class), - field.getAnnotation(InlineComment.class), - saveDefaults - ); - } else if (source instanceof Class && object instanceof Class) { - // 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。 - initializeStaticClass( - (Class) object, parent, field.getName(), - field.getAnnotation(ConfigPath.class), - field.getAnnotation(HeaderComment.class), - field.getAnnotation(InlineComment.class), - saveDefaults, loadSubClasses - ); - } - - // 以上判断实现以下规范: - // - 实例类中仅加载 ConfigValue实例 与 ConfigurationRoot实例 - // - 静态类中仅加载 静态ConfigValue实例 与 静态ConfigurationRoot类 - - } catch (IllegalAccessException ignored) { - } - } - - protected void initializeValue(@NotNull ConfigValue value, @NotNull String path, - @Nullable HeaderComment fieldHeaderComment, - @Nullable InlineComment fieldInlineComment, - boolean saveDefaults) { - value.initialize( - provider, saveDefaults, path, - readHeaderComments(fieldHeaderComment), - readInlineComments(fieldInlineComment) - ); - } - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java index fb662ed..82cc98b 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java @@ -1,17 +1,38 @@ package cc.carm.lib.configuration.source; +import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; -import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.configuration.loader.ConfigurationLoader; import cc.carm.lib.easyoptions.OptionHolder; import cc.carm.lib.easyoptions.OptionType; import org.jetbrains.annotations.NotNull; -public abstract class ConfigurationProvider

> { +public class ConfigurationProvider> { - protected @NotNull ConfigurationLoader

loader = new ConfigurationLoader<>(); - protected @NotNull ValueAdapterRegistry

adapters = new ValueAdapterRegistry<>(); - protected @NotNull OptionHolder options = new OptionHolder(); + protected final @NotNull S source; + protected final @NotNull ConfigurationLoader loader; + protected final @NotNull ValueAdapterRegistry adapters; + protected final @NotNull OptionHolder options; + public ConfigurationProvider(@NotNull S source, @NotNull ConfigurationLoader loader, + @NotNull ValueAdapterRegistry adapters, @NotNull OptionHolder options) { + this.source = source; + this.loader = loader; + this.adapters = adapters; + this.options = options; + } + + public @NotNull S source() { + return source; + } + + public void reload() throws Exception { + source().reload(); + } + + public void save() throws Exception { + source().save(); + } public OptionHolder options() { return options; @@ -25,13 +46,29 @@ public abstract class ConfigurationProvider

> options.set(option, value); } - public ConfigurationLoader

loader() { + public ValueAdapterRegistry adapters() { + return this.adapters; + } + + + public ConfigurationLoader loader() { return loader; } - public void load(Configuration configuration) { - loader().load(configuration); + public void load(Class configClass) { + try { + loader.load(this, configClass); + } catch (Exception e) { + e.printStackTrace(); + } } + public void load(@NotNull Configuration config) { + try { + loader.load(this, config); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationReader.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSection.java similarity index 53% rename from core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationReader.java rename to core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSection.java index 96b85f4..c058695 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationReader.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSection.java @@ -1,21 +1,71 @@ -package cc.carm.lib.configuration.core.source; +package cc.carm.lib.configuration.source; -import cc.carm.lib.configuration.core.function.ConfigValueParser; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigValueParser; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Unmodifiable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; -interface ConfigurationReader { +public interface ConfigurationSection { + + @NotNull + Set getKeys(boolean deep); + + @NotNull + Map getValues(boolean deep); + + void set(@NotNull String path, @Nullable Object value); + + boolean contains(@NotNull String path); + + default boolean isType(@NotNull String path, @NotNull Class typeClass) { + return typeClass.isInstance(get(path)); + } + + boolean isList(@NotNull String path); + + @Nullable List getList(@NotNull String path); + + boolean isSection(@NotNull String path); + + @Nullable + ConfigurationSection getSection(@NotNull String path); + + @Nullable Object get(@NotNull String path); + + default @Nullable T get(@NotNull String path, @NotNull Class clazz) { + return get(path, null, clazz); + } + + default @Nullable T get(@NotNull String path, @NotNull ConfigValueParser parser) { + return get(path, null, parser); + } + + @Contract("_,!null,_->!null") + default @Nullable T get(@NotNull String path, @Nullable T defaultValue, @NotNull Class clazz) { + return get(path, defaultValue, ConfigValueParser.castObject(clazz)); + } + + @Contract("_,!null,_->!null") + default @Nullable T get(@NotNull String path, @Nullable T defaultValue, + @NotNull ConfigValueParser parser) { + Object value = get(path); + if (value != null) { + try { + return parser.parse(value, defaultValue); + } catch (Exception e) { + e.printStackTrace(); + } + } + return defaultValue; + } - ConfigurationWrapper getWrapper(); default boolean isBoolean(@NotNull String path) { - return getWrapper().isType(path, Boolean.class); + return isType(path, Boolean.class); } default boolean getBoolean(@NotNull String path) { @@ -24,11 +74,11 @@ interface ConfigurationReader { @Contract("_, !null -> !null") default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) { - return getWrapper().get(path, def, ConfigValueParser.booleanValue()); + return get(path, def, ConfigValueParser.booleanValue()); } default @Nullable Boolean isByte(@NotNull String path) { - return getWrapper().isType(path, Byte.class); + return isType(path, Byte.class); } default @Nullable Byte getByte(@NotNull String path) { @@ -37,11 +87,11 @@ interface ConfigurationReader { @Contract("_, !null -> !null") default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) { - return getWrapper().get(path, def, ConfigValueParser.byteValue()); + return get(path, def, ConfigValueParser.byteValue()); } default boolean isShort(@NotNull String path) { - return getWrapper().isType(path, Short.class); + return isType(path, Short.class); } default @Nullable Short getShort(@NotNull String path) { @@ -50,12 +100,12 @@ interface ConfigurationReader { @Contract("_, !null -> !null") default @Nullable Short getShort(@NotNull String path, @Nullable Short def) { - return getWrapper().get(path, def, ConfigValueParser.shortValue()); + return get(path, def, ConfigValueParser.shortValue()); } default boolean isInt(@NotNull String path) { - return getWrapper().isType(path, Integer.class); + return isType(path, Integer.class); } default @Nullable Integer getInt(@NotNull String path) { @@ -64,12 +114,12 @@ interface ConfigurationReader { @Contract("_, !null -> !null") default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) { - return getWrapper().get(path, def, ConfigValueParser.intValue()); + return get(path, def, ConfigValueParser.intValue()); } default boolean isLong(@NotNull String path) { - return getWrapper().isType(path, Long.class); + return isType(path, Long.class); } default @Nullable Long getLong(@NotNull String path) { @@ -78,12 +128,12 @@ interface ConfigurationReader { @Contract("_, !null -> !null") default @Nullable Long getLong(@NotNull String path, @Nullable Long def) { - return getWrapper().get(path, def, ConfigValueParser.longValue()); + return get(path, def, ConfigValueParser.longValue()); } default boolean isFloat(@NotNull String path) { - return getWrapper().isType(path, Float.class); + return isType(path, Float.class); } default @Nullable Float getFloat(@NotNull String path) { @@ -92,12 +142,12 @@ interface ConfigurationReader { @Contract("_, !null -> !null") default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) { - return getWrapper().get(path, def, ConfigValueParser.floatValue()); + return get(path, def, ConfigValueParser.floatValue()); } default boolean isDouble(@NotNull String path) { - return getWrapper().isType(path, Double.class); + return isType(path, Double.class); } default @Nullable Double getDouble(@NotNull String path) { @@ -106,12 +156,12 @@ interface ConfigurationReader { @Contract("_, !null -> !null") default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) { - return getWrapper().get(path, def, ConfigValueParser.doubleValue()); + return get(path, def, ConfigValueParser.doubleValue()); } default boolean isChar(@NotNull String path) { - return getWrapper().isType(path, Boolean.class); + return isType(path, Boolean.class); } default @Nullable Character getChar(@NotNull String path) { @@ -120,12 +170,12 @@ interface ConfigurationReader { @Contract("_, !null -> !null") default @Nullable Character getChar(@NotNull String path, @Nullable Character def) { - return getWrapper().get(path, def, Character.class); + return get(path, def, Character.class); } default boolean isString(@NotNull String path) { - return getWrapper().isType(path, String.class); + return isType(path, String.class); } default @Nullable String getString(@NotNull String path) { @@ -134,61 +184,59 @@ interface ConfigurationReader { @Contract("_, !null -> !null") default @Nullable String getString(@NotNull String path, @Nullable String def) { - return getWrapper().get(path, def, String.class); + return get(path, def, String.class); } - default @NotNull List getList(@NotNull String path, @NotNull ConfigValueParser parser) { - return parseList(getWrapper().getList(path), parser); + default @NotNull List getList(@NotNull String path, @NotNull ConfigDataFunction parser) { + return parseList(getList(path), parser); } @Unmodifiable default @NotNull List getStringList(@NotNull String path) { - return getList(path, ConfigValueParser.castToString()); + return getList(path, ConfigDataFunction.castToString()); } @Unmodifiable default @NotNull List getIntegerList(@NotNull String path) { - return getList(path, ConfigValueParser.intValue()); + return getList(path, ConfigDataFunction.intValue()); } @Unmodifiable default @NotNull List getLongList(@NotNull String path) { - return getList(path, ConfigValueParser.longValue()); + return getList(path, ConfigDataFunction.longValue()); } @Unmodifiable default @NotNull List getDoubleList(@NotNull String path) { - return getList(path, ConfigValueParser.doubleValue()); + return getList(path, ConfigDataFunction.doubleValue()); } @Unmodifiable default @NotNull List getFloatList(@NotNull String path) { - return getList(path, ConfigValueParser.floatValue()); + return getList(path, ConfigDataFunction.floatValue()); } @Unmodifiable default @NotNull List getByteList(@NotNull String path) { - return getList(path, ConfigValueParser.byteValue()); + return getList(path, ConfigDataFunction.byteValue()); } @Unmodifiable default @NotNull List getCharList(@NotNull String path) { - return getList(path, ConfigValueParser.castObject(Character.class)); + return getList(path, ConfigDataFunction.castObject(Character.class)); } @Unmodifiable - static @NotNull List parseList(@Nullable List list, ConfigValueParser parser) { + static @NotNull List parseList(@Nullable List list, ConfigDataFunction parser) { if (list == null) return Collections.emptyList(); List values = new ArrayList<>(); for (Object o : list) { try { - T parsed = parser.parse(o, null); - if (parsed != null) values.add(parsed); + values.add(parser.parse(o)); } catch (Exception ignored) { } } return values; } - } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSource.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSource.java new file mode 100644 index 0000000..72723ed --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSource.java @@ -0,0 +1,41 @@ +package cc.carm.lib.configuration.source; + +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +public abstract class ConfigurationSource, O> implements ConfigurationSection { + + protected long updateMillis; + + protected ConfigurationSource(long updateMillis) { + this.updateMillis = updateMillis; + } + + public void reload() throws Exception { + onReload(); // 调用重写的Reload方法 + this.updateMillis = System.currentTimeMillis(); + } + + protected abstract S getThis(); + + public abstract void save() throws Exception; + + protected abstract void onReload() throws Exception; + + public abstract @NotNull O original(); + + @NotNull + public Set getKeys(boolean deep) { + return getValues(deep).keySet(); + } + + public long getUpdateMillis() { + return this.updateMillis; + } + + public boolean isExpired(long time) { + return getUpdateMillis() > time; + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/path/PathGenerator.java b/core/src/main/java/cc/carm/lib/configuration/source/path/PathGenerator.java deleted file mode 100644 index 19d0a6d..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/source/path/PathGenerator.java +++ /dev/null @@ -1,33 +0,0 @@ -package cc.carm.lib.configuration.source.path; - -import cc.carm.lib.configuration.source.ConfigurationProvider; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Field; - -public interface PathGenerator

> { - - @Nullable String getFieldPath(@Nullable String parentPath, @NotNull Field field); - - @Nullable String getClassPath(@Nullable String parentPath, - @NotNull Class clazz, @Nullable Field clazzField); - - /** - * Get the configuration name of the specified element. - * Use the naming convention of all lowercase and "-" links. - * - * @param name source name - * @return the final path - */ - static String covertPathName(String name) { - return name.replaceAll("[A-Z]", "-$0") // 将驼峰形转换为蛇形; - .replaceAll("-(.*)", "$1") // 若首字母也为大写,则也会被转换,需要去掉第一个横线 - .replaceAll("_-([A-Z])", "_$1") // 因为命名中可能包含 _,因此需要被特殊处理一下 - .replaceAll("([a-z])-([A-Z])", "$1_$2") // 然后将非全大写命名的内容进行转换 - .replace("-", "") // 移除掉多余的横线 - .replace("_", "-") // 将下划线替换为横线 - .toLowerCase(); // 最后转为全小写 - } - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/path/StandardPathGenerator.java b/core/src/main/java/cc/carm/lib/configuration/source/path/StandardPathGenerator.java deleted file mode 100644 index 824db53..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/source/path/StandardPathGenerator.java +++ /dev/null @@ -1,74 +0,0 @@ -package cc.carm.lib.configuration.source.path; - -import cc.carm.lib.configuration.annotation.ConfigPath; -import cc.carm.lib.configuration.source.ConfigurationProvider; -import cc.carm.lib.configuration.source.standard.ConfigurationOptions; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Field; -import java.util.function.UnaryOperator; - -public class StandardPathGenerator

> implements PathGenerator

{ - - public static > StandardPathGenerator of(T provider) { - return of(provider, PathGenerator::covertPathName); - } - - public static > StandardPathGenerator of(T provider, UnaryOperator pathConverter) { - return new StandardPathGenerator<>(provider, pathConverter); - } - - protected final P provider; - protected UnaryOperator pathConverter; - - public StandardPathGenerator(P provider, UnaryOperator pathConverter) { - this.provider = provider; - this.pathConverter = pathConverter; - } - - public @NotNull UnaryOperator getPathConverter() { - return pathConverter; - } - - public void setPathConverter(UnaryOperator pathConverter) { - this.pathConverter = pathConverter; - } - - public String covertPath(String name) { - return pathConverter.apply(name); - } - - public char pathSeparator() { - return provider.option(ConfigurationOptions.PATH_SEPARATOR); - } - - protected String link(@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() + covertPath(path); - } - - @Override - public @Nullable String getFieldPath(@Nullable String parentPath, @NotNull Field field) { - ConfigPath path = field.getAnnotation(ConfigPath.class); - if (path == null) return link(parentPath, false, field.getName()); // No annotation, use field name. - else return link(parentPath, path.root(), path.value().isEmpty() ? field.getName() : path.value()); - } - - @Override - public @Nullable String getClassPath(@Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField) { - // For standard path generator, we generate path following by: - // 1. Check if the class has a ConfigPath annotation, if so, use the root and value as the path. - // 2. If the class defined as a field, check if the field has a ConfigPath annotation, - // and use filed information. - ConfigPath clazzPath = clazz.getAnnotation(ConfigPath.class); - - if (clazzPath != null) return link(parentPath, clazzPath.root(), clazzPath.value()); - if (clazzField == null) return parentPath; // No field, return same as parent. - - ConfigPath fieldPath = clazzField.getAnnotation(ConfigPath.class); - if (fieldPath == null) return link(parentPath, false, clazzField.getName()); - else return getFieldPath(parentPath, clazzField); - } - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationMetaTypes.java b/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationMetaTypes.java deleted file mode 100644 index 90e4499..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/source/standard/ConfigurationMetaTypes.java +++ /dev/null @@ -1,12 +0,0 @@ -package cc.carm.lib.configuration.source.standard; - -import cc.carm.lib.configuration.annotation.ConfigPath; -import cc.carm.lib.easyannotation.AnnotatedMetaType; - -public interface ConfigurationMetaTypes { - - AnnotatedMetaType PATH = AnnotatedMetaType.of(ConfigPath.class, ConfigPath::value); - - AnnotatedMetaType ROOT = AnnotatedMetaType.of(ConfigPath.class, ConfigPath::root); - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java index 8b6ecd7..e2901d9 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java @@ -1,43 +1,20 @@ package cc.carm.lib.configuration.value; -import cc.carm.lib.configuration.core.builder.ConfigBuilder; -import cc.carm.lib.configuration.core.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; import java.util.Objects; import java.util.Optional; public abstract class ConfigValue extends ValueManifest { - public static @NotNull ConfigBuilder builder() { - return new ConfigBuilder(); - } +// public static @NotNull ConfigBuilder builder() { +// return new ConfigBuilder(); +// } protected ConfigValue(@NotNull ValueManifest manifest) { - super(manifest.provider, manifest.configPath, manifest.headerComments, manifest.inlineComment, manifest.defaultValue); - } - - /** - * @param provider Provider of config files {@link ConfigurationProvider} - * @param configPath Config path of this value - * @param headerComments Header comment contents - * @param inlineComments Inline comment contents - * @param defaultValue The default value - * @deprecated Please use {@link #ConfigValue(ValueManifest)} instead. - */ - @Deprecated - protected ConfigValue(@Nullable ConfigurationProvider provider, @Nullable String configPath, - @Nullable List headerComments, @Nullable String inlineComments, - @Nullable T defaultValue) { - super(provider, configPath, headerComments, inlineComments, defaultValue); - } - - public void initialize(@NotNull ConfigurationProvider provider, boolean saveDefault, @NotNull String configPath, - @Nullable List headerComments, @Nullable String inlineComments) { - this.initialize(provider, configPath, headerComments, inlineComments); - if (saveDefault) setDefault(); + super(manifest.metadata, manifest.provider, manifest.defaultSupplier); } /** @@ -53,8 +30,8 @@ public abstract class ConfigValue extends ValueManifest { * * @return 设定值或默认值 */ - public @Nullable T getOrDefault() { - return getOptional().orElse(getDefaultValue()); + public T getOrDefault() { + return optional().orElse(defaults()); } /** @@ -64,10 +41,10 @@ public abstract class ConfigValue extends ValueManifest { * @throws NullPointerException 对应数据为空时抛出 */ public @NotNull T getNotNull() { - return Objects.requireNonNull(getOrDefault(), "Value(" + configPath + ") is null."); + return Objects.requireNonNull(getOrDefault(), "Value(" + path() + ") is null."); } - public @NotNull Optional<@Nullable T> getOptional() { + public @NotNull Optional<@Nullable T> optional() { return Optional.ofNullable(get()); } @@ -94,8 +71,8 @@ public abstract class ConfigValue extends ValueManifest { * @param override 是否覆盖已设定的值 */ public void setDefault(boolean override) { - if (!override && getConfiguration().contains(getConfigPath())) return; - Optional.ofNullable(getDefaultValue()).ifPresent(this::set); + if (!override && config().contains(path())) return; + Optional.ofNullable(defaults()).ifPresent(this::set); } /** @@ -104,7 +81,7 @@ public abstract class ConfigValue extends ValueManifest { * @return 获取当前值是否为默认值。 */ public boolean isDefault() { - return Objects.equals(getDefaultValue(), get()); + return Objects.equals(defaults(), get()); } } 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 e9caa02..fb4b36d 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 @@ -1,124 +1,150 @@ package cc.carm.lib.configuration.value; -import cc.carm.lib.configuration.core.source.ConfigurationProvider; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationSource; +import cc.carm.lib.configuration.value.meta.ValueMetaList; +import cc.carm.lib.configuration.value.meta.ValueMetaType; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Unmodifiable; -import java.util.List; -import java.util.Optional; +import java.lang.reflect.Type; +import java.util.Map; +import java.util.function.Supplier; -/** - * ConfigValue Manifests. - * The basic information that describes a configuration value. - * - * @param Value type - * @author CarmJos - */ public class ValueManifest { - public static ValueManifest of(@Nullable ConfigurationProvider provider, @Nullable String configPath, - @Nullable List headerComments, @Nullable String inlineComments) { - return new ValueManifest<>(provider, configPath, headerComments, inlineComments, null); - } - - public static ValueManifest of(@Nullable ConfigurationProvider provider, @Nullable String configPath, - @Nullable List headerComments, @Nullable String inlineComments, - @Nullable V defaultValue) { - return new ValueManifest<>(provider, configPath, headerComments, inlineComments, defaultValue); - } - + protected final @NotNull Map, Object> metadata; protected @Nullable ConfigurationProvider provider; - protected @Nullable String configPath; + protected @NotNull Supplier<@Nullable T> defaultSupplier; - protected @Nullable List headerComments; - protected @Nullable String inlineComment; - - protected @Nullable T defaultValue; - - /** - * @param provider Provider of config files {@link ConfigurationProvider} - * @param configPath Config path of this value - * @param headerComments Header comment contents - * @param inlineComment Inline comment content - * @param defaultValue The default value - */ - public ValueManifest(@Nullable ConfigurationProvider provider, @Nullable String configPath, - @Nullable List headerComments, @Nullable String inlineComment, - @Nullable T defaultValue) { + public ValueManifest(@NotNull Map, Object> metadata, + @Nullable ConfigurationProvider provider, @NotNull Supplier<@Nullable T> defaultSupplier) { + this.metadata = metadata; this.provider = provider; - this.configPath = configPath; - this.headerComments = headerComments; - this.inlineComment = inlineComment; - this.defaultValue = defaultValue; + this.defaultSupplier = defaultSupplier; } - /** - * The initialize method for {@link ConfigInitializer}, which is used to initialize the value. - * - * @param provider Provider of config files {@link ConfigurationProvider} - * @param configPath Config path of this value - * @param headerComments Header comment contents - * @param inlineComment Inline comment content - */ - protected void initialize(@NotNull ConfigurationProvider provider, @NotNull String configPath, - @Nullable List headerComments, @Nullable String inlineComment) { - if (this.provider == null) this.provider = provider; - if (this.configPath == null) this.configPath = configPath; - if (this.headerComments == null) this.headerComments = headerComments; - if (this.inlineComment == null) this.inlineComment = inlineComment; - - if (getHeaderComments() != null) { - this.provider.setHeaderComment(getConfigPath(), getHeaderComments()); - } - if (getInlineComment() != null) { - this.provider.setInlineComment(getConfigPath(), getInlineComment()); - } + public @Nullable T defaults() { + return this.defaultSupplier.get(); } - public @Nullable T getDefaultValue() { - return this.defaultValue; + public void defaults(@Nullable T defaultValue) { + defaults(() -> defaultValue); } - public void setDefaultValue(@Nullable T defaultValue) { - this.defaultValue = defaultValue; + public void defaults(@NotNull Supplier<@Nullable T> defaultValue) { + this.defaultSupplier = defaultValue; } - public @NotNull ConfigurationProvider getProvider() { - return Optional.ofNullable(this.provider) - .orElseThrow(() -> new IllegalStateException("Value(" + configPath + ") does not have a provider.")); + public @NotNull ConfigurationProvider provider() { + if (this.provider != null) return this.provider; + throw new IllegalStateException("Value does not have a provider."); } - public final @NotNull ConfigurationWrapper getConfiguration() { - try { - return getProvider().getConfiguration(); - } catch (Exception ex) { - throw new IllegalStateException("Value(" + configPath + ") has not been initialized", ex); - } + public @NotNull ConfigurationSource config() { + return provider().source(); } - public @NotNull String getConfigPath() { - return Optional.ofNullable(this.configPath) - .orElseThrow(() -> new IllegalStateException("No section path provided.")); + public @NotNull String path() { + String path = getMeta(ValueMetaList.PATH); + if (path != null) return path; + else throw new IllegalStateException("No section path provided."); } protected Object getValue() { - String path = getConfigPath(); // 当未指定路径时,优先抛出异常 - return getConfiguration().get(path); + return config().get(path()); } protected void setValue(@Nullable Object value) { - getConfiguration().set(getConfigPath(), value); + config().set(path(), value); } - public @Nullable String getInlineComment() { - return inlineComment; + public Map, Object> metadata() { + return metadata; } - @Unmodifiable - public @Nullable List getHeaderComments() { - return headerComments; + /** + * Get the value of option. + * + * @param type {@link ValueMetaType} + * @param defaultValue Default value if the value of option is not set. + * @param Value type + * @return Value of option + */ + @SuppressWarnings("unchecked") + @Contract("_, !null -> !null") + public @Nullable V getMeta(@NotNull ValueMetaType type, @Nullable V defaultValue) { + return (V) metadata().getOrDefault(type, type.getDefault(this, defaultValue)); + } + + /** + * Get the value of option. + * + * @param type {@link ValueMetaType} + * @param Value type + * @return Value of option + */ + public @Nullable V getMeta(@NotNull ValueMetaType type) { + return getMeta(type, null); + } + + public boolean hasMeta(@NotNull ValueMetaType type) { + return metadata().containsKey(type) || type.hasDefaults(this); + } + + /** + * Set the value of meta, if the value is null, the meta will be removed. + *
Will only be changed in current holder. + * + * @param type {@link ValueMetaType} + * @param value Value of meta + * @param Value type + * @return Previous value of meta + */ + @SuppressWarnings("unchecked") + public @Nullable V setMeta(@NotNull ValueMetaType type, @Nullable V value) { + if (value == null || type.isDefault(this, value)) { + return (V) metadata().remove(type); + } else { + return (V) metadata().put(type, value); + } + } + + /** + * Set the value of meta, if the value is null, the meta will not be changed. + *
Will only be changed in current holder. + * + * @param type {@link ValueMetaType} + * @param value Value of meta + * @param Value type + */ + public void setMetaIfAbsent(@NotNull ValueMetaType type, @Nullable V value) { + if (value == null || type.isDefault(this, value)) { + metadata().remove(type); + } else { + metadata().putIfAbsent(type, value); + } + } + + /** + * Set the value of meta, if the value is null, the meta will not be changed. + *
Will only be changed in current holder. + * + * @param type {@link ValueMetaType} + * @param value Value of meta + * @param Value type + */ + @SuppressWarnings("unchecked") + public @Nullable V setMetaIfPresent(@NotNull ValueMetaType type, @Nullable V value) { + Object exists = metadata().get(type); + if (exists == null) return null; + + if (value == null || type.isDefault(this, value)) { + return (V) metadata().remove(type); + } else { + return (V) metadata().put(type, value); + } } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java index 92cd162..6cd50ea 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java @@ -7,8 +7,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public abstract class CachedConfigValue extends ConfigValue { - - + protected @Nullable T cachedValue; protected long parsedTime = -1; @@ -27,11 +26,11 @@ public abstract class CachedConfigValue extends ConfigValue { } public boolean isExpired() { - return this.parsedTime <= 0 || getProvider().isExpired(this.parsedTime); + return this.parsedTime <= 0 || config().isExpired(this.parsedTime); } protected final T getDefaultFirst(@Nullable T value) { - return updateCache(this.defaultValue == null ? value : this.defaultValue); + return updateCache(this.defaultSupplier == null ? value : this.defaultSupplier); } protected @Nullable T getCachedOrDefault() { @@ -41,7 +40,7 @@ public abstract class CachedConfigValue extends ConfigValue { @Contract("!null->!null") protected T getCachedOrDefault(@Nullable T emptyValue) { if (getCachedValue() != null) return getCachedValue(); - else if (getDefaultValue() != null) return getDefaultValue(); + else if (defaults() != null) return defaults(); else return emptyValue; } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java b/core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java index f45b057..e4f8c8b 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java @@ -1,214 +1,213 @@ -package cc.carm.lib.configuration.value.impl; - -import cc.carm.lib.configuration.core.builder.map.ConfigMapCreator; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.configuration.value.ValueManifest; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Unmodifiable; - -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; - -public abstract class ConfigValueMap extends CachedConfigValue> implements Map { - - public static @NotNull ConfigMapCreator builderOf(@NotNull Class keyClass, - @NotNull Class valueClass) { - return builder().asMap(keyClass, valueClass); - } - - protected final @NotNull Supplier> supplier; - - protected final @NotNull Class sourceClass; - protected final @NotNull Class keyClass; - protected final @NotNull Class valueClass; - - protected final @NotNull ConfigDataFunction keyParser; - protected final @NotNull ConfigDataFunction valueParser; - - protected final @NotNull ConfigDataFunction keySerializer; - protected final @NotNull ConfigDataFunction valueSerializer; - - - protected ConfigValueMap(@NotNull ValueManifest> manifest, @NotNull Class sourceClass, - @NotNull Supplier> mapObjSupplier, - @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, - @NotNull Class valueClass, @NotNull ConfigDataFunction valueParser, - @NotNull ConfigDataFunction keySerializer, - @NotNull ConfigDataFunction valueSerializer) { - super(manifest); - this.supplier = mapObjSupplier; - this.sourceClass = sourceClass; - this.keyClass = keyClass; - this.valueClass = valueClass; - this.keyParser = keyParser; - this.valueParser = valueParser; - this.keySerializer = keySerializer; - this.valueSerializer = valueSerializer; - } - - public @NotNull Class getSourceClass() { - return sourceClass; - } - - public @NotNull Class getKeyClass() { - return keyClass; - } - - public @NotNull Class getValueClass() { - return valueClass; - } - - public @NotNull ConfigDataFunction getKeyParser() { - return keyParser; - } - - public @NotNull ConfigDataFunction getValueParser() { - return valueParser; - } - - public @NotNull ConfigDataFunction getKeySerializer() { - return keySerializer; - } - - public @NotNull ConfigDataFunction getValueSerializer() { - return valueSerializer; - } - - public abstract S getSource(ConfigurationWrapper section, String dataKey); - - @Override - public @NotNull Map get() { - if (!isExpired()) return getCachedOrDefault(supplier.get()); - - // 已过时的数据,需要重新解析一次。 - Map map = supplier.get(); - - ConfigurationWrapper section = getConfiguration().getConfigurationSection(getConfigPath()); - if (section == null) return getDefaultFirst(map); - - Set keys = section.getKeys(false); - if (keys.isEmpty()) return getDefaultFirst(map); - - for (String dataKey : keys) { - S dataVal = getSource(section, dataKey); - if (dataVal == null) continue; - try { - K key = keyParser.parse(dataKey); - V value = valueParser.parse(dataVal); - map.put(key, value); - } catch (Exception e) { - e.printStackTrace(); - } - } - - return updateCache(map); - } - - @Override - public V get(Object key) { - return get().get(key); - } - - public V getNotNull(Object key) { - return Objects.requireNonNull(get(key)); - } - - @Override - public void set(@Nullable Map value) { - updateCache(value); - if (value == null) setValue(null); - else { - Map data = new LinkedHashMap<>(); - for (Map.Entry entry : value.entrySet()) { - try { - data.put( - keySerializer.parse(entry.getKey()), - valueSerializer.parse(entry.getValue()) - ); - } catch (Exception e) { - e.printStackTrace(); - } - } - setValue(data); - } - } - - public @NotNull T modifyValue(Function, T> function) { - Map m = get(); - T result = function.apply(m); - set(m); - return result; - } - - public @NotNull Map modifyMap(Consumer> consumer) { - Map m = get(); - consumer.accept(m); - set(m); - return m; - } - - @Override - public int size() { - return get().size(); - } - - @Override - public boolean isEmpty() { - return get().isEmpty(); - } - - @Override - public boolean containsKey(Object key) { - return get().containsKey(key); - } - - @Override - public boolean containsValue(Object value) { - return get().containsValue(value); - } - - @Nullable - @Override - public V put(K key, V value) { - return modifyValue(m -> m.put(key, value)); - } - - @Override - public V remove(Object key) { - return modifyValue(m -> m.remove(key)); - } - - @Override - public void putAll(@NotNull Map m) { - modifyMap(map -> map.putAll(m)); - } - - @Override - public void clear() { - modifyMap(Map::clear); - } - - @NotNull - @Override - public Set keySet() { - return get().keySet(); - } - - @NotNull - @Override - public Collection values() { - return get().values(); - } - - @NotNull - @Override - @Unmodifiable - public Set> entrySet() { - return get().entrySet(); - } - -} +//package cc.carm.lib.configuration.value.impl; +// +//import cc.carm.lib.configuration.builder.map.ConfigMapCreator; +//import cc.carm.lib.configuration.function.ConfigDataFunction; +//import cc.carm.lib.configuration.value.ValueManifest; +//import org.jetbrains.annotations.NotNull; +//import org.jetbrains.annotations.Nullable; +//import org.jetbrains.annotations.Unmodifiable; +// +//import java.util.*; +//import java.util.function.Consumer; +//import java.util.function.Function; +//import java.util.function.Supplier; +// +//public abstract class ConfigValueMap extends CachedConfigValue> implements Map { +// +// public static @NotNull ConfigMapCreator builderOf(@NotNull Class keyClass, +// @NotNull Class valueClass) { +// return builder().asMap(keyClass, valueClass); +// } +// +// protected final @NotNull Supplier> supplier; +// +// protected final @NotNull Class sourceClass; +// protected final @NotNull Class keyClass; +// protected final @NotNull Class valueClass; +// +// protected final @NotNull ConfigDataFunction keyParser; +// protected final @NotNull ConfigDataFunction valueParser; +// +// protected final @NotNull ConfigDataFunction keySerializer; +// protected final @NotNull ConfigDataFunction valueSerializer; +// +// +// protected ConfigValueMap(@NotNull ValueManifest> manifest, @NotNull Class sourceClass, +// @NotNull Supplier> mapObjSupplier, +// @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, +// @NotNull Class valueClass, @NotNull ConfigDataFunction valueParser, +// @NotNull ConfigDataFunction keySerializer, +// @NotNull ConfigDataFunction valueSerializer) { +// super(manifest); +// this.supplier = mapObjSupplier; +// this.sourceClass = sourceClass; +// this.keyClass = keyClass; +// this.valueClass = valueClass; +// this.keyParser = keyParser; +// this.valueParser = valueParser; +// this.keySerializer = keySerializer; +// this.valueSerializer = valueSerializer; +// } +// +// public @NotNull Class getSourceClass() { +// return sourceClass; +// } +// +// public @NotNull Class getKeyClass() { +// return keyClass; +// } +// +// public @NotNull Class getValueClass() { +// return valueClass; +// } +// +// public @NotNull ConfigDataFunction getKeyParser() { +// return keyParser; +// } +// +// public @NotNull ConfigDataFunction getValueParser() { +// return valueParser; +// } +// +// public @NotNull ConfigDataFunction getKeySerializer() { +// return keySerializer; +// } +// +// public @NotNull ConfigDataFunction getValueSerializer() { +// return valueSerializer; +// } +// +// public abstract S getSource(ConfigurationWrapper section, String dataKey); +// +// @Override +// public @NotNull Map get() { +// if (!isExpired()) return getCachedOrDefault(supplier.get()); +// +// // 已过时的数据,需要重新解析一次。 +// Map map = supplier.get(); +// +// ConfigurationWrapper section = getConfiguration().getConfigurationSection(getConfigPath()); +// if (section == null) return getDefaultFirst(map); +// +// Set keys = section.getKeys(false); +// if (keys.isEmpty()) return getDefaultFirst(map); +// +// for (String dataKey : keys) { +// S dataVal = getSource(section, dataKey); +// if (dataVal == null) continue; +// try { +// K key = keyParser.parse(dataKey); +// V value = valueParser.parse(dataVal); +// map.put(key, value); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// +// return updateCache(map); +// } +// +// @Override +// public V get(Object key) { +// return get().get(key); +// } +// +// public V getNotNull(Object key) { +// return Objects.requireNonNull(get(key)); +// } +// +// @Override +// public void set(@Nullable Map value) { +// updateCache(value); +// if (value == null) setValue(null); +// else { +// Map data = new LinkedHashMap<>(); +// for (Map.Entry entry : value.entrySet()) { +// try { +// data.put( +// keySerializer.parse(entry.getKey()), +// valueSerializer.parse(entry.getValue()) +// ); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// setValue(data); +// } +// } +// +// public @NotNull T modifyValue(Function, T> function) { +// Map m = get(); +// T result = function.apply(m); +// set(m); +// return result; +// } +// +// public @NotNull Map modifyMap(Consumer> consumer) { +// Map m = get(); +// consumer.accept(m); +// set(m); +// return m; +// } +// +// @Override +// public int size() { +// return get().size(); +// } +// +// @Override +// public boolean isEmpty() { +// return get().isEmpty(); +// } +// +// @Override +// public boolean containsKey(Object key) { +// return get().containsKey(key); +// } +// +// @Override +// public boolean containsValue(Object value) { +// return get().containsValue(value); +// } +// +// @Nullable +// @Override +// public V put(K key, V value) { +// return modifyValue(m -> m.put(key, value)); +// } +// +// @Override +// public V remove(Object key) { +// return modifyValue(m -> m.remove(key)); +// } +// +// @Override +// public void putAll(@NotNull Map m) { +// modifyMap(map -> map.putAll(m)); +// } +// +// @Override +// public void clear() { +// modifyMap(Map::clear); +// } +// +// @NotNull +// @Override +// public Set keySet() { +// return get().keySet(); +// } +// +// @NotNull +// @Override +// public Collection values() { +// return get().values(); +// } +// +// @NotNull +// @Override +// @Unmodifiable +// public Set> entrySet() { +// return get().entrySet(); +// } +// +//} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaList.java b/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaList.java new file mode 100644 index 0000000..abd0614 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaList.java @@ -0,0 +1,11 @@ +package cc.carm.lib.configuration.value.meta; + +public interface ValueMetaList { + + /** + * The value path in configuration. + * Also see {@link cc.carm.lib.configuration.option.ConfigurationOptions#PATH_SEPARATOR} + */ + ValueMetaType PATH = ValueMetaType.of(); + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaType.java b/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaType.java new file mode 100644 index 0000000..6c5d825 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaType.java @@ -0,0 +1,59 @@ +package cc.carm.lib.configuration.value.meta; + +import cc.carm.lib.configuration.value.ValueManifest; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; +import java.util.function.Supplier; + +public class ValueMetaType { + + public static ValueMetaType of() { + return of(() -> null); + } + + public static ValueMetaType of(T defaults) { + return of(() -> defaults); + } + + public static ValueMetaType of(@NotNull Supplier<@Nullable T> defaults) { + return of(v -> defaults.get()); + } + + public static ValueMetaType of(@NotNull Function, @Nullable T> defaults) { + return new ValueMetaType<>(defaults); + } + + protected Function, @Nullable T> defaultFunction; + + public ValueMetaType(@NotNull Function, @Nullable T> defaults) { + this.defaultFunction = defaults; + } + + public boolean isDefault(ValueManifest manifest, @NotNull T value) { + return value.equals(defaults(manifest)); + } + + public boolean hasDefaults(ValueManifest manifest) { + return defaults(manifest) != null; + } + + public T getDefault(ValueManifest manifest, @Nullable T suppliedValue) { + T defaults = defaults(manifest); + return defaults == null ? suppliedValue : defaults; + } + + public @Nullable T defaults(ValueManifest manifest) { + return defaultFunction.apply(manifest); + } + + public void setDefaults(Function, T> defaultFunction) { + this.defaultFunction = defaultFunction; + } + + public void setDefaults(T value) { + setDefaults((v) -> value); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java index 555d4b2..b7c9713 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java @@ -1,229 +1,229 @@ -package cc.carm.lib.configuration.value.standard; - -import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.value.ValueManifest; -import cc.carm.lib.configuration.value.impl.CachedConfigValue; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.Consumer; -import java.util.function.Function; - -public class ConfiguredList extends CachedConfigValue> implements List { - - public static @NotNull ConfigListBuilder builderOf(@NotNull Class valueClass) { - return builder().asList(valueClass); - } - - public static @NotNull ConfiguredList of(@NotNull Class valueClass, @NotNull Collection defaults) { - return builderOf(valueClass).fromObject().defaults(defaults).build(); - } - - @SafeVarargs - public static @NotNull ConfiguredList of(@NotNull Class valueClass, @NotNull V... defaults) { - return builderOf(valueClass).fromObject().defaults(defaults).build(); - } - - @SafeVarargs - @SuppressWarnings("unchecked") - public static @NotNull ConfiguredList of(@NotNull V defaultValue, @NotNull V... moreDefaults) { - Collection values = new ArrayList<>(); - values.add(defaultValue); - values.addAll(Arrays.asList(moreDefaults)); - return of((Class) defaultValue.getClass(), values); - } - - protected final @NotNull Class valueClass; - - protected final @NotNull ConfigDataFunction parser; - protected final @NotNull ConfigDataFunction serializer; - - public ConfiguredList(@NotNull ValueManifest> manifest, @NotNull Class valueClass, - @NotNull ConfigDataFunction parser, - @NotNull ConfigDataFunction serializer) { - super(manifest); - this.valueClass = valueClass; - this.parser = parser; - this.serializer = serializer; - } - - @Override - public @NotNull List get() { - if (!isExpired()) return getCachedOrDefault(new ArrayList<>()); - // Data that is outdated and needs to be parsed again. - List list = new ArrayList<>(); - List data = getConfiguration().contains(getConfigPath()) ? - getConfiguration().getList(getConfigPath()) : null; - if (data == null) return getDefaultFirst(list); - for (Object dataVal : data) { - if (dataVal == null) continue; - try { - list.add(parser.parse(dataVal)); - } catch (Exception e) { - e.printStackTrace(); - } - } - return updateCache(list); - } - - @Override - public V get(int index) { - return get().get(index); - } - - public @NotNull List copy() { - return new ArrayList<>(get()); - } - - public @NotNull T handle(Function, T> function) { - List list = get(); - T result = function.apply(list); - set(list); - return result; - } - - public @NotNull List modify(Consumer> consumer) { - List list = get(); - consumer.accept(list); - set(list); - return list; - } - - @Override - public void set(@Nullable List value) { - updateCache(value); - if (value == null) setValue(null); - else { - List data = new ArrayList<>(); - for (V val : value) { - if (val == null) continue; - try { - data.add(serializer.parse(val)); - } catch (Exception ex) { - ex.printStackTrace(); - } - } - setValue(data); - } - } - - @Override - public V set(int index, V element) { - return handle(list -> list.set(index, element)); - } - - @Override - public int size() { - return get().size(); - } - - @Override - public boolean isEmpty() { - return get().isEmpty(); - } - - @Override - public boolean contains(Object o) { - return get().contains(o); - } - - @NotNull - @Override - public Iterator iterator() { - return get().iterator(); - } - - @NotNull - @Override - public Object @NotNull [] toArray() { - return get().toArray(); - } - - @NotNull - @Override - public T @NotNull [] toArray(@NotNull T[] a) { - return get().toArray(a); - } - - @Override - public boolean containsAll(@NotNull Collection c) { - return new HashSet<>(get()).containsAll(c); - } - - @Override - public boolean add(V v) { - handle(list -> list.add(v)); - return true; - } - - @Override - public void add(int index, V element) { - modify(list -> list.add(index, element)); - } - - @Override - public boolean addAll(@NotNull Collection c) { - return handle(list -> list.addAll(c)); - } - - @Override - public boolean addAll(int index, @NotNull Collection c) { - return handle(list -> list.addAll(index, c)); - } - - @Override - public boolean remove(Object o) { - return handle(list -> list.remove(o)); - } - - @Override - public V remove(int index) { - return handle(list -> list.remove(index)); - } - - @Override - public boolean removeAll(@NotNull Collection c) { - return handle(list -> list.removeAll(c)); - } - - @Override - public boolean retainAll(@NotNull Collection c) { - return handle(list -> list.retainAll(c)); - } - - @Override - public void clear() { - modify(List::clear); - } - - @Override - public int indexOf(Object o) { - return get().indexOf(o); - } - - @Override - public int lastIndexOf(Object o) { - return get().lastIndexOf(o); - } - - @NotNull - @Override - public ListIterator listIterator() { - return get().listIterator(); - } - - @NotNull - @Override - public ListIterator listIterator(int index) { - return get().listIterator(index); - } - - @NotNull - @Override - public List subList(int fromIndex, int toIndex) { - return get().subList(fromIndex, toIndex); - } - -} +//package cc.carm.lib.configuration.value.standard; +// +//import cc.carm.lib.configuration.builder.list.ConfigListBuilder; +//import cc.carm.lib.configuration.function.ConfigDataFunction; +//import cc.carm.lib.configuration.value.ValueManifest; +//import cc.carm.lib.configuration.value.impl.CachedConfigValue; +//import org.jetbrains.annotations.NotNull; +//import org.jetbrains.annotations.Nullable; +// +//import java.util.*; +//import java.util.function.Consumer; +//import java.util.function.Function; +// +//public class ConfiguredList extends CachedConfigValue> implements List { +// +// public static @NotNull ConfigListBuilder builderOf(@NotNull Class valueClass) { +// return builder().asList(valueClass); +// } +// +// public static @NotNull ConfiguredList of(@NotNull Class valueClass, @NotNull Collection defaults) { +// return builderOf(valueClass).fromObject().defaults(defaults).build(); +// } +// +// @SafeVarargs +// public static @NotNull ConfiguredList of(@NotNull Class valueClass, @NotNull V... defaults) { +// return builderOf(valueClass).fromObject().defaults(defaults).build(); +// } +// +// @SafeVarargs +// @SuppressWarnings("unchecked") +// public static @NotNull ConfiguredList of(@NotNull V defaultValue, @NotNull V... moreDefaults) { +// Collection values = new ArrayList<>(); +// values.add(defaultValue); +// values.addAll(Arrays.asList(moreDefaults)); +// return of((Class) defaultValue.getClass(), values); +// } +// +// protected final @NotNull Class valueClass; +// +// protected final @NotNull ConfigDataFunction parser; +// protected final @NotNull ConfigDataFunction serializer; +// +// public ConfiguredList(@NotNull ValueManifest> manifest, @NotNull Class valueClass, +// @NotNull ConfigDataFunction parser, +// @NotNull ConfigDataFunction serializer) { +// super(manifest); +// this.valueClass = valueClass; +// this.parser = parser; +// this.serializer = serializer; +// } +// +// @Override +// public @NotNull List get() { +// if (!isExpired()) return getCachedOrDefault(new ArrayList<>()); +// // Data that is outdated and needs to be parsed again. +// List list = new ArrayList<>(); +// List data = getConfiguration().contains(getConfigPath()) ? +// getConfiguration().getList(getConfigPath()) : null; +// if (data == null) return getDefaultFirst(list); +// for (Object dataVal : data) { +// if (dataVal == null) continue; +// try { +// list.add(parser.parse(dataVal)); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// return updateCache(list); +// } +// +// @Override +// public V get(int index) { +// return get().get(index); +// } +// +// public @NotNull List copy() { +// return new ArrayList<>(get()); +// } +// +// public @NotNull T handle(Function, T> function) { +// List list = get(); +// T result = function.apply(list); +// set(list); +// return result; +// } +// +// public @NotNull List modify(Consumer> consumer) { +// List list = get(); +// consumer.accept(list); +// set(list); +// return list; +// } +// +// @Override +// public void set(@Nullable List value) { +// updateCache(value); +// if (value == null) setValue(null); +// else { +// List data = new ArrayList<>(); +// for (V val : value) { +// if (val == null) continue; +// try { +// data.add(serializer.parse(val)); +// } catch (Exception ex) { +// ex.printStackTrace(); +// } +// } +// setValue(data); +// } +// } +// +// @Override +// public V set(int index, V element) { +// return handle(list -> list.set(index, element)); +// } +// +// @Override +// public int size() { +// return get().size(); +// } +// +// @Override +// public boolean isEmpty() { +// return get().isEmpty(); +// } +// +// @Override +// public boolean contains(Object o) { +// return get().contains(o); +// } +// +// @NotNull +// @Override +// public Iterator iterator() { +// return get().iterator(); +// } +// +// @NotNull +// @Override +// public Object @NotNull [] toArray() { +// return get().toArray(); +// } +// +// @NotNull +// @Override +// public T @NotNull [] toArray(@NotNull T[] a) { +// return get().toArray(a); +// } +// +// @Override +// public boolean containsAll(@NotNull Collection c) { +// return new HashSet<>(get()).containsAll(c); +// } +// +// @Override +// public boolean add(V v) { +// handle(list -> list.add(v)); +// return true; +// } +// +// @Override +// public void add(int index, V element) { +// modify(list -> list.add(index, element)); +// } +// +// @Override +// public boolean addAll(@NotNull Collection c) { +// return handle(list -> list.addAll(c)); +// } +// +// @Override +// public boolean addAll(int index, @NotNull Collection c) { +// return handle(list -> list.addAll(index, c)); +// } +// +// @Override +// public boolean remove(Object o) { +// return handle(list -> list.remove(o)); +// } +// +// @Override +// public V remove(int index) { +// return handle(list -> list.remove(index)); +// } +// +// @Override +// public boolean removeAll(@NotNull Collection c) { +// return handle(list -> list.removeAll(c)); +// } +// +// @Override +// public boolean retainAll(@NotNull Collection c) { +// return handle(list -> list.retainAll(c)); +// } +// +// @Override +// public void clear() { +// modify(List::clear); +// } +// +// @Override +// public int indexOf(Object o) { +// return get().indexOf(o); +// } +// +// @Override +// public int lastIndexOf(Object o) { +// return get().lastIndexOf(o); +// } +// +// @NotNull +// @Override +// public ListIterator listIterator() { +// return get().listIterator(); +// } +// +// @NotNull +// @Override +// public ListIterator listIterator(int index) { +// return get().listIterator(index); +// } +// +// @NotNull +// @Override +// public List subList(int fromIndex, int toIndex) { +// return get().subList(fromIndex, toIndex); +// } +// +//} 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 5e4c086..1513734 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 @@ -1,28 +1,27 @@ -package cc.carm.lib.configuration.value.standard; - -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.configuration.value.ValueManifest; -import cc.carm.lib.configuration.value.impl.ConfigValueMap; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; -import java.util.function.Supplier; - -public class ConfiguredMap extends ConfigValueMap { - - public ConfiguredMap(@NotNull ValueManifest> manifest, - @NotNull Supplier> mapObjSupplier, - @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, - @NotNull Class valueClass, @NotNull ConfigDataFunction valueParser, - @NotNull ConfigDataFunction keySerializer, - @NotNull ConfigDataFunction valueSerializer) { - super(manifest, Object.class, mapObjSupplier, keyClass, keyParser, valueClass, valueParser, keySerializer, valueSerializer); - } - - @Override - public Object getSource(ConfigurationWrapper section, String dataKey) { - return section.get(dataKey); - } - -} +//package cc.carm.lib.configuration.value.standard; +// +//import cc.carm.lib.configuration.function.ConfigDataFunction; +//import cc.carm.lib.configuration.value.ValueManifest; +//import cc.carm.lib.configuration.value.impl.ConfigValueMap; +//import org.jetbrains.annotations.NotNull; +// +//import java.util.Map; +//import java.util.function.Supplier; +// +//public class ConfiguredMap extends ConfigValueMap { +// +// public ConfiguredMap(@NotNull ValueManifest> manifest, +// @NotNull Supplier> mapObjSupplier, +// @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, +// @NotNull Class valueClass, @NotNull ConfigDataFunction valueParser, +// @NotNull ConfigDataFunction keySerializer, +// @NotNull ConfigDataFunction valueSerializer) { +// super(manifest, Object.class, mapObjSupplier, keyClass, keyParser, valueClass, valueParser, keySerializer, valueSerializer); +// } +// +// @Override +// public Object getSource(ConfigurationWrapper section, String dataKey) { +// return section.get(dataKey); +// } +// +//} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java index 718de8d..2630953 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java @@ -1,97 +1,96 @@ -package cc.carm.lib.configuration.value.standard; - -import cc.carm.lib.configuration.core.builder.value.SectionValueBuilder; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.function.ConfigValueParser; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.configuration.value.ValueManifest; -import cc.carm.lib.configuration.value.impl.CachedConfigValue; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Map; - -public class ConfiguredSection extends CachedConfigValue { - - public static @NotNull SectionValueBuilder builderOf(@NotNull Class valueClass) { - return builder().asValue(valueClass).fromSection(); - } - - protected final @NotNull Class valueClass; - - protected final @NotNull ConfigValueParser, V> parser; - protected final @NotNull ConfigDataFunction> serializer; - - public ConfiguredSection(@NotNull ValueManifest manifest, @NotNull Class valueClass, - @NotNull ConfigValueParser, V> parser, - @NotNull ConfigDataFunction> serializer) { - super(manifest); - this.valueClass = valueClass; - this.parser = parser; - this.serializer = serializer; - } - - /** - * @return Value's type class - */ - public @NotNull Class getValueClass() { - return valueClass; - } - - /** - * @return Value's parser, cast value from section. - */ - public @NotNull ConfigValueParser, V> getParser() { - return parser; - } - - /** - * @return Value's serializer, serialize value to section. - */ - public @NotNull ConfigDataFunction> getSerializer() { - return serializer; - } - - /** - * @return Get the value that parsed from the configuration section. - */ - @Override - public @Nullable V get() { - if (!isExpired()) return getCachedOrDefault(); - // Data that is outdated and needs to be parsed again. - - ConfigurationWrapper section = getConfiguration().getConfigurationSection(getConfigPath()); - if (section == null) return getDefaultValue(); - - try { - // If there are no errors, update the cache and return. - return updateCache(this.parser.parse(section, this.defaultValue)); - } catch (Exception e) { - // There was a parsing error, prompted and returned the default value. - e.printStackTrace(); - return getDefaultValue(); - } - - } - - /** - * Use the specified value to update the configuration section. - * Will use {@link #getSerializer()} to serialize the value to section. - * - * @param value The value that needs to be set in the configuration. - */ - @Override - public void set(V value) { - updateCache(value); - if (value == null) setValue(null); - else { - try { - setValue(serializer.parse(value)); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - -} +//package cc.carm.lib.configuration.value.standard; +// +//import cc.carm.lib.configuration.builder.value.SectionValueBuilder; +//import cc.carm.lib.configuration.function.ConfigDataFunction; +//import cc.carm.lib.configuration.function.ConfigValueParser; +//import cc.carm.lib.configuration.value.ValueManifest; +//import cc.carm.lib.configuration.value.impl.CachedConfigValue; +//import org.jetbrains.annotations.NotNull; +//import org.jetbrains.annotations.Nullable; +// +//import java.util.Map; +// +//public class ConfiguredSection extends CachedConfigValue { +// +// public static @NotNull SectionValueBuilder builderOf(@NotNull Class valueClass) { +// return builder().asValue(valueClass).fromSection(); +// } +// +// protected final @NotNull Class valueClass; +// +// protected final @NotNull ConfigValueParser, V> parser; +// protected final @NotNull ConfigDataFunction> serializer; +// +// public ConfiguredSection(@NotNull ValueManifest manifest, @NotNull Class valueClass, +// @NotNull ConfigValueParser, V> parser, +// @NotNull ConfigDataFunction> serializer) { +// super(manifest); +// this.valueClass = valueClass; +// this.parser = parser; +// this.serializer = serializer; +// } +// +// /** +// * @return Value's type class +// */ +// public @NotNull Class getValueClass() { +// return valueClass; +// } +// +// /** +// * @return Value's parser, cast value from section. +// */ +// public @NotNull ConfigValueParser, V> getParser() { +// return parser; +// } +// +// /** +// * @return Value's serializer, serialize value to section. +// */ +// public @NotNull ConfigDataFunction> getSerializer() { +// return serializer; +// } +// +// /** +// * @return Get the value that parsed from the configuration section. +// */ +// @Override +// public @Nullable V get() { +// if (!isExpired()) return getCachedOrDefault(); +// // Data that is outdated and needs to be parsed again. +// +// ConfigurationWrapper section = getConfiguration().getConfigurationSection(getConfigPath()); +// if (section == null) return getDefaultValue(); +// +// try { +// // If there are no errors, update the cache and return. +// return updateCache(this.parser.parse(section, this.defaultValue)); +// } catch (Exception e) { +// // There was a parsing error, prompted and returned the default value. +// e.printStackTrace(); +// return getDefaultValue(); +// } +// +// } +// +// /** +// * Use the specified value to update the configuration section. +// * Will use {@link #getSerializer()} to serialize the value to section. +// * +// * @param value The value that needs to be set in the configuration. +// */ +// @Override +// public void set(V value) { +// updateCache(value); +// if (value == null) setValue(null); +// else { +// try { +// setValue(serializer.parse(value)); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// } +// } +// +// +//} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java index 4d3a35c..82434df 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java @@ -1,32 +1,31 @@ -package cc.carm.lib.configuration.value.standard; - -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.configuration.value.ValueManifest; -import cc.carm.lib.configuration.value.impl.ConfigValueMap; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; -import java.util.function.Supplier; - -public class ConfiguredSectionMap extends ConfigValueMap> { - - public ConfiguredSectionMap(@NotNull ValueManifest> manifest, - @NotNull Supplier> mapObjSupplier, - @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, - @NotNull Class valueClass, @NotNull ConfigDataFunction, V> valueParser, - @NotNull ConfigDataFunction keySerializer, - @NotNull ConfigDataFunction> valueSerializer) { - super( - manifest, ConfigurationWrapper.class, mapObjSupplier, - keyClass, keyParser, valueClass, valueParser, - keySerializer, valueSerializer.andThen(s -> (Object) s) - ); - } - - @Override - public ConfigurationWrapper getSource(ConfigurationWrapper section, String dataKey) { - return section.getConfigurationSection(dataKey); - } - -} +//package cc.carm.lib.configuration.value.standard; +// +//import cc.carm.lib.configuration.function.ConfigDataFunction; +//import cc.carm.lib.configuration.value.ValueManifest; +//import cc.carm.lib.configuration.value.impl.ConfigValueMap; +//import org.jetbrains.annotations.NotNull; +// +//import java.util.Map; +//import java.util.function.Supplier; +// +//public class ConfiguredSectionMap extends ConfigValueMap> { +// +// public ConfiguredSectionMap(@NotNull ValueManifest> manifest, +// @NotNull Supplier> mapObjSupplier, +// @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, +// @NotNull Class valueClass, @NotNull ConfigDataFunction, V> valueParser, +// @NotNull ConfigDataFunction keySerializer, +// @NotNull ConfigDataFunction> valueSerializer) { +// super( +// manifest, ConfigurationWrapper.class, mapObjSupplier, +// keyClass, keyParser, valueClass, valueParser, +// keySerializer, valueSerializer.andThen(s -> (Object) s) +// ); +// } +// +// @Override +// public ConfigurationWrapper getSource(ConfigurationWrapper section, String dataKey) { +// return section.getConfigurationSection(dataKey); +// } +// +//} 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 6b962f4..5117d26 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 @@ -1,31 +1,29 @@ package cc.carm.lib.configuration.value.standard; -import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.function.ConfigValueParser; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigValueParser; import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class ConfiguredValue extends CachedConfigValue { - public static ConfigValueBuilder builderOf(Class valueClass) { - return builder().asValue(valueClass); - } - - @SuppressWarnings("unchecked") - public static ConfiguredValue of(@NotNull V defaultValue) { - return of((Class) defaultValue.getClass(), defaultValue); - } - - public static ConfiguredValue of(Class valueClass) { - return of(valueClass, null); - } - - public static ConfiguredValue of(Class valueClass, @Nullable V defaultValue) { - return builderOf(valueClass).fromObject().defaults(defaultValue).build(); - } +// public static ConfigValueBuilder builderOf(Class valueClass) { +// return builder().asValue(valueClass); +// } +// +// @SuppressWarnings("unchecked") +// public static ConfiguredValue of(@NotNull V defaultValue) { +// return of((Class) defaultValue.getClass(), defaultValue); +// } +// +// public static ConfiguredValue of(Class valueClass) { +// return of(valueClass, null); +// } +// +// public static ConfiguredValue of(Class valueClass, @Nullable V defaultValue) { +// return builderOf(valueClass).fromObject().defaults(defaultValue).build(); +// } protected final @NotNull Class valueClass; @@ -68,14 +66,15 @@ public class ConfiguredValue extends CachedConfigValue { // Data that is outdated and needs to be parsed again. Object value = getValue(); - if (value == null) return getDefaultValue(); // 获取的值不存在,直接使用默认值。 + if (value == null) return defaults(); + try { // If there are no errors, update the cache and return. - return updateCache(this.parser.parse(value, this.defaultValue)); + return updateCache(this.parser.parse(provider(), value, defaults())); } catch (Exception e) { // There was a parsing error, prompted and returned the default value. e.printStackTrace(); - return getDefaultValue(); + return defaults(); } } diff --git a/core/src/main/old/ValueManifestv.java b/core/src/main/old/ValueManifestv.java new file mode 100644 index 0000000..eb282ce --- /dev/null +++ b/core/src/main/old/ValueManifestv.java @@ -0,0 +1,123 @@ +package cc.carm.lib.configuration.value; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; + +import java.util.List; +import java.util.Optional; + +/** + * ConfigValue Manifests. + * The basic information that describes a configuration value. + * + * @param Value type + * @author CarmJos + */ +public class ValueManifest { + + public static ValueManifest of(@Nullable ConfigurationProvider provider, @Nullable String configPath, + @Nullable List headerComments, @Nullable String inlineComments) { + return new ValueManifest<>(provider, configPath, headerComments, inlineComments, null); + } + + public static ValueManifest of(@Nullable ConfigurationProvider provider, @Nullable String configPath, + @Nullable List headerComments, @Nullable String inlineComments, + @Nullable V defaultValue) { + return new ValueManifest<>(provider, configPath, headerComments, inlineComments, defaultValue); + } + + protected @Nullable ConfigurationProvider provider; + protected @Nullable String configPath; + + protected @Nullable List headerComments; + protected @Nullable String inlineComment; + + protected @Nullable T defaultValue; + + /** + * @param provider Provider of config files {@link ConfigurationProvider} + * @param configPath Config path of this value + * @param headerComments Header comment contents + * @param inlineComment Inline comment content + * @param defaultValue The default value + */ + public ValueManifest(@Nullable ConfigurationProvider provider, @Nullable String configPath, + @Nullable List headerComments, @Nullable String inlineComment, + @Nullable T defaultValue) { + this.provider = provider; + this.configPath = configPath; + this.headerComments = headerComments; + this.inlineComment = inlineComment; + this.defaultValue = defaultValue; + } + + /** + * The initialize method for {@link ConfigInitializer}, which is used to initialize the value. + * + * @param provider Provider of config files {@link ConfigurationProvider} + * @param configPath Config path of this value + * @param headerComments Header comment contents + * @param inlineComment Inline comment content + */ + protected void initialize(@NotNull ConfigurationProvider provider, @NotNull String configPath, + @Nullable List headerComments, @Nullable String inlineComment) { + if (this.provider == null) this.provider = provider; + if (this.configPath == null) this.configPath = configPath; + if (this.headerComments == null) this.headerComments = headerComments; + if (this.inlineComment == null) this.inlineComment = inlineComment; + + if (getHeaderComments() != null) { + this.provider.setHeaderComment(getConfigPath(), getHeaderComments()); + } + if (getInlineComment() != null) { + this.provider.setInlineComment(getConfigPath(), getInlineComment()); + } + } + + public @Nullable T getDefaultValue() { + return this.defaultValue; + } + + public void setDefaultValue(@Nullable T defaultValue) { + this.defaultValue = defaultValue; + } + + public @NotNull ConfigurationProvider getProvider() { + return Optional.ofNullable(this.provider) + .orElseThrow(() -> new IllegalStateException("Value(" + configPath + ") does not have a provider.")); + } + + public final @NotNull ConfigurationWrapper getConfiguration() { + try { + return getProvider().getConfiguration(); + } catch (Exception ex) { + throw new IllegalStateException("Value(" + configPath + ") has not been initialized", ex); + } + } + + public @NotNull String getConfigPath() { + return Optional.ofNullable(this.configPath) + .orElseThrow(() -> new IllegalStateException("No section path provided.")); + } + + protected Object getValue() { + String path = getConfigPath(); // 当未指定路径时,优先抛出异常 + return getConfiguration().get(path); + } + + protected void setValue(@Nullable Object value) { + getConfiguration().set(getConfigPath(), value); + } + + public @Nullable String getInlineComment() { + return inlineComment; + } + + @Unmodifiable + public @Nullable List getHeaderComments() { + return headerComments; + } + + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java b/core/src/main/old/builder/AbstractConfigBuilder.java similarity index 94% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java rename to core/src/main/old/builder/AbstractConfigBuilder.java index dc3dd81..25429ba 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java +++ b/core/src/main/old/builder/AbstractConfigBuilder.java @@ -1,6 +1,5 @@ -package cc.carm.lib.configuration.core.builder; +package cc.carm.lib.configuration.builder; -import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ValueManifest; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/CommonConfigBuilder.java b/core/src/main/old/builder/CommonConfigBuilder.java similarity index 67% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/CommonConfigBuilder.java rename to core/src/main/old/builder/CommonConfigBuilder.java index 941fdcd..b9e26f3 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/CommonConfigBuilder.java +++ b/core/src/main/old/builder/CommonConfigBuilder.java @@ -1,6 +1,4 @@ -package cc.carm.lib.configuration.core.builder; - -import cc.carm.lib.configuration.core.source.ConfigurationProvider; +package cc.carm.lib.configuration.builder; public abstract class CommonConfigBuilder> extends AbstractConfigBuilder> { diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/ConfigBuilder.java b/core/src/main/old/builder/ConfigBuilder.java similarity index 82% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/ConfigBuilder.java rename to core/src/main/old/builder/ConfigBuilder.java index 68262df..2dd7dc0 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/ConfigBuilder.java +++ b/core/src/main/old/builder/ConfigBuilder.java @@ -1,9 +1,9 @@ -package cc.carm.lib.configuration.core.builder; +package cc.carm.lib.configuration.builder; -import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder; -import cc.carm.lib.configuration.core.builder.map.ConfigMapBuilder; -import cc.carm.lib.configuration.core.builder.map.ConfigMapCreator; -import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder; +import cc.carm.lib.configuration.builder.map.ConfigMapBuilder; +import cc.carm.lib.configuration.builder.map.ConfigMapCreator; +import cc.carm.lib.configuration.builder.list.ConfigListBuilder; +import cc.carm.lib.configuration.builder.value.ConfigValueBuilder; import org.jetbrains.annotations.NotNull; import java.util.HashMap; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/list/ConfigListBuilder.java b/core/src/main/old/builder/list/ConfigListBuilder.java similarity index 94% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/list/ConfigListBuilder.java rename to core/src/main/old/builder/list/ConfigListBuilder.java index 94e5a44..67b5210 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/list/ConfigListBuilder.java +++ b/core/src/main/old/builder/list/ConfigListBuilder.java @@ -1,6 +1,6 @@ -package cc.carm.lib.configuration.core.builder.list; +package cc.carm.lib.configuration.builder.list; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigDataFunction; import org.jetbrains.annotations.NotNull; import java.util.Map; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java b/core/src/main/old/builder/list/SourceListBuilder.java similarity index 93% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java rename to core/src/main/old/builder/list/SourceListBuilder.java index e7e4367..4173a66 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java +++ b/core/src/main/old/builder/list/SourceListBuilder.java @@ -1,7 +1,7 @@ -package cc.carm.lib.configuration.core.builder.list; +package cc.carm.lib.configuration.builder.list; -import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.builder.CommonConfigBuilder; +import cc.carm.lib.configuration.function.ConfigDataFunction; import cc.carm.lib.configuration.value.standard.ConfiguredList; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/ConfigMapBuilder.java b/core/src/main/old/builder/map/ConfigMapBuilder.java similarity index 95% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/map/ConfigMapBuilder.java rename to core/src/main/old/builder/map/ConfigMapBuilder.java index ecfa675..635dd5d 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/ConfigMapBuilder.java +++ b/core/src/main/old/builder/map/ConfigMapBuilder.java @@ -1,6 +1,6 @@ -package cc.carm.lib.configuration.core.builder.map; +package cc.carm.lib.configuration.builder.map; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigDataFunction; import org.jetbrains.annotations.NotNull; import java.util.Map; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/ConfigMapCreator.java b/core/src/main/old/builder/map/ConfigMapCreator.java similarity index 95% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/map/ConfigMapCreator.java rename to core/src/main/old/builder/map/ConfigMapCreator.java index 4b92a5b..24a8312 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/ConfigMapCreator.java +++ b/core/src/main/old/builder/map/ConfigMapCreator.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.core.builder.map; +package cc.carm.lib.configuration.builder.map; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SectionMapBuilder.java b/core/src/main/old/builder/map/SectionMapBuilder.java similarity index 93% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/map/SectionMapBuilder.java rename to core/src/main/old/builder/map/SectionMapBuilder.java index df57cf3..c5a6267 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SectionMapBuilder.java +++ b/core/src/main/old/builder/map/SectionMapBuilder.java @@ -1,8 +1,7 @@ -package cc.carm.lib.configuration.core.builder.map; +package cc.carm.lib.configuration.builder.map; -import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; +import cc.carm.lib.configuration.builder.CommonConfigBuilder; +import cc.carm.lib.configuration.function.ConfigDataFunction; import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.standard.ConfiguredSectionMap; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java b/core/src/main/old/builder/map/SourceMapBuilder.java similarity index 95% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java rename to core/src/main/old/builder/map/SourceMapBuilder.java index 034f597..4699edd 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java +++ b/core/src/main/old/builder/map/SourceMapBuilder.java @@ -1,7 +1,7 @@ -package cc.carm.lib.configuration.core.builder.map; +package cc.carm.lib.configuration.builder.map; -import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.builder.CommonConfigBuilder; +import cc.carm.lib.configuration.function.ConfigDataFunction; import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.standard.ConfiguredMap; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/ConfigValueBuilder.java b/core/src/main/old/builder/value/ConfigValueBuilder.java similarity index 90% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/value/ConfigValueBuilder.java rename to core/src/main/old/builder/value/ConfigValueBuilder.java index 58f9f35..b4db9ce 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/ConfigValueBuilder.java +++ b/core/src/main/old/builder/value/ConfigValueBuilder.java @@ -1,8 +1,7 @@ -package cc.carm.lib.configuration.core.builder.value; +package cc.carm.lib.configuration.builder.value; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.function.ConfigValueParser; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigValueParser; import org.jetbrains.annotations.NotNull; import java.util.Map; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java b/core/src/main/old/builder/value/SectionValueBuilder.java similarity index 83% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java rename to core/src/main/old/builder/value/SectionValueBuilder.java index 928860b..dbdf6de 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java +++ b/core/src/main/old/builder/value/SectionValueBuilder.java @@ -1,9 +1,8 @@ -package cc.carm.lib.configuration.core.builder.value; +package cc.carm.lib.configuration.builder.value; -import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.function.ConfigValueParser; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; +import cc.carm.lib.configuration.builder.CommonConfigBuilder; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigValueParser; import cc.carm.lib.configuration.value.standard.ConfiguredSection; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java b/core/src/main/old/builder/value/SourceValueBuilder.java similarity index 90% rename from core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java rename to core/src/main/old/builder/value/SourceValueBuilder.java index 57541fa..22c2c9a 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java +++ b/core/src/main/old/builder/value/SourceValueBuilder.java @@ -1,8 +1,8 @@ -package cc.carm.lib.configuration.core.builder.value; +package cc.carm.lib.configuration.builder.value; -import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.core.function.ConfigDataFunction; -import cc.carm.lib.configuration.core.function.ConfigValueParser; +import cc.carm.lib.configuration.builder.CommonConfigBuilder; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigValueParser; import cc.carm.lib.configuration.value.standard.ConfiguredValue; import org.jetbrains.annotations.NotNull; diff --git a/core/src/test/java/AdaptTest.java b/core/src/test/java/AdaptTest.java index b0e8d0d..e4cc97c 100644 --- a/core/src/test/java/AdaptTest.java +++ b/core/src/test/java/AdaptTest.java @@ -2,6 +2,9 @@ import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; import cc.carm.lib.configuration.adapter.strandard.EnumAdapter; import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters; import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.loader.ConfigurationLoader; +import cc.carm.lib.easyoptions.OptionHolder; +import cc.carm.test.config.TestSource; import org.junit.Test; import java.time.Duration; @@ -12,7 +15,7 @@ public class AdaptTest { @Test public void test() throws Exception { - ValueAdapterRegistry registry = new ValueAdapterRegistry<>(); + ValueAdapterRegistry registry = new ValueAdapterRegistry(); registry.register(Long.class, PrimitiveAdapters.ofLong()); registry.register(long.class, PrimitiveAdapters.ofLong()); registry.register(Integer.class, PrimitiveAdapters.ofInteger()); @@ -30,7 +33,7 @@ public class AdaptTest { registry.register(Boolean.class, PrimitiveAdapters.ofBoolean()); registry.register(boolean.class, PrimitiveAdapters.ofBoolean()); registry.register(String.class, PrimitiveAdapters.ofString()); - registry.register(new EnumAdapter<>()); + registry.register(new EnumAdapter()); registry.register(Long.class, Duration.class, Duration::ofSeconds, Duration::getSeconds); registry.register( @@ -39,7 +42,7 @@ public class AdaptTest { data -> Duration.between(LocalTime.now(), data) ); - ConfigurationProvider provider = new ConfigurationProvider(); + ConfigurationProvider provider = new ConfigurationProvider<>(new TestSource(), new ConfigurationLoader(), registry, new OptionHolder()); LocalTime v = registry.deserialize(provider, LocalTime.class, "600"); Object d = registry.serialize(provider, v); diff --git a/core/src/test/java/NameTest.java b/core/src/test/java/NameTest.java index 7a45698..d1d09a9 100644 --- a/core/src/test/java/NameTest.java +++ b/core/src/test/java/NameTest.java @@ -1,3 +1,4 @@ +import cc.carm.lib.configuration.loader.PathGenerator; import org.junit.Test; public class NameTest { @@ -6,10 +7,10 @@ public class NameTest { @Test public void onTest() { - System.out.println(ConfigInitializer.getPathFromName("LoveGames")); // -> love-games - System.out.println(ConfigInitializer.getPathFromName("EASY_GAME")); // -> easy-game - System.out.println(ConfigInitializer.getPathFromName("F")); //-? f - System.out.println(ConfigInitializer.getPathFromName("Test123123")); // -? test123123123 + System.out.println(PathGenerator.covertPathName("LoveGames")); // -> love-games + System.out.println(PathGenerator.covertPathName("EASY_GAME")); // -> easy-game + System.out.println(PathGenerator.covertPathName("F")); //-? f + System.out.println(PathGenerator.covertPathName("Test123123")); // -? test123123123 } diff --git a/core/src/test/java/cc/carm/test/config/LoaderTest.java b/core/src/test/java/cc/carm/test/config/LoaderTest.java new file mode 100644 index 0000000..aa3de0a --- /dev/null +++ b/core/src/test/java/cc/carm/test/config/LoaderTest.java @@ -0,0 +1,42 @@ +package cc.carm.test.config; + +import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; +import cc.carm.lib.configuration.annotation.ConfigPath; +import cc.carm.lib.configuration.Configuration; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.loader.ConfigurationLoader; +import cc.carm.lib.easyoptions.OptionHolder; +import org.junit.Test; + +public class LoaderTest { + + @Test + public void test() throws Exception { + ConfigurationProvider provider = new ConfigurationProvider<>(new TestSource(), new ConfigurationLoader(), new ValueAdapterRegistry(), new OptionHolder()); + + ConfigurationLoader loader = new ConfigurationLoader(); + loader.load(provider, ROOT.class); + } + + interface ROOT extends Configuration { + + interface SUB extends Configuration { + + + } + + + @ConfigPath(root = true) + interface EXTERNAL extends Configuration { + + + } + + @ConfigPath("NO") + interface YES extends Configuration { + + + } + + } +} \ No newline at end of file diff --git a/core/src/test/java/cc/carm/test/config/TestSource.java b/core/src/test/java/cc/carm/test/config/TestSource.java new file mode 100644 index 0000000..30247a3 --- /dev/null +++ b/core/src/test/java/cc/carm/test/config/TestSource.java @@ -0,0 +1,82 @@ +package cc.carm.test.config; + +import cc.carm.lib.configuration.source.ConfigurationSection; +import cc.carm.lib.configuration.source.ConfigurationSource; +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 TestSource() { + super(System.currentTimeMillis()); + } + + @Override + protected TestSource getThis() { + return this; + } + + @Override + public void save() throws Exception { + + } + + @Override + protected void onReload() throws Exception { + + } + + @Override + public @NotNull Map original() { + return null; + } + + @Override + public @NotNull Set getKeys(boolean deep) { + 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) { + return null; + } +} 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 5e662ea..f9ebe6d 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.core.Configuration; +import cc.carm.lib.configuration.source.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 10ade90..b6c18df 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 @@ -1,6 +1,5 @@ package cc.carm.lib.configuration.demo.tests; -import cc.carm.lib.configuration.core.source.ConfigurationProvider; 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; 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 6b3875e..76d30bd 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,6 +1,6 @@ package cc.carm.lib.configuration.demo.tests.conf; -import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.configuration.source.Configuration; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.annotation.InlineComment; 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 c242e4a..2f6c021 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,6 +1,6 @@ package cc.carm.lib.configuration.demo.tests.conf; -import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.configuration.source.Configuration; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.annotation.InlineComment; 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 ba61899..2d4a548 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.core.Configuration; +import cc.carm.lib.configuration.source.Configuration; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue; 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 9e53d95..9121742 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,6 +1,5 @@ package cc.carm.lib.configuration.demo.tests.model; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import org.jetbrains.annotations.NotNull; import java.util.HashMap; diff --git a/features/commentable/pom.xml b/features/commentable/pom.xml new file mode 100644 index 0000000..5aee317 --- /dev/null +++ b/features/commentable/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + cc.carm.lib + easyconfiguration-parent + 3.9.1 + ../../pom.xml + + + ${project.jdk.version} + ${project.jdk.version} + UTF-8 + UTF-8 + + + easyconfiguration-feature-commentable + jar + + + + ${project.groupId} + easyconfiguration-core + ${project.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + \ No newline at end of file diff --git a/commentable/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java b/features/commentable/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java similarity index 100% rename from commentable/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java rename to features/commentable/src/main/java/cc/carm/lib/configuration/annotation/HeaderComment.java diff --git a/commentable/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java b/features/commentable/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java similarity index 100% rename from commentable/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java rename to features/commentable/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java diff --git a/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java b/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java new file mode 100644 index 0000000..be7d8f9 --- /dev/null +++ b/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java @@ -0,0 +1,22 @@ +package cc.carm.lib.configuration.commentable; + +import cc.carm.lib.configuration.annotation.HeaderComment; +import cc.carm.lib.configuration.annotation.InlineComment; +import cc.carm.lib.configuration.value.meta.ValueMetaType; + +import java.util.Collections; +import java.util.List; + +public interface CommentableMetaTypes { + + /** + * Configuration's {@link HeaderComment} + */ + ValueMetaType> HEADER_COMMENTS = ValueMetaType.of(Collections.emptyList()); + + /** + * Configuration's {@link InlineComment} + */ + ValueMetaType INLINE_COMMENT_VALUE = ValueMetaType.of(); + +} diff --git a/commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java b/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java similarity index 100% rename from commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java rename to features/commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java diff --git a/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableOptions.java b/features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java similarity index 88% rename from commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableOptions.java rename to features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java index 7fcfc0d..3bc585b 100644 --- a/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableOptions.java +++ b/features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java @@ -1,9 +1,7 @@ -package cc.carm.lib.configuration.commentable; +package cc.carm.lib.configuration.option; import cc.carm.lib.easyoptions.OptionType; -import static cc.carm.lib.easyoptions.OptionType.of; - public interface CommentableOptions { /** diff --git a/commentable/pom.xml b/features/file/pom.xml similarity index 54% rename from commentable/pom.xml rename to features/file/pom.xml index d58cdcb..861bcb1 100644 --- a/commentable/pom.xml +++ b/features/file/pom.xml @@ -7,6 +7,7 @@ cc.carm.lib easyconfiguration-parent 3.9.1 + ../../pom.xml ${project.jdk.version} @@ -15,8 +16,8 @@ UTF-8 - easyconfiguration-commentable - + easyconfiguration-feature-file + jar @@ -26,4 +27,24 @@ + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + \ No newline at end of file diff --git a/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java b/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java new file mode 100644 index 0000000..4868651 --- /dev/null +++ b/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java @@ -0,0 +1,15 @@ +package cc.carm.lib.configuration.option; + +import cc.carm.lib.easyoptions.OptionType; + +import static cc.carm.lib.easyoptions.OptionType.of; + +public class FileConfigOptions { + + /** + * Whether to copy files from resource if exists. + */ + OptionType COPY_DEFAULTS = of(true); + + +} diff --git a/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigProvider.java b/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigProvider.java new file mode 100644 index 0000000..41bdea1 --- /dev/null +++ b/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigProvider.java @@ -0,0 +1,87 @@ +//package cc.carm.lib.configuration.core.source.impl; +// +//import org.jetbrains.annotations.NotNull; +//import org.jetbrains.annotations.Nullable; +// +//import java.io.File; +//import java.io.IOException; +//import java.io.InputStream; +//import java.io.OutputStream; +//import java.net.URL; +//import java.net.URLConnection; +//import java.nio.file.Files; +//import java.util.Objects; +// +//public abstract class FileConfigProvider> extends ConfigurationProvider { +// +// protected final @NotNull File file; +// +// protected FileConfigProvider(@NotNull File file) { +// this.file = file; +// } +// +// public @NotNull File getFile() { +// return file; +// } +// +// public void initializeFile(@Nullable String sourcePath) throws IOException { +// if (this.file.exists()) return; +// +// File parent = this.file.getParentFile(); +// if (parent != null && !parent.exists() && !parent.mkdirs()) { +// throw new IOException("Failed to create directory " + file.getParentFile().getAbsolutePath()); +// } +// +// if (!this.file.createNewFile()) { +// throw new IOException("Failed to create file " + file.getAbsolutePath()); +// } +// +// if (sourcePath != null) { +// try { +// saveResource(sourcePath, true); +// } catch (IllegalArgumentException ignored) { +// } +// } +// } +// +// public void saveResource(@NotNull String resourcePath, boolean replace) +// throws IOException, IllegalArgumentException { +// Objects.requireNonNull(resourcePath, "ResourcePath cannot be null"); +// if (resourcePath.isEmpty()) throw new IllegalArgumentException("ResourcePath cannot be empty"); +// +// resourcePath = resourcePath.replace('\\', '/'); +// +// URL url = this.getClass().getClassLoader().getResource(resourcePath); +// if (url == null) throw new IllegalArgumentException("The resource '" + resourcePath + "' not exists"); +// +// File outDir = file.getParentFile(); +// +// if (!outDir.exists() && !outDir.mkdirs()) throw new IOException("Failed to create directory " + outDir); +// if (!file.exists() || replace) { +// try (OutputStream out = Files.newOutputStream(file.toPath())) { +// URLConnection connection = url.openConnection(); +// connection.setUseCaches(false); +// try (InputStream in = connection.getInputStream()) { +// byte[] buf = new byte[1024]; +// int len; +// while ((len = in.read(buf)) > 0) { +// out.write(buf, 0, len); +// } +// } +// } +// } +// } +// +// @Nullable +// public InputStream getResource(@NotNull String filename) { +// try { +// URL url = this.getClass().getClassLoader().getResource(filename); +// if (url == null) return null; +// URLConnection connection = url.openConnection(); +// connection.setUseCaches(false); +// return connection.getInputStream(); +// } catch (IOException ex) { +// return null; +// } +// } +//} 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 new file mode 100644 index 0000000..c189461 --- /dev/null +++ b/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigSource.java @@ -0,0 +1,6 @@ +package cc.carm.lib.configuration.source; + +public class FileConfigSource { + + +} diff --git a/pom.xml b/pom.xml index 55f7c72..f2d2d0f 100644 --- a/pom.xml +++ b/pom.xml @@ -18,12 +18,14 @@ 3.9.1 core - demo - impl/yaml - impl/json - impl/sql - impl/hocon - commentable + features/commentable + features/file + + + + + + EasyConfiguration diff --git a/impl/json/README.md b/providers/gson/README.md similarity index 100% rename from impl/json/README.md rename to providers/gson/README.md diff --git a/impl/json/pom.xml b/providers/gson/pom.xml similarity index 97% rename from impl/json/pom.xml rename to providers/gson/pom.xml index 44155a5..df5abd9 100644 --- a/impl/json/pom.xml +++ b/providers/gson/pom.xml @@ -15,7 +15,7 @@ UTF-8 UTF-8 - easyconfiguration-json + easyconfiguration-gson jar diff --git a/impl/json/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java b/providers/gson/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java similarity index 100% rename from impl/json/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java rename to providers/gson/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java diff --git a/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java similarity index 97% rename from impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java rename to providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java index bbf7c80..74865ee 100644 --- a/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java @@ -1,7 +1,6 @@ package cc.carm.lib.configuration.json; import cc.carm.lib.configuration.source.comment.ConfigurationComments; -import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.source.impl.FileConfigProvider; import com.google.gson.Gson; import com.google.gson.GsonBuilder; diff --git a/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java similarity index 98% rename from impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java rename to providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java index c175c2d..5cb0f88 100644 --- a/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java @@ -1,6 +1,5 @@ package cc.carm.lib.configuration.json; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/impl/json/src/test/java/config/JSONConfigTest.java b/providers/gson/src/test/java/config/JSONConfigTest.java similarity index 100% rename from impl/json/src/test/java/config/JSONConfigTest.java rename to providers/gson/src/test/java/config/JSONConfigTest.java diff --git a/impl/hocon/README.md b/providers/hocon/README.md similarity index 100% rename from impl/hocon/README.md rename to providers/hocon/README.md diff --git a/impl/hocon/pom.xml b/providers/hocon/pom.xml similarity index 100% rename from impl/hocon/pom.xml rename to providers/hocon/pom.xml diff --git a/impl/hocon/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java b/providers/hocon/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java similarity index 100% rename from impl/hocon/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java rename to providers/hocon/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java diff --git a/impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONConfigWrapper.java b/providers/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONConfigWrapper.java similarity index 98% rename from impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONConfigWrapper.java rename to providers/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONConfigWrapper.java index 5465e23..600974e 100644 --- a/impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONConfigWrapper.java +++ b/providers/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONConfigWrapper.java @@ -1,6 +1,5 @@ package cc.carm.lib.configuration.hocon; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import cc.carm.lib.configuration.hocon.util.HOCONUtils; import com.typesafe.config.*; import org.jetbrains.annotations.NotNull; diff --git a/impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONFileConfigProvider.java b/providers/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONFileConfigProvider.java similarity index 100% rename from impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONFileConfigProvider.java rename to providers/hocon/src/main/java/cc/carm/lib/configuration/hocon/HOCONFileConfigProvider.java diff --git a/impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/exception/HOCONGetValueException.java b/providers/hocon/src/main/java/cc/carm/lib/configuration/hocon/exception/HOCONGetValueException.java similarity index 100% rename from impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/exception/HOCONGetValueException.java rename to providers/hocon/src/main/java/cc/carm/lib/configuration/hocon/exception/HOCONGetValueException.java diff --git a/impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/util/HOCONUtils.java b/providers/hocon/src/main/java/cc/carm/lib/configuration/hocon/util/HOCONUtils.java similarity index 100% rename from impl/hocon/src/main/java/cc/carm/lib/configuration/hocon/util/HOCONUtils.java rename to providers/hocon/src/main/java/cc/carm/lib/configuration/hocon/util/HOCONUtils.java diff --git a/impl/hocon/src/test/java/online/flowerinsnow/test/easyconfiguration/HOCONTest.java b/providers/hocon/src/test/java/online/flowerinsnow/test/easyconfiguration/HOCONTest.java similarity index 100% rename from impl/hocon/src/test/java/online/flowerinsnow/test/easyconfiguration/HOCONTest.java rename to providers/hocon/src/test/java/online/flowerinsnow/test/easyconfiguration/HOCONTest.java diff --git a/impl/sql/README.md b/providers/sql/README.md similarity index 100% rename from impl/sql/README.md rename to providers/sql/README.md diff --git a/impl/sql/pom.xml b/providers/sql/pom.xml similarity index 100% rename from impl/sql/pom.xml rename to providers/sql/pom.xml diff --git a/impl/sql/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java b/providers/sql/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java similarity index 100% rename from impl/sql/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java rename to providers/sql/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java diff --git a/impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java b/providers/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java similarity index 98% rename from impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java rename to providers/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java index e896060..e2f4ea3 100644 --- a/impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java +++ b/providers/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigProvider.java @@ -1,7 +1,6 @@ package cc.carm.lib.configuration.sql; import cc.carm.lib.configuration.source.comment.ConfigurationComments; -import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.easysql.api.SQLManager; import cc.carm.lib.easysql.api.SQLQuery; import cc.carm.lib.easysql.api.SQLTable; diff --git a/impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigWrapper.java b/providers/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigWrapper.java similarity index 98% rename from impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigWrapper.java rename to providers/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigWrapper.java index a817b68..060268d 100644 --- a/impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigWrapper.java +++ b/providers/sql/src/main/java/cc/carm/lib/configuration/sql/SQLConfigWrapper.java @@ -1,6 +1,5 @@ package cc.carm.lib.configuration.sql; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLValueResolver.java b/providers/sql/src/main/java/cc/carm/lib/configuration/sql/SQLValueResolver.java similarity index 100% rename from impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLValueResolver.java rename to providers/sql/src/main/java/cc/carm/lib/configuration/sql/SQLValueResolver.java diff --git a/impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLValueTypes.java b/providers/sql/src/main/java/cc/carm/lib/configuration/sql/SQLValueTypes.java similarity index 100% rename from impl/sql/src/main/java/cc/carm/lib/configuration/sql/SQLValueTypes.java rename to providers/sql/src/main/java/cc/carm/lib/configuration/sql/SQLValueTypes.java diff --git a/impl/sql/src/test/java/config/SQLConfigTest.java b/providers/sql/src/test/java/config/SQLConfigTest.java similarity index 100% rename from impl/sql/src/test/java/config/SQLConfigTest.java rename to providers/sql/src/test/java/config/SQLConfigTest.java diff --git a/impl/sql/src/test/resources/log4j2.xml b/providers/sql/src/test/resources/log4j2.xml similarity index 100% rename from impl/sql/src/test/resources/log4j2.xml rename to providers/sql/src/test/resources/log4j2.xml diff --git a/impl/yaml/README.md b/providers/yaml/README.md similarity index 100% rename from impl/yaml/README.md rename to providers/yaml/README.md diff --git a/impl/yaml/pom.xml b/providers/yaml/pom.xml similarity index 100% rename from impl/yaml/pom.xml rename to providers/yaml/pom.xml diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java similarity index 100% rename from impl/yaml/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java rename to providers/yaml/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java similarity index 100% rename from impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java rename to providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java similarity index 97% rename from impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java rename to providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java index 2610273..e2c8ca8 100644 --- a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java +++ b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java @@ -1,6 +1,5 @@ package cc.carm.lib.configuration.yaml; -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import org.bspfsystems.yamlconfiguration.configuration.ConfigurationSection; import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; import org.jetbrains.annotations.Contract; diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java similarity index 93% rename from impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java rename to providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java index 5e16ff3..fec8efd 100644 --- a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java +++ b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java @@ -1,6 +1,5 @@ package cc.carm.lib.configuration.yaml; -import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.impl.CachedConfigValue; import cc.carm.lib.configuration.yaml.builder.YAMLConfigBuilder; diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/AbstractYAMLBuilder.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/AbstractYAMLBuilder.java similarity index 100% rename from impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/AbstractYAMLBuilder.java rename to providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/AbstractYAMLBuilder.java diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/YAMLConfigBuilder.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/YAMLConfigBuilder.java similarity index 100% rename from impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/YAMLConfigBuilder.java rename to providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/YAMLConfigBuilder.java diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java similarity index 100% rename from impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java rename to providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java similarity index 100% rename from impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java rename to providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java diff --git a/impl/yaml/src/test/java/config/DemoConfigTest.java b/providers/yaml/src/test/java/config/DemoConfigTest.java similarity index 100% rename from impl/yaml/src/test/java/config/DemoConfigTest.java rename to providers/yaml/src/test/java/config/DemoConfigTest.java diff --git a/impl/yaml/src/test/java/config/model/AnyModel.java b/providers/yaml/src/test/java/config/model/AnyModel.java similarity index 100% rename from impl/yaml/src/test/java/config/model/AnyModel.java rename to providers/yaml/src/test/java/config/model/AnyModel.java diff --git a/impl/yaml/src/test/java/config/model/SomeModel.java b/providers/yaml/src/test/java/config/model/SomeModel.java similarity index 100% rename from impl/yaml/src/test/java/config/model/SomeModel.java rename to providers/yaml/src/test/java/config/model/SomeModel.java diff --git a/impl/yaml/src/test/java/config/source/ModelConfiguration.java b/providers/yaml/src/test/java/config/source/ModelConfiguration.java similarity index 97% rename from impl/yaml/src/test/java/config/source/ModelConfiguration.java rename to providers/yaml/src/test/java/config/source/ModelConfiguration.java index 021c6a3..14dfdf9 100644 --- a/impl/yaml/src/test/java/config/source/ModelConfiguration.java +++ b/providers/yaml/src/test/java/config/source/ModelConfiguration.java @@ -1,6 +1,6 @@ package config.source; -import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.configuration.source.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/impl/yaml/src/test/java/sample/Sample.java b/providers/yaml/src/test/java/sample/Sample.java similarity index 89% rename from impl/yaml/src/test/java/sample/Sample.java rename to providers/yaml/src/test/java/sample/Sample.java index caaa989..83a9b7c 100644 --- a/impl/yaml/src/test/java/sample/Sample.java +++ b/providers/yaml/src/test/java/sample/Sample.java @@ -1,7 +1,6 @@ package sample; import cc.carm.lib.configuration.EasyConfiguration; -import cc.carm.lib.configuration.core.source.ConfigurationProvider; public class Sample { diff --git a/impl/yaml/src/test/java/sample/SampleConfig.java b/providers/yaml/src/test/java/sample/SampleConfig.java similarity index 95% rename from impl/yaml/src/test/java/sample/SampleConfig.java rename to providers/yaml/src/test/java/sample/SampleConfig.java index 7b71a42..d8b53d1 100644 --- a/impl/yaml/src/test/java/sample/SampleConfig.java +++ b/providers/yaml/src/test/java/sample/SampleConfig.java @@ -1,6 +1,6 @@ package sample; -import cc.carm.lib.configuration.core.Configuration; +import cc.carm.lib.configuration.source.Configuration; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.annotation.InlineComment; diff --git a/impl/yaml/src/test/resources/test/test2/config.yml b/providers/yaml/src/test/resources/test/test2/config.yml similarity index 100% rename from impl/yaml/src/test/resources/test/test2/config.yml rename to providers/yaml/src/test/resources/test/test2/config.yml From 374a6198d8af6a2629a0f8d82b62bd8ea738154a Mon Sep 17 00:00:00 2001 From: Carm Date: Sun, 2 Feb 2025 22:29:18 +0800 Subject: [PATCH 07/17] feat!(value): Redesigned the Configuration api --- core/pom.xml | 8 - .../carm/lib/configuration/Configuration.java | 6 +- .../configuration/adapter/ValueAdapter.java | 73 ++- .../adapter/ValueAdapterRegistry.java | 148 +++--- .../adapter/ValueDeserializer.java | 17 - .../configuration/adapter/ValueParser.java | 19 + .../adapter/ValueSerializer.java | 10 +- .../lib/configuration/adapter/ValueType.java | 150 ++++++ .../adapter/strandard/EnumAdapter.java | 29 -- .../adapter/strandard/PrimitiveAdapters.java | 71 ++- .../adapter/strandard/StandardAdapters.java | 19 + .../configuration/annotation/ConfigPath.java | 2 +- .../builder/AbstractConfigBuilder.java | 51 ++ .../builder/CommonConfigBuilder.java | 12 + .../builder/value/ConfigValueBuilder.java | 78 +++ .../builder/value/SectionValueBuilder.java | 81 +++ .../builder/value/SourceValueBuilder.java | 68 +++ .../function/ConfigDataFunction.java | 4 +- .../function/ConfigValueHandler.java | 67 +++ .../function/ConfigValueParser.java | 62 --- .../lib/configuration/meta/PathMetadata.java | 58 +++ .../option/ConfigurationOptions.java | 25 - .../source/ConfigurationFactory.java | 77 ++- .../source/ConfigurationProvider.java | 140 +++++- .../loader/ConfigurationLoader.java | 48 +- .../{ => source}/loader/PathGenerator.java | 2 +- .../loader/StandardPathGenerator.java | 4 +- .../source/option/ConfigurationOption.java | 46 ++ .../option/ConfigurationOptionHolder.java | 70 +++ .../source/option/ConfigurationOptions.java | 33 ++ .../{ => section}/ConfigurationSection.java | 31 +- .../{ => section}/ConfigurationSource.java | 25 +- .../lib/configuration/value/ConfigValue.java | 8 +- .../configuration/value/ValueManifest.java | 151 ++---- .../value/impl/CachedConfigValue.java | 15 +- .../value/impl/ConfigValueMap.java | 213 -------- .../value/meta/ValueMetaList.java | 11 - .../value/meta/ValueMetaType.java | 59 --- .../value/standard/ConfiguredList.java | 460 +++++++++--------- .../value/standard/ConfiguredMap.java | 27 - .../value/standard/ConfiguredSection.java | 96 ---- .../value/standard/ConfiguredSectionMap.java | 31 -- .../value/standard/ConfiguredValue.java | 122 +++-- core/src/main/old/ValueManifestv.java | 123 ----- .../old/builder/AbstractConfigBuilder.java | 10 +- core/src/main/old/builder/ConfigBuilder.java | 43 -- .../builder/value/SectionValueBuilder.java | 1 - core/src/test/java/AdaptTest.java | 45 +- core/src/test/java/NameTest.java | 2 +- .../java/cc/carm/test/config/LoaderTest.java | 8 +- .../java/cc/carm/test/config/TestSource.java | 6 +- .../commentable/CommentableMetaTypes.java | 6 +- .../option/CommentableOptions.java | 6 +- .../option/FileConfigOptions.java | 7 +- .../configuration/source/FileProvider.java | 21 + pom.xml | 2 +- providers/gson/pom.xml | 7 + .../configuration/yaml/YAMLConfigSource.java | 4 + 58 files changed, 1635 insertions(+), 1383 deletions(-) delete mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/ValueType.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/adapter/strandard/StandardAdapters.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/builder/value/ConfigValueBuilder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/builder/value/SectionValueBuilder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/function/ConfigValueHandler.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/function/ConfigValueParser.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/meta/PathMetadata.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/option/ConfigurationOptions.java rename core/src/main/java/cc/carm/lib/configuration/{ => source}/loader/ConfigurationLoader.java (72%) rename core/src/main/java/cc/carm/lib/configuration/{ => source}/loader/PathGenerator.java (97%) rename core/src/main/java/cc/carm/lib/configuration/{ => source}/loader/StandardPathGenerator.java (96%) create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOption.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptionHolder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptions.java rename core/src/main/java/cc/carm/lib/configuration/source/{ => section}/ConfigurationSection.java (87%) rename core/src/main/java/cc/carm/lib/configuration/source/{ => section}/ConfigurationSource.java (54%) delete mode 100644 core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaList.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaType.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java delete mode 100644 core/src/main/old/ValueManifestv.java delete mode 100644 core/src/main/old/builder/ConfigBuilder.java create mode 100644 features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java create mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigSource.java diff --git a/core/pom.xml b/core/pom.xml index 4a285d5..5f9a61e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -18,14 +18,6 @@ easyconfiguration-core jar - - - cc.carm.lib - easyoptions - 1.1.0 - - - diff --git a/core/src/main/java/cc/carm/lib/configuration/Configuration.java b/core/src/main/java/cc/carm/lib/configuration/Configuration.java index 3596cf7..26a52a1 100644 --- a/core/src/main/java/cc/carm/lib/configuration/Configuration.java +++ b/core/src/main/java/cc/carm/lib/configuration/Configuration.java @@ -2,8 +2,6 @@ package cc.carm.lib.configuration; /** * The root interface of the configuration file interfaces, - * which is used to label and record the configuration information. + * which is used to label a class as a configuration. */ -public interface Configuration { - -} +public interface Configuration { } \ No newline at end of file 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 deeb81d..6fe33a3 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 @@ -1,52 +1,77 @@ package cc.carm.lib.configuration.adapter; import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; /** * Value adapter, used to convert the value of the configuration file into the objects. * - * @param The type of the base data - * @param The type of the target value + * @param The type of the target value */ -public abstract class ValueAdapter implements ValueSerializer, ValueDeserializer { +public class ValueAdapter + implements ValueSerializer, ValueParser { - protected final Class baseType; - protected final Class valueType; + protected final @NotNull ValueType type; + protected @Nullable ValueSerializer serializer; + protected @Nullable ValueParser deserializer; - protected ValueAdapter(Class baseType, Class valueType) { - this.baseType = baseType; - this.valueType = valueType; + public ValueAdapter(@NotNull ValueType type) { + this(type, null, null); } - public Class getBaseClass() { - return baseType; + public ValueAdapter(@NotNull ValueType type, + @Nullable ValueSerializer serializer, + @Nullable ValueParser deserializer) { + this.type = type; + this.serializer = serializer; + this.deserializer = deserializer; } - public Class getValueClass() { - return valueType; + public @NotNull ValueType type() { + return type; } - public boolean isAdaptedFrom(Class clazz) { - return clazz.isAssignableFrom(valueType); + public @Nullable ValueSerializer serializer() { + return serializer; } - public boolean isAdaptedFrom(Object object) { - return isAdaptedFrom(object.getClass()); + public @Nullable ValueParser deserializer() { + return deserializer; } - public boolean isAdaptedTo(Class clazz) { - return clazz == valueType; + public void serializer(@Nullable ValueSerializer serializer) { + this.serializer = serializer; } - @SuppressWarnings("unchecked") - protected final V deserializeObject(ConfigurationProvider provider, Class valueClass, Object data) throws Exception { - return deserialize(provider, (Class) valueClass, (B) data); + public void deserializer(@Nullable ValueParser deserializer) { + this.deserializer = deserializer; } - @SuppressWarnings("unchecked") - protected final B serializeObject(ConfigurationProvider provider, Object value) throws Exception { - return serialize(provider, (V) value); + @Override + public Object serialize(@NotNull ConfigurationProvider provider, @NotNull ValueType type, @NotNull TYPE value) throws Exception { + if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported"); + return serializer.serialize(provider, type, value); } + @Override + public TYPE deserialize(@NotNull ConfigurationProvider provider, @NotNull ValueType type, @NotNull Object value) throws Exception { + if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported"); + return deserializer.deserialize(provider, type, value); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ValueAdapter)) return false; + ValueAdapter that = (ValueAdapter) o; + return Objects.equals(type, that.type); + } + + @Override + public int hashCode() { + return Objects.hashCode(type); + } } 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 3216c79..3bb7e67 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 @@ -1,91 +1,125 @@ package cc.carm.lib.configuration.adapter; -import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters; import cc.carm.lib.configuration.function.ConfigDataFunction; import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.HashMap; -import java.util.Map; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; public class ValueAdapterRegistry { - protected final Map, ValueAdapter> adapters = new HashMap<>(); + protected final Set> adapters = new HashSet<>(); - public void register(@NotNull ValueAdapter adapter) { - adapters.put(adapter.getValueClass(), adapter); + public void register(@NotNull Class from, @NotNull Class to, + @Nullable ConfigDataFunction parser, + @Nullable ConfigDataFunction serializer) { + register(ValueType.of(from), ValueType.of(to), parser, serializer); } - public void register(Class clazz, @NotNull ValueAdapter adapter) { - adapters.put(clazz, adapter); + public void register(@NotNull ValueType from, @NotNull ValueType to, + @Nullable ConfigDataFunction parser, + @Nullable ConfigDataFunction serializer) { + ValueAdapter fromAdapter = adapterOf(from); + if (fromAdapter == null) throw new IllegalArgumentException("No adapter for type " + from); + register(to, + serializer == null ? null : (provider, type, value) -> fromAdapter.serialize(provider, from, serializer.handle(value)), + parser == null ? null : (provider, type, data) -> parser.handle(fromAdapter.deserialize(provider, from, data)) + ); } - public void register(Class baseClass, Class valueClass, - ConfigDataFunction parser, - ConfigDataFunction serializer) { - register(new ValueAdapter(baseClass, valueClass) { - @Override - public B serialize(@NotNull ConfigurationProvider provider, @NotNull V value) throws Exception { - return serializer.parse(value); - } - - @Override - public V deserialize(@NotNull ConfigurationProvider provider, @NotNull Class clazz, @NotNull B data) throws Exception { - return parser.parse(data); - } - }); + public void register(@NotNull ValueAdapter... adapter) { + adapters.addAll(Arrays.asList(adapter)); } - public void unregister(@NotNull Class typeClass) { - adapters.remove(typeClass); + public void register(@NotNull Class type, @NotNull ValueSerializer serializer) { + register(ValueType.of(type), serializer); + } + + public void register(@NotNull ValueType type, @NotNull ValueSerializer serializer) { + ValueAdapter existing = adapterOf(type); + if (existing != null) { + existing.serializer(serializer); + } else { + register(new ValueAdapter<>(type, serializer, null)); + } + } + + public void register(@NotNull Class type, @NotNull ValueParser deserializer) { + register(ValueType.of(type), deserializer); + } + + public void register(@NotNull ValueType type, @NotNull ValueParser deserializer) { + ValueAdapter existing = adapterOf(type); + if (existing != null) { + existing.deserializer(deserializer); + } else { + register(new ValueAdapter<>(type, null, deserializer)); + } + } + + public void register(@NotNull ValueType type, @Nullable ValueSerializer serializer, @Nullable ValueParser deserializer) { + if (serializer == null && deserializer == null) return; + ValueAdapter existing = adapterOf(type); + if (existing != null) { + if (serializer != null) existing.serializer(serializer); + if (deserializer != null) existing.deserializer(deserializer); + } else { + register(new ValueAdapter<>(type, serializer, deserializer)); + } + } + + public void unregister(@NotNull Class type) { + unregister(ValueType.of(type)); + } + + public void unregister(@NotNull ValueType type) { + adapters.removeIf(adapter -> adapter.type().equals(type)); } @SuppressWarnings("unchecked") + public ValueAdapter adapterOf(@NotNull ValueType type) { + ValueAdapter matched = adapters.stream().filter(adapter -> adapter.type().equals(type)).findFirst().orElse(null); + if (matched != null) return (ValueAdapter) matched; + + // If no adapter found, try to find the adapter for the super type + return (ValueAdapter) adapters.stream() + .filter(adapter -> adapter.type().isSubtypeOf(type)) + .findFirst().orElse(null); + } + + public ValueAdapter adapterOf(@NotNull T value) { + return adapterOf(ValueType.of(value)); + } + + public ValueAdapter adapterOf(@NotNull Class type) { + return adapterOf(ValueType.of(type)); + } + @Contract("_,_,null -> null") public T deserialize(@NotNull ConfigurationProvider provider, @NotNull Class type, @Nullable Object source) throws Exception { + return deserialize(provider, ValueType.of(type), source); + } + + @Contract("_,_,null -> null") + public T deserialize(@NotNull ConfigurationProvider provider, @NotNull ValueType type, @Nullable Object source) throws Exception { if (source == null) return null; // Null check if (type.isInstance(source)) return type.cast(source); // Not required to deserialize - - ValueAdapter adapter = getAdapter(type); - if (adapter == null) throw new RuntimeException("No adapter for type " + type.getName()); - - // Check if value is adapted from given value's type - if (adapter.isAdaptedFrom(source)) { - return (T) adapter.deserializeObject(provider, type, source); - } - - // Otherwise, we need to deserialize one by one. - Object baseValue = deserialize(provider, adapter.getBaseClass(), source); - if (baseValue == null) return null; // Null check - - return (T) adapter.deserializeObject(provider, type, baseValue); + ValueAdapter adapter = adapterOf(type); + if (adapter == null) throw new RuntimeException("No adapter for type " + type); + return adapter.deserialize(provider, type, source); } @Contract("_,null -> null") public Object serialize(@NotNull ConfigurationProvider provider, @Nullable T value) throws Exception { if (value == null) return null; // Null check - - ValueAdapter adapter = getAdapter(value.getClass()); + ValueType type = ValueType.of(value); + ValueAdapter adapter = adapterOf(type); if (adapter == null) return value; // No adapters, try to return the original value - - if (adapter instanceof PrimitiveAdapters) { - // If the value is adapted from a primitive type, - // we should serialize it into object, then return. - return adapter.serializeObject(provider, value); - } - - // Otherwise, we need to serialize one by one. - return serialize(provider, adapter.serializeObject(provider, value)); - } - - public ValueAdapter getAdapter(Class clazz) { - return adapters.getOrDefault(clazz, findAdapter(clazz)); - } - - public ValueAdapter findAdapter(Class clazz) { - return adapters.values().stream().filter(adapter -> adapter.isAdaptedTo(clazz)).findFirst().orElse(null); + return adapter.serialize(provider, type, value); } diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java deleted file mode 100644 index 2f63ebb..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueDeserializer.java +++ /dev/null @@ -1,17 +0,0 @@ -package cc.carm.lib.configuration.adapter; - -import cc.carm.lib.configuration.source.ConfigurationProvider; -import org.jetbrains.annotations.NotNull; - -/** - * Value deserializer, convert base data to target value. - * - * @param The type of base data - * @param The type of target value - */ -@FunctionalInterface -public interface ValueDeserializer { - - V deserialize(@NotNull ConfigurationProvider provider, @NotNull Class clazz, @NotNull B data) throws Exception; - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java new file mode 100644 index 0000000..b35b089 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java @@ -0,0 +1,19 @@ +package cc.carm.lib.configuration.adapter; + +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; + +/** + * Value deserializer, convert base data to target value. + * + * @param The type of target value + */ +@FunctionalInterface +public interface ValueParser { + + TYPE deserialize( + @NotNull ConfigurationProvider provider, + @NotNull ValueType type, @NotNull Object data + ) throws Exception; + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java index d27e8c9..44db8a9 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java @@ -6,12 +6,14 @@ import org.jetbrains.annotations.NotNull; /** * Value serializer, convert target value to base data. * - * @param The type of base data - * @param The type of value + * @param The type of value */ @FunctionalInterface -public interface ValueSerializer { +public interface ValueSerializer { - B serialize(@NotNull ConfigurationProvider provider, @NotNull V value) throws Exception; + Object serialize( + @NotNull ConfigurationProvider provider, + @NotNull ValueType type, @NotNull TYPE value + ) throws Exception; } 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 new file mode 100644 index 0000000..ca2edaf --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueType.java @@ -0,0 +1,150 @@ +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; + +/** + * Used to get the generic type. + */ +public abstract class ValueType { + + @SuppressWarnings("unchecked") + public static ValueType of(@NotNull T value) { + return of((Class) value.getClass()); + } + + public static ValueType of(final Type type) { + return new ValueType(type) { + }; + } + + public static ValueType of(final Class clazz) { + return of((Type) clazz); + } + + /** + * Get the generic type of the complex type. + * + * @param rawType The raw type + * @param types The type arguments + * @param The type + * @return The {@link ValueType} + */ + public static ValueType of(final Class rawType, final Type... types) { + ParameterizedType parameterizedType = new ParameterizedType() { + @Override + public @NotNull Type @NotNull [] getActualTypeArguments() { + return types; + } + + @Override + public @NotNull Type getRawType() { + return rawType; + } + + @Override + public Type getOwnerType() { + return null; + } + }; + return of(parameterizedType); + } + + private final Type type; + + protected ValueType() { + this.type = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + } + + private ValueType(Type type) { + this.type = type; + } + + public Type getType() { + return type; + } + + public boolean isSubtypeOf(Class target) { + Class rawType = getRawType(); + return target.isAssignableFrom(rawType); + } + + public boolean isSubtypeOf(ValueType target) { + return target.isSubtypeOf(getRawType()); + } + + public boolean isInstance(Object obj) { + return obj != null && getRawType().isInstance(obj); + } + + + /** + * 提取当前 ValueType 的原始类型(Class 对象)。 + * + * @return 对应的 Class 对象 + * @throws IllegalStateException 如果无法提取出原始类型 + */ + public Class getRawType() { + if (type instanceof Class) { + return (Class) type; + } + if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) type; + Type raw = pt.getRawType(); + if (raw instanceof Class) { + return (Class) raw; + } + } + throw new IllegalStateException("Unsupported type: " + type); + } + + @SuppressWarnings("unchecked") + public T cast(Object obj) { + if (!isInstance(obj)) { + throw new ClassCastException("Cannot cast object " + obj + " to type " + this); + } + return (T) obj; + } + + @Override + public String toString() { + if (type instanceof Class) { + return ((Class) type).getName(); + } + if (type instanceof ParameterizedType) { + ParameterizedType pt = (ParameterizedType) type; + Type raw = pt.getRawType(); + StringBuilder sb = new StringBuilder(); + sb.append(raw.getTypeName()); + sb.append('<'); + Type[] args = pt.getActualTypeArguments(); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(args[i].getTypeName()); + } + return sb.toString(); + } + return type.getTypeName(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj instanceof ValueType) { + return Objects.equals(type, ((ValueType) obj).type); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(type); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java deleted file mode 100644 index ee4a3a4..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/EnumAdapter.java +++ /dev/null @@ -1,29 +0,0 @@ -package cc.carm.lib.configuration.adapter.strandard; - -import cc.carm.lib.configuration.adapter.ValueAdapter; -import cc.carm.lib.configuration.source.ConfigurationProvider; -import org.jetbrains.annotations.NotNull; - -@SuppressWarnings({"unchecked", "rawtypes"}) -public class EnumAdapter extends ValueAdapter { - - public EnumAdapter() { - super(String.class, Enum.class); - } - - @Override - public String serialize(@NotNull ConfigurationProvider provider, @NotNull Enum value) throws Exception { - return value.name(); - } - - @Override - public Enum deserialize(@NotNull ConfigurationProvider provider, @NotNull Class clazz, @NotNull String data) throws Exception { - return Enum.valueOf(clazz, data); - } - - @Override - public boolean isAdaptedTo(Class clazz) { - return clazz.isEnum(); - } - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java index 5a36a73..f522bed 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java @@ -1,11 +1,27 @@ package cc.carm.lib.configuration.adapter.strandard; import cc.carm.lib.configuration.adapter.ValueAdapter; +import cc.carm.lib.configuration.adapter.ValueParser; +import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.NotNull; -public abstract class PrimitiveAdapters extends ValueAdapter { +public class PrimitiveAdapters extends ValueAdapter { + + public static final PrimitiveAdapters[] ADAPTERS = new PrimitiveAdapters[]{ + ofString(), ofBoolean(), ofBooleanType(), ofCharacter(), ofCharacterType(), + ofInteger(), ofIntegerType(), ofLong(), ofLongType(), ofDouble(), ofDoubleType(), + ofFloat(), ofFloatType(), ofShort(), ofShortType(), ofByte(), ofByteType() + }; + + @SuppressWarnings({"unchecked", "rawtypes"}) + public static ValueAdapter> ofEnum() { + ValueAdapter> adapter = new ValueAdapter<>(new ValueType>() { + }); + adapter.deserializer((provider, type, data) -> Enum.valueOf((Class) type.getRawType(), data.toString())); + adapter.serializer((provider, type, value) -> value.name()); + return adapter; + } public static PrimitiveAdapters ofString() { return of(String.class, o -> o instanceof String ? (String) o : o.toString()); @@ -15,56 +31,79 @@ public abstract class PrimitiveAdapters extends ValueAdapter { return of(Boolean.class, o -> o instanceof Boolean ? (Boolean) o : Boolean.parseBoolean(o.toString())); } + public static PrimitiveAdapters ofBooleanType() { + return of(boolean.class, o -> o instanceof Boolean ? (Boolean) o : Boolean.parseBoolean(o.toString())); + } + public static PrimitiveAdapters ofCharacter() { return of(Character.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0)); } + public static PrimitiveAdapters ofCharacterType() { + return of(char.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0)); + } + public static PrimitiveAdapters ofInteger() { return ofNumber(Integer.class, Number::intValue, Integer::parseInt); } + public static PrimitiveAdapters ofIntegerType() { + return ofNumber(int.class, Number::intValue, Integer::parseInt); + } + public static PrimitiveAdapters ofLong() { return ofNumber(Long.class, Number::longValue, Long::parseLong); } + public static PrimitiveAdapters ofLongType() { + return ofNumber(long.class, Number::longValue, Long::parseLong); + } + public static PrimitiveAdapters ofDouble() { return ofNumber(Double.class, Number::doubleValue, Double::parseDouble); } + public static PrimitiveAdapters ofDoubleType() { + return ofNumber(double.class, Number::doubleValue, Double::parseDouble); + } + public static PrimitiveAdapters ofFloat() { return ofNumber(Float.class, Number::floatValue, Float::parseFloat); } + public static PrimitiveAdapters ofFloatType() { + return ofNumber(float.class, Number::floatValue, Float::parseFloat); + } + public static PrimitiveAdapters ofShort() { return ofNumber(Short.class, Number::shortValue, Short::parseShort); } + public static PrimitiveAdapters ofShortType() { + return ofNumber(short.class, Number::shortValue, Short::parseShort); + } + public static PrimitiveAdapters ofByte() { return ofNumber(Byte.class, Number::byteValue, Byte::parseByte); } - protected PrimitiveAdapters(Class valueType) { - super(Object.class, valueType); - } - - @Override - public Object serialize(@NotNull ConfigurationProvider provider, @NotNull T value) throws Exception { - return value; + public static PrimitiveAdapters ofByteType() { + return ofNumber(byte.class, Number::byteValue, Byte::parseByte); } public static PrimitiveAdapters of(@NotNull Class clazz, @NotNull ConfigDataFunction function) { - return new PrimitiveAdapters(clazz) { - @Override - public T deserialize(@NotNull ConfigurationProvider provider, @NotNull Class clazz, @NotNull Object data) throws Exception { - return function.parse(data); - } - }; + return new PrimitiveAdapters<>(clazz, (p, type, data) -> function.handle(data)); } public static PrimitiveAdapters ofNumber(@NotNull Class numberClass, @NotNull ConfigDataFunction castFunction, @NotNull ConfigDataFunction parseFunction) { - return of(numberClass, o -> o instanceof Number ? castFunction.parse((Number) o) : parseFunction.parse(o.toString())); + return of(numberClass, o -> o instanceof Number ? castFunction.handle((Number) o) : parseFunction.handle(o.toString())); } + + protected PrimitiveAdapters(@NotNull Class valueType, @NotNull ValueParser deserializer) { + super(ValueType.of(valueType), (provider, type, value) -> value, deserializer); + } + } 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 new file mode 100644 index 0000000..3b713d5 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/StandardAdapters.java @@ -0,0 +1,19 @@ +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; + +public interface StandardAdapters { + + ValueAdapter SECTION_ADAPTER = new ValueAdapter<>( + ValueType.of(ConfigurationSection.class), + (provider, type, value) -> value, + (provider, type, value) -> { + if (value instanceof ConfigurationSection) { + return (ConfigurationSection) value; + } else throw new IllegalArgumentException("Value is not a ConfigurationSection"); + } + ); + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java index c843e17..9d21c85 100644 --- a/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java +++ b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.annotation; -import cc.carm.lib.configuration.loader.PathGenerator; +import cc.carm.lib.configuration.source.loader.PathGenerator; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java new file mode 100644 index 0000000..0481d70 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java @@ -0,0 +1,51 @@ +package cc.carm.lib.configuration.builder; + +import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.value.ConfigValue; +import cc.carm.lib.configuration.value.ValueManifest; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +public abstract class AbstractConfigBuilder, P extends ConfigurationProvider> { + + protected final Class providerClass; + + protected @Nullable P provider; + protected @Nullable String path; + + protected @NotNull Supplier defaultValueSupplier = () -> null; + + protected AbstractConfigBuilder(Class providerClass) { + this.providerClass = providerClass; + } + + protected abstract @NotNull B self(); + + public abstract @NotNull ConfigValue build(); + + public @NotNull B from(@Nullable P provider) { + this.provider = provider; + return self(); + } + + public @NotNull B path(@Nullable String path) { + this.path = path; + return self(); + } + + public @NotNull B defaults(@Nullable T defaultValue) { + return defaults(() -> defaultValue); + } + + public @NotNull B defaults(@NotNull Supplier<@Nullable T> supplier) { + this.defaultValueSupplier = supplier; + return self(); + } + + protected @NotNull ValueManifest buildManifest() { + return null; + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java new file mode 100644 index 0000000..10a1fe1 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java @@ -0,0 +1,12 @@ +package cc.carm.lib.configuration.builder; + +import cc.carm.lib.configuration.source.ConfigurationProvider; + +public abstract class CommonConfigBuilder> + extends AbstractConfigBuilder> { + + protected CommonConfigBuilder() { + super(ConfigurationProvider.class); + } + +} 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 new file mode 100644 index 0000000..113fabf --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/ConfigValueBuilder.java @@ -0,0 +1,78 @@ +package cc.carm.lib.configuration.builder.value; + +import cc.carm.lib.configuration.adapter.ValueType; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.source.section.ConfigurationSection; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class ConfigValueBuilder { + + protected final @NotNull ValueType type; + + public ConfigValueBuilder(@NotNull ValueType type) { + this.type = type; + } + + public @NotNull SourceValueBuilder from(@NotNull Class clazz) { + return new SourceValueBuilder<>(ValueType.of(clazz), this.type); + } + + public @NotNull SourceValueBuilder from(@NotNull ValueType sourceType) { + return new SourceValueBuilder<>(sourceType, this.type); + } + + public @NotNull SourceValueBuilder from(@NotNull ValueType sourceType, + @NotNull ConfigValueHandler valueParser, + @NotNull ConfigValueHandler valueSerializer) { + return new SourceValueBuilder<>(sourceType, this.type, valueParser, valueSerializer); + } + + public @NotNull SourceValueBuilder fromString() { + return from(String.class); + } + + public @NotNull SourceValueBuilder fromInteger() { + return from(Integer.class); + } + + public @NotNull SourceValueBuilder fromLong() { + return from(Long.class); + } + + public @NotNull SourceValueBuilder fromDouble() { + return from(Double.class); + } + + public @NotNull SourceValueBuilder fromFloat() { + return from(Float.class); + } + + public @NotNull SourceValueBuilder fromBoolean() { + return from(Boolean.class); + } + + public @NotNull SourceValueBuilder fromCharacter() { + return from(Character.class); + } + + public @NotNull SourceValueBuilder fromByte() { + return from(Byte.class); + } + + public @NotNull SourceValueBuilder fromShort() { + return from(Short.class); + } + + public @NotNull SectionValueBuilder fromSection() { + return new SectionValueBuilder<>(this.type); + } + + public @NotNull SectionValueBuilder fromSection(@NotNull ConfigValueHandler valueParser, + @NotNull ConfigValueHandler> 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 new file mode 100644 index 0000000..a4a4dae --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/SectionValueBuilder.java @@ -0,0 +1,81 @@ +package cc.carm.lib.configuration.builder.value; + +import cc.carm.lib.configuration.adapter.ValueType; +import cc.carm.lib.configuration.builder.CommonConfigBuilder; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.value.standard.ConfiguredValue; +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Consumer; + +public class SectionValueBuilder extends CommonConfigBuilder> { + + protected final @NotNull ValueType valueType; + + protected @NotNull ConfigValueHandler parser; + protected @NotNull ConfigValueHandler> serializer; + + public SectionValueBuilder(@NotNull ValueType valueType) { + this(valueType, ConfigValueHandler.required(), ConfigValueHandler.required()); + } + + public SectionValueBuilder(@NotNull ValueType valueType, + @NotNull ConfigValueHandler parser, + @NotNull ConfigValueHandler> serializer) { + this.valueType = valueType; + this.parser = parser; + this.serializer = serializer; + } + + @Override + protected @NotNull SectionValueBuilder self() { + return this; + } + + public @NotNull SectionValueBuilder parse(ConfigDataFunction valueParser) { + return parse((p, section) -> valueParser.handle(section)); + } + + public @NotNull SectionValueBuilder parse(ConfigValueHandler valueParser) { + this.parser = valueParser; + return this; + } + + public @NotNull SectionValueBuilder serialize(ConfigDataFunction> serializer) { + return serialize((p, value) -> serializer.handle(value)); + } + + public @NotNull SectionValueBuilder serialize(ConfigValueHandler> serializer) { + this.serializer = serializer; + return this; + } + + public @NotNull SectionValueBuilder serialize(Consumer> serializer) { + return serialize((p, value) -> { + Map map = new LinkedHashMap<>(); + serializer.accept(map); + return map; + }); + } + + @Override + public @NotNull ConfiguredValue build() { + return new ConfiguredValue<>( + buildManifest(), + (p, type, data) -> { + ConfigurationSection section = p.deserialize(ConfigurationSection.class, data); + if (section == null) return null; + return this.parser.handle(p, section); + }, + (p, type, data) -> { + Map map = this.serializer.handle(p, data); + return map == null || map.isEmpty() ? null : map; // Map is a type of original data + } + ); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java new file mode 100644 index 0000000..fd8bc29 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java @@ -0,0 +1,68 @@ +package cc.carm.lib.configuration.builder.value; + +import cc.carm.lib.configuration.adapter.ValueType; +import cc.carm.lib.configuration.builder.CommonConfigBuilder; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.value.standard.ConfiguredValue; +import org.jetbrains.annotations.NotNull; + +public class SourceValueBuilder extends CommonConfigBuilder> { + + protected final @NotNull ValueType sourceType; + protected final @NotNull ValueType valueType; + protected @NotNull ConfigValueHandler valueParser; + protected @NotNull ConfigValueHandler valueSerializer; + + public SourceValueBuilder(@NotNull ValueType sourceType, @NotNull ValueType valueType) { + this(sourceType, valueType, ConfigValueHandler.required(), ConfigValueHandler.required()); + } + + public SourceValueBuilder(@NotNull ValueType sourceType, @NotNull ValueType valueType, + @NotNull ConfigValueHandler valueParser, + @NotNull ConfigValueHandler valueSerializer) { + this.sourceType = sourceType; + this.valueType = valueType; + this.valueParser = valueParser; + this.valueSerializer = valueSerializer; + } + + @Override + protected @NotNull SourceValueBuilder self() { + return this; + } + + public @NotNull SourceValueBuilder parse(ConfigDataFunction parser) { + return parse((p, source) -> parser.handle(source)); + } + + public @NotNull SourceValueBuilder parse(@NotNull ConfigValueHandler parser) { + this.valueParser = parser; + return this; + } + + public @NotNull SourceValueBuilder serialize(@NotNull ConfigValueHandler serializer) { + this.valueSerializer = serializer; + return this; + } + + public @NotNull SourceValueBuilder serialize(@NotNull ConfigDataFunction serializer) { + return serialize((p, value) -> serializer.handle(value)); + } + + @Override + public @NotNull ConfiguredValue build() { + return new ConfiguredValue<>( + buildManifest(), + (p, type, data) -> { + S source = p.deserialize(this.sourceType, data); + return this.valueParser.handle(p, source); + }, + (p, type, value) -> { + S source = this.valueSerializer.handle(p, value); + return p.serialize(source); + } + ); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/function/ConfigDataFunction.java b/core/src/main/java/cc/carm/lib/configuration/function/ConfigDataFunction.java index 04d8cff..7571bcf 100644 --- a/core/src/main/java/cc/carm/lib/configuration/function/ConfigDataFunction.java +++ b/core/src/main/java/cc/carm/lib/configuration/function/ConfigDataFunction.java @@ -9,11 +9,11 @@ import java.util.Objects; @FunctionalInterface public interface ConfigDataFunction { - @NotNull R parse(@NotNull T data) throws Exception; + @NotNull R handle(@NotNull T data) throws Exception; default @NotNull ConfigDataFunction andThen(@NotNull ConfigDataFunction after) { Objects.requireNonNull(after); - return data -> after.parse(parse(data)); + return data -> after.handle(handle(data)); } @Contract(pure = true) diff --git a/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueHandler.java b/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueHandler.java new file mode 100644 index 0000000..165f471 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueHandler.java @@ -0,0 +1,67 @@ +package cc.carm.lib.configuration.function; + + +import cc.carm.lib.configuration.adapter.ValueType; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +@FunctionalInterface +public interface ConfigValueHandler { + + @Nullable R handle(@NotNull ConfigurationProvider provider, @NotNull T data) throws Exception; + + default ConfigValueHandler andThen(@NotNull ConfigValueHandler after) { + Objects.requireNonNull(after); + return ((provider, data) -> { + R result = handle(provider, data); + if (result == null) return null; + else return after.handle(provider, result); + }); + } + + default ConfigValueHandler compose(@NotNull ConfigValueHandler before) { + Objects.requireNonNull(before); + return ((provider, data) -> { + T result = before.handle(provider, data); + if (result == null) return null; + return handle(provider, result); + }); + } + + default ConfigValueHandler compose(@NotNull ConfigDataFunction before) { + Objects.requireNonNull(before); + return ((provider, data) -> { + T result = before.handle(data); + return handle(provider, result); + }); + } + + @Contract(pure = true) + static @NotNull ConfigValueHandler identity() { + return (provider, input) -> input; + } + + @Contract(pure = true) + static @NotNull ConfigValueHandler toObject() { + return ConfigurationProvider::serialize; + } + + @Contract(pure = true) + static @NotNull ConfigValueHandler fromObject(ValueType type) { + return (provider, input) -> provider.deserialize(type, input); + } + + + @Contract(pure = true) + static @NotNull ConfigValueHandler required() { + return (provider, input) -> { + throw new IllegalArgumentException("Please specify the value parser."); + }; + } +} + + diff --git a/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueParser.java b/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueParser.java deleted file mode 100644 index 9554776..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueParser.java +++ /dev/null @@ -1,62 +0,0 @@ -package cc.carm.lib.configuration.function; - - -import cc.carm.lib.configuration.source.ConfigurationProvider; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Objects; - -@FunctionalInterface -public interface ConfigValueParser { - - @Nullable R parse(@NotNull ConfigurationProvider provider, - @NotNull T data, @Nullable R defaultValue) throws Exception; - - default ConfigValueParser andThen(@NotNull ConfigValueParser after) { - Objects.requireNonNull(after); - return ((provider, data, defaultValue) -> { - R result = parse(provider, data, null); - if (result == null) return defaultValue; - else return after.parse(provider, result, defaultValue); - }); - } - - default ConfigValueParser compose(@NotNull ConfigValueParser before) { - Objects.requireNonNull(before); - return ((provider, data, defaultValue) -> { - T result = before.parse(provider, data, null); - if (result == null) return null; - return parse(provider, result, defaultValue); - }); - } - - default ConfigValueParser compose(@NotNull ConfigDataFunction before) { - Objects.requireNonNull(before); - return ((provider, data, defaultValue) -> { - T result = before.parse(data); - return parse(provider, result, defaultValue); - }); - } - - @Contract(pure = true) - static @NotNull ConfigValueParser identity() { - return (provider, input, defaultValue) -> input; - } - - @Contract(pure = true) - static @NotNull ConfigValueParser toObject() { - return (provider, input, defaultValue) -> input; - } - - @Contract(pure = true) - static @NotNull ConfigValueParser required() { - return (provider, input, defaultValue) -> { - throw new IllegalArgumentException("Please specify the value parser."); - }; - } - -} - - diff --git a/core/src/main/java/cc/carm/lib/configuration/meta/PathMetadata.java b/core/src/main/java/cc/carm/lib/configuration/meta/PathMetadata.java new file mode 100644 index 0000000..a2df1b1 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/meta/PathMetadata.java @@ -0,0 +1,58 @@ +package cc.carm.lib.configuration.meta; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; +import java.util.function.Supplier; + +public class PathMetadata { + + public static PathMetadata of() { + return of(() -> null); + } + + public static PathMetadata of(T defaults) { + return of(() -> defaults); + } + + public static PathMetadata of(@NotNull Supplier<@Nullable T> defaults) { + return of(v -> defaults.get()); + } + + public static PathMetadata of(@NotNull Function defaults) { + return new PathMetadata<>(defaults); + } + + protected Function defaultFunction; + + public PathMetadata(@NotNull Function defaults) { + this.defaultFunction = defaults; + } + + public boolean isDefault(String path, @NotNull T value) { + return value.equals(defaults(path)); + } + + public boolean hasDefaults(String path) { + return defaults(path) != null; + } + + public T getDefault(String path, @Nullable T suppliedValue) { + T defaults = defaults(path); + return defaults == null ? suppliedValue : defaults; + } + + public @Nullable T defaults(String path) { + return defaultFunction.apply(path); + } + + public void setDefaults(Function defaultFunction) { + this.defaultFunction = defaultFunction; + } + + public void setDefaults(T value) { + setDefaults((v) -> value); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/option/ConfigurationOptions.java b/core/src/main/java/cc/carm/lib/configuration/option/ConfigurationOptions.java deleted file mode 100644 index 6e17d6c..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/option/ConfigurationOptions.java +++ /dev/null @@ -1,25 +0,0 @@ -package cc.carm.lib.configuration.option; - - -import cc.carm.lib.easyoptions.OptionType; - -import static cc.carm.lib.easyoptions.OptionType.of; - -public interface ConfigurationOptions { - - /** - * The configuration path separator. - */ - OptionType PATH_SEPARATOR = of('.'); - - /** - * Whether to set & save default values if offered and not exists in configuration. - */ - OptionType SET_DEFAULTS = of(true); - - /** - * Whether to load subclasses of configuration class. - */ - OptionType LOAD_SUB_CLASSES = of(true); - -} 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 2e7b229..3046267 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,85 +1,84 @@ package cc.carm.lib.configuration.source; -import cc.carm.lib.configuration.adapter.ValueAdapter; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; -import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.loader.ConfigurationLoader; -import cc.carm.lib.configuration.loader.PathGenerator; -import cc.carm.lib.easyoptions.OptionHolder; -import cc.carm.lib.easyoptions.OptionType; +import cc.carm.lib.configuration.source.loader.ConfigurationLoader; +import cc.carm.lib.configuration.source.loader.PathGenerator; +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 org.jetbrains.annotations.NotNull; import java.util.function.Consumer; import java.util.function.Function; -public abstract class ConfigurationFactory

, C> { +public abstract class ConfigurationFactory, PROVIDER extends ConfigurationProvider, SELF> { - protected Function loaderFunction = p -> new ConfigurationLoader(); + protected Function loaderFunction = PROVIDER -> new ConfigurationLoader(); protected Consumer loaderConsumer = loader -> { }; protected ValueAdapterRegistry adapters = new ValueAdapterRegistry(); - protected OptionHolder options = new OptionHolder(); + protected ConfigurationOptionHolder options = new ConfigurationOptionHolder(); - public abstract C getThis(); + public abstract SELF self(); - public C loader(Function loaderFunction) { + public SELF loader(Function loaderFunction) { this.loaderFunction = loaderFunction; - return getThis(); + return self(); } - public C loader(ConfigurationLoader loader) { - return loader(p -> loader); + public SELF loader(ConfigurationLoader loader) { + return loader(PROVIDER -> loader); } - public C loader(Consumer loaderConsumer) { + public SELF loader(Consumer loaderConsumer) { this.loaderConsumer = this.loaderConsumer.andThen(loaderConsumer); - return getThis(); + return self(); } - public C pathGenerator(PathGenerator pathGenerator) { + public SELF pathGenerator(PathGenerator pathGenerator) { return loader(loader -> { loader.setPathGenerator(pathGenerator); }); } - public C adapters(ValueAdapterRegistry adapters) { + public SELF adapters(ValueAdapterRegistry adapters) { this.adapters = adapters; - return getThis(); + return self(); } - public C adapter(Consumer adapterRegistryConsumer) { + public SELF adapter(Consumer adapterRegistryConsumer) { adapterRegistryConsumer.accept(adapters); - return getThis(); + return self(); } - public C adapter(@NotNull ValueAdapter adapter) { - return adapter(a -> a.register(adapter)); - } +// public SELF adapter(@NotNull ValueAdapter 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 C adapter(Class clazz, @NotNull ValueAdapter adapter) { - return adapter(a -> a.register(clazz, adapter)); - } - - public C adapter(Class baseClass, Class valueClass, - ConfigDataFunction parser, ConfigDataFunction serializer) { - return adapter(a -> a.register(baseClass, valueClass, parser, serializer)); - } - - public C options(OptionHolder options) { + public SELF options(ConfigurationOptionHolder options) { this.options = options; - return getThis(); + return self(); } - public C option(Consumer optionsConsumer) { + public SELF option(Consumer optionsConsumer) { optionsConsumer.accept(options); - return getThis(); + return self(); } - public C option(OptionType option, O value) { + public SELF option(ConfigurationOption option, O value) { return option(o -> o.set(option, value)); } - public abstract @NotNull P build(); + public abstract @NotNull PROVIDER build(); } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java index 82cc98b..68f7097 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java @@ -2,24 +2,36 @@ package cc.carm.lib.configuration.source; import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; -import cc.carm.lib.configuration.loader.ConfigurationLoader; -import cc.carm.lib.easyoptions.OptionHolder; -import cc.carm.lib.easyoptions.OptionType; +import cc.carm.lib.configuration.adapter.ValueType; +import cc.carm.lib.configuration.meta.PathMetadata; +import cc.carm.lib.configuration.source.loader.ConfigurationLoader; +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.value.ValueManifest; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; public class ConfigurationProvider> { protected final @NotNull S source; protected final @NotNull ConfigurationLoader loader; protected final @NotNull ValueAdapterRegistry adapters; - protected final @NotNull OptionHolder options; + protected final @NotNull ConfigurationOptionHolder options; + protected final @NotNull Map, Object>> pathMetadata; public ConfigurationProvider(@NotNull S source, @NotNull ConfigurationLoader loader, - @NotNull ValueAdapterRegistry adapters, @NotNull OptionHolder options) { + @NotNull ValueAdapterRegistry adapters, + @NotNull ConfigurationOptionHolder options, + @NotNull Map, Object>> pathMetadata) { this.source = source; this.loader = loader; this.adapters = adapters; this.options = options; + this.pathMetadata = pathMetadata; } public @NotNull S source() { @@ -34,15 +46,15 @@ public class ConfigurationProvider> { source().save(); } - public OptionHolder options() { + public ConfigurationOptionHolder options() { return options; } - public @NotNull T option(@NotNull OptionType option) { + public @NotNull T option(@NotNull ConfigurationOption option) { return options.get(option); } - public void option(@NotNull OptionType option, @NotNull T value) { + public void option(@NotNull ConfigurationOption option, @NotNull T value) { options.set(option, value); } @@ -50,11 +62,117 @@ public class ConfigurationProvider> { return this.adapters; } - public ConfigurationLoader loader() { return loader; } + public @NotNull Map, Object>> pathMetadata() { + return pathMetadata; + } + + public @NotNull Map, Object> metadata(@NotNull String path) { + return pathMetadata().computeIfAbsent(path, k -> new java.util.HashMap<>()); + } + + /** + * Get the value of option. + * + * @param type {@link PathMetadata} + * @param defaultValue Default value if the value of option is not set. + * @param Value type + * @return Value of option + */ + @SuppressWarnings("unchecked") + @Contract("_,_, !null -> !null") + public @Nullable V meta(@NotNull String path, + @NotNull PathMetadata type, @Nullable V defaultValue) { + return (V) metadata(path).getOrDefault(type, type.getDefault(path, defaultValue)); + } + + /** + * Get the value of option. + * + * @param type {@link PathMetadata} + * @param Value type + * @return Value of option + */ + public @Nullable V meta(@NotNull String path, @NotNull PathMetadata type) { + return meta(path, type, null); + } + + public boolean hasMeta(@NotNull String path, @NotNull PathMetadata type) { + return metadata(path).containsKey(type) || type.hasDefaults(path); + } + + /** + * Set the value of meta, if the value is null, the meta will be removed. + *
Will only be changed in current holder. + * + * @param type {@link PathMetadata} + * @param value Value of meta + * @param Value type + * @return Previous value of meta + */ + @SuppressWarnings("unchecked") + public @Nullable V setMeta(@NotNull String path, @NotNull PathMetadata type, @Nullable V value) { + if (value == null || type.isDefault(path, value)) { + return (V) metadata(path).remove(type); + } else { + return (V) metadata(path).put(type, value); + } + } + + /** + * Set the value of meta, if the value is null, the meta will not be changed. + *
Will only be changed in current holder. + * + * @param type {@link PathMetadata} + * @param value Value of meta + * @param Value type + */ + public void setMetaIfAbsent(@NotNull String path, @NotNull PathMetadata type, @Nullable V value) { + if (value == null || type.isDefault(path, value)) { + metadata(path).remove(type); + } else { + metadata(path).putIfAbsent(type, value); + } + } + + /** + * Set the value of meta, if the value is null, the meta will not be changed. + *
Will only be changed in current holder. + * + * @param type {@link PathMetadata} + * @param value Value of meta + * @param Value type + */ + @SuppressWarnings("unchecked") + public @Nullable V setMetaIfPresent(@NotNull String path, @NotNull PathMetadata type, @Nullable V value) { + Object exists = metadata(path).get(type); + if (exists == null) return null; + + if (value == null || type.isDefault(path, value)) { + return (V) metadata(path).remove(type); + } else { + return (V) metadata(path).put(type, value); + } + } + + @Contract("_,null -> null") + public T deserialize(@NotNull Class type, @Nullable Object source) throws Exception { + return adapters().deserialize(this, type, source); + } + + @Contract("_,null -> null") + public T deserialize(@NotNull ValueType type, @Nullable Object source) throws Exception { + return adapters().deserialize(this, type, source); + } + + @Contract("null -> null") + public Object serialize(@Nullable T value) throws Exception { + return adapters().serialize(this, value); + } + public void load(Class configClass) { try { loader.load(this, configClass); @@ -71,4 +189,8 @@ public class ConfigurationProvider> { } } + public void load(@NotNull ValueManifest value) { + value.provider(this); + } + } diff --git a/core/src/main/java/cc/carm/lib/configuration/loader/ConfigurationLoader.java b/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationLoader.java similarity index 72% rename from core/src/main/java/cc/carm/lib/configuration/loader/ConfigurationLoader.java rename to core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationLoader.java index d2d341a..7c4052f 100644 --- a/core/src/main/java/cc/carm/lib/configuration/loader/ConfigurationLoader.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationLoader.java @@ -1,11 +1,14 @@ -package cc.carm.lib.configuration.loader; +package cc.carm.lib.configuration.source.loader; import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.source.ConfigurationProvider; -import cc.carm.lib.configuration.option.ConfigurationOptions; +import cc.carm.lib.configuration.source.option.ConfigurationOptions; +import cc.carm.lib.configuration.value.ConfigValue; +import cc.carm.lib.configuration.value.ValueManifest; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.lang.reflect.Field; import java.util.Arrays; @@ -15,6 +18,20 @@ import java.util.Arrays; */ public class ConfigurationLoader { + public static final Field PATH_FIELD; + public static final Field PROVIDER_FIELD; + + static { + try { + PATH_FIELD = ValueManifest.class.getDeclaredField("path"); + PATH_FIELD.setAccessible(true); + PROVIDER_FIELD = ValueManifest.class.getDeclaredField("provider"); + PROVIDER_FIELD.setAccessible(true); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + protected PathGenerator pathGenerator; public ConfigurationLoader() { @@ -83,13 +100,15 @@ public class ConfigurationLoader { field.setAccessible(true); Object object = field.get(source); // -// if (object instanceof ConfigValue) { -// // 目标是 ConfigValue 实例,进行具体的初始化注入 -// -// } else - - if (source instanceof Configuration && object instanceof Configuration) { - // 当且仅当 源字段与字段 均为ConfigurationRoot实例时,才对目标字段进行下一步初始化加载。 + if (object instanceof ConfigValue) { + // 目标是 ConfigValue 实例,进行具体的初始化注入 + ConfigValue value = (ConfigValue) object; + String path = getFieldPath(provider, parent, field); + if (path == null) return; + insertIfAbsent(value, PATH_FIELD, path); + insertIfAbsent(value, PROVIDER_FIELD, provider); + } else if (source instanceof Configuration && object instanceof Configuration) { + // 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。 initializeInstance(provider, (Configuration) object, parent, field); } else if (source instanceof Class && object instanceof Class) { // 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。 @@ -97,11 +116,18 @@ public class ConfigurationLoader { } // 以上判断实现以下规范: - // - 实例类中仅加载 ConfigValue实例 与 ConfigurationRoot实例 - // - 静态类中仅加载 静态ConfigValue实例 与 静态ConfigurationRoot类 + // - 实例类中仅加载 ConfigValue实例 与 Configuration实例 + // - 静态类中仅加载 静态ConfigValue实例 与 静态Configuration类 } catch (IllegalAccessException ignored) { } } + private void insertIfAbsent(@NotNull ValueManifest value, @NotNull Field field, @NotNull Object obj) { + try { + if (field.get(obj) == null) field.set(obj, value); + } catch (IllegalAccessException ignored) { + } + } + } diff --git a/core/src/main/java/cc/carm/lib/configuration/loader/PathGenerator.java b/core/src/main/java/cc/carm/lib/configuration/source/loader/PathGenerator.java similarity index 97% rename from core/src/main/java/cc/carm/lib/configuration/loader/PathGenerator.java rename to core/src/main/java/cc/carm/lib/configuration/source/loader/PathGenerator.java index d2ad485..f7d508e 100644 --- a/core/src/main/java/cc/carm/lib/configuration/loader/PathGenerator.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/loader/PathGenerator.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.loader; +package cc.carm.lib.configuration.source.loader; import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.NotNull; diff --git a/core/src/main/java/cc/carm/lib/configuration/loader/StandardPathGenerator.java b/core/src/main/java/cc/carm/lib/configuration/source/loader/StandardPathGenerator.java similarity index 96% rename from core/src/main/java/cc/carm/lib/configuration/loader/StandardPathGenerator.java rename to core/src/main/java/cc/carm/lib/configuration/source/loader/StandardPathGenerator.java index 4513647..2612e0a 100644 --- a/core/src/main/java/cc/carm/lib/configuration/loader/StandardPathGenerator.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/loader/StandardPathGenerator.java @@ -1,8 +1,8 @@ -package cc.carm.lib.configuration.loader; +package cc.carm.lib.configuration.source.loader; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.source.ConfigurationProvider; -import cc.carm.lib.configuration.option.ConfigurationOptions; +import cc.carm.lib.configuration.source.option.ConfigurationOptions; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOption.java b/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOption.java new file mode 100644 index 0000000..fdc6ed4 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOption.java @@ -0,0 +1,46 @@ +package cc.carm.lib.configuration.source.option; + +import org.jetbrains.annotations.NotNull; + +public class ConfigurationOption { + + @SuppressWarnings("unchecked") + public static ConfigurationOption of(@NotNull T defaultValue) { + return of((Class) defaultValue.getClass(), defaultValue); + } + + public static ConfigurationOption of(@NotNull Class valueClazz, @NotNull T defaultValue) { + return new ConfigurationOption<>(valueClazz, defaultValue); + } + + private final @NotNull Class valueClazz; + private @NotNull V defaultValue; + + public ConfigurationOption(@NotNull Class valueClazz, @NotNull V defaultValue) { + this.valueClazz = valueClazz; + this.defaultValue = defaultValue; + } + + @NotNull + public Class valueClass() { + return this.valueClazz; + } + + public @NotNull V defaults() { + return defaultValue; + } + + /** + * Set the default value of option. + * + * @param defaultValue Default value + */ + public void defaults(@NotNull V defaultValue) { + this.defaultValue = defaultValue; + } + + public boolean isDefault(@NotNull V value) { + return value.equals(defaultValue); + } + +} \ No newline at end of file diff --git a/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptionHolder.java b/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptionHolder.java new file mode 100644 index 0000000..abacb5d --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptionHolder.java @@ -0,0 +1,70 @@ +package cc.carm.lib.configuration.source.option; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +public class ConfigurationOptionHolder { + + public static @NotNull ConfigurationOptionHolder of(@NotNull Map, V> options) { + return new ConfigurationOptionHolder(new ConcurrentHashMap<>(options)); + } + + protected final Map, Object> options; + + public ConfigurationOptionHolder() { + this(new ConcurrentHashMap<>()); + } + + public ConfigurationOptionHolder(Map, Object> options) { + this.options = options; + } + + public @NotNull Map, Object> options() { + return options; + } + + /** + * Get the value of option. + * + * @param type {@link ConfigurationOption} + * @param Value type + * @return Value of option + */ + @SuppressWarnings("unchecked") + public @NotNull V get(@NotNull ConfigurationOption type) { + return Optional.ofNullable(options().get(type)).map(v -> (V) v).orElseGet(type::defaults); + } + + /** + * Set the value of option. + * + * @param type {@link ConfigurationOption} + * @param value Value of option + * @param Value type + * @return Previous value of option + */ + @SuppressWarnings("unchecked") + public @Nullable V set(@NotNull ConfigurationOption type, @Nullable V value) { + if (value == null) { + return (V) options().remove(type); + } else { + return (V) options().put(type, value); + } + } + + /** + * Set the value of option to option's {@link ConfigurationOption#defaults()}. + * + * @param type {@link ConfigurationOption} + * @param Value type + * @return Previous value of option + */ + public @Nullable V clear(@NotNull ConfigurationOption type) { + return set(type, null); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptions.java b/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptions.java new file mode 100644 index 0000000..377a273 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptions.java @@ -0,0 +1,33 @@ +package cc.carm.lib.configuration.source.option; + +import cc.carm.lib.configuration.Configuration; + +import static cc.carm.lib.configuration.source.option.ConfigurationOption.of; + +public interface ConfigurationOptions { + + /** + * The configuration path separator. + */ + ConfigurationOption PATH_SEPARATOR = of('.'); + + /** + * Whether to set & save default values if offered and not exists in configuration. + */ + ConfigurationOption SET_DEFAULTS = of(true); + + /** + * Whether to load subclasses of configuration class. + */ + ConfigurationOption LOAD_SUB_CLASSES = of(true); + + /** + * Whether to pre parse the config values. + *
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 cc.carm.lib.configuration.source.ConfigurationProvider#load(Configuration)}. + */ + ConfigurationOption PRELOAD = of(false); + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSection.java b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSection.java similarity index 87% rename from core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSection.java rename to core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSection.java index c058695..088c1d8 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSection.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSection.java @@ -1,7 +1,6 @@ -package cc.carm.lib.configuration.source; +package cc.carm.lib.configuration.source.section; import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.function.ConfigValueParser; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,7 +11,9 @@ import java.util.*; public interface ConfigurationSection { @NotNull - Set getKeys(boolean deep); + default Set getKeys(boolean deep) { + return getValues(deep).keySet(); + } @NotNull Map getValues(boolean deep); @@ -40,22 +41,22 @@ public interface ConfigurationSection { return get(path, null, clazz); } - default @Nullable T get(@NotNull String path, @NotNull ConfigValueParser parser) { + default @Nullable T get(@NotNull String path, @NotNull ConfigDataFunction parser) { return get(path, null, parser); } @Contract("_,!null,_->!null") default @Nullable T get(@NotNull String path, @Nullable T defaultValue, @NotNull Class clazz) { - return get(path, defaultValue, ConfigValueParser.castObject(clazz)); + return get(path, defaultValue, ConfigDataFunction.castObject(clazz)); } @Contract("_,!null,_->!null") default @Nullable T get(@NotNull String path, @Nullable T defaultValue, - @NotNull ConfigValueParser parser) { + @NotNull ConfigDataFunction parser) { Object value = get(path); if (value != null) { try { - return parser.parse(value, defaultValue); + return parser.handle(value); } catch (Exception e) { e.printStackTrace(); } @@ -74,7 +75,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) { - return get(path, def, ConfigValueParser.booleanValue()); + return get(path, def, ConfigDataFunction.booleanValue()); } default @Nullable Boolean isByte(@NotNull String path) { @@ -87,7 +88,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) { - return get(path, def, ConfigValueParser.byteValue()); + return get(path, def, ConfigDataFunction.byteValue()); } default boolean isShort(@NotNull String path) { @@ -100,7 +101,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Short getShort(@NotNull String path, @Nullable Short def) { - return get(path, def, ConfigValueParser.shortValue()); + return get(path, def, ConfigDataFunction.shortValue()); } @@ -114,7 +115,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) { - return get(path, def, ConfigValueParser.intValue()); + return get(path, def, ConfigDataFunction.intValue()); } @@ -128,7 +129,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Long getLong(@NotNull String path, @Nullable Long def) { - return get(path, def, ConfigValueParser.longValue()); + return get(path, def, ConfigDataFunction.longValue()); } @@ -142,7 +143,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) { - return get(path, def, ConfigValueParser.floatValue()); + return get(path, def, ConfigDataFunction.floatValue()); } @@ -156,7 +157,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) { - return get(path, def, ConfigValueParser.doubleValue()); + return get(path, def, ConfigDataFunction.doubleValue()); } @@ -232,7 +233,7 @@ public interface ConfigurationSection { List values = new ArrayList<>(); for (Object o : list) { try { - values.add(parser.parse(o)); + values.add(parser.handle(o)); } catch (Exception ignored) { } } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSource.java b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSource.java similarity index 54% rename from core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSource.java rename to core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSource.java index 72723ed..fd27553 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationSource.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigurationSource.java @@ -1,10 +1,9 @@ -package cc.carm.lib.configuration.source; +package cc.carm.lib.configuration.source.section; import org.jetbrains.annotations.NotNull; -import java.util.Set; - -public abstract class ConfigurationSource, O> implements ConfigurationSection { +public abstract class ConfigurationSource, ORIGINAL> + implements ConfigurationSection { protected long updateMillis; @@ -17,25 +16,23 @@ public abstract class ConfigurationSource, O this.updateMillis = System.currentTimeMillis(); } - protected abstract S getThis(); + 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 abstract @NotNull O original(); - - @NotNull - public Set getKeys(boolean deep) { - return getValues(deep).keySet(); - } - public long getUpdateMillis() { return this.updateMillis; } - public boolean isExpired(long time) { - return getUpdateMillis() > time; + public boolean isExpired(long parsedTime) { + return getUpdateMillis() > parsedTime; } } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java index e2901d9..c198c18 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java @@ -9,12 +9,8 @@ import java.util.Optional; public abstract class ConfigValue extends ValueManifest { -// public static @NotNull ConfigBuilder builder() { -// return new ConfigBuilder(); -// } - protected ConfigValue(@NotNull ValueManifest manifest) { - super(manifest.metadata, manifest.provider, manifest.defaultSupplier); + super(manifest.type, manifest.provider, manifest.path, manifest.defaultSupplier); } /** @@ -41,7 +37,7 @@ public abstract class ConfigValue extends ValueManifest { * @throws NullPointerException 对应数据为空时抛出 */ public @NotNull T getNotNull() { - return Objects.requireNonNull(getOrDefault(), "Value(" + path() + ") is null."); + return Objects.requireNonNull(getOrDefault(), "Value(" + path() + ") [" + type() + "] is null."); } public @NotNull Optional<@Nullable T> optional() { 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 fb4b36d..f508cd7 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 @@ -1,30 +1,56 @@ package cc.carm.lib.configuration.value; +import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.source.ConfigurationProvider; -import cc.carm.lib.configuration.source.ConfigurationSource; -import cc.carm.lib.configuration.value.meta.ValueMetaList; -import cc.carm.lib.configuration.value.meta.ValueMetaType; -import org.jetbrains.annotations.Contract; +import cc.carm.lib.configuration.source.section.ConfigurationSource; +import cc.carm.lib.configuration.meta.PathMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.lang.reflect.Type; import java.util.Map; import java.util.function.Supplier; public class ValueManifest { - protected final @NotNull Map, Object> metadata; + protected final @NotNull ValueType type; protected @Nullable ConfigurationProvider provider; + protected @Nullable String path; // Section path + protected @NotNull Supplier<@Nullable T> defaultSupplier; - public ValueManifest(@NotNull Map, Object> metadata, - @Nullable ConfigurationProvider provider, @NotNull Supplier<@Nullable T> defaultSupplier) { - this.metadata = metadata; + public ValueManifest(ValueType type) { + this(type, null, null, () -> null); + } + + public ValueManifest(@NotNull T defaultValue) { + this(ValueType.of(defaultValue), null, null, () -> defaultValue); + } + + public ValueManifest(@NotNull ValueType type, @NotNull Supplier<@Nullable T> defaultSupplier) { + this(type, null, null, defaultSupplier); + } + + public ValueManifest(@NotNull ValueType type, + @Nullable ConfigurationProvider provider, @Nullable String path, + @NotNull Supplier<@Nullable T> defaultSupplier) { + this.type = type; this.provider = provider; + this.path = path; this.defaultSupplier = defaultSupplier; } + public @NotNull ValueType type() { + return this.type; + } + + public void provider(@NotNull ConfigurationProvider provider) { + this.provider = provider; + } + + public void path(@NotNull String path) { + this.path = path; + } + public @Nullable T defaults() { return this.defaultSupplier.get(); } @@ -37,6 +63,15 @@ public class ValueManifest { this.defaultSupplier = defaultValue; } + public boolean hasDefaults() { + return this.defaultSupplier.get() != null; + } + + public @NotNull String path() { + if (path != null) return path; + else throw new IllegalStateException("No section path provided."); + } + public @NotNull ConfigurationProvider provider() { if (this.provider != null) return this.provider; throw new IllegalStateException("Value does not have a provider."); @@ -46,106 +81,16 @@ public class ValueManifest { return provider().source(); } - public @NotNull String path() { - String path = getMeta(ValueMetaList.PATH); - if (path != null) return path; - else throw new IllegalStateException("No section path provided."); - } - - protected Object getValue() { + protected Object getData() { return config().get(path()); } - protected void setValue(@Nullable Object value) { + protected void setData(@Nullable Object value) { config().set(path(), value); } - public Map, Object> metadata() { - return metadata; + public Map, Object> metadata() { + return provider().metadata(path()); } - /** - * Get the value of option. - * - * @param type {@link ValueMetaType} - * @param defaultValue Default value if the value of option is not set. - * @param Value type - * @return Value of option - */ - @SuppressWarnings("unchecked") - @Contract("_, !null -> !null") - public @Nullable V getMeta(@NotNull ValueMetaType type, @Nullable V defaultValue) { - return (V) metadata().getOrDefault(type, type.getDefault(this, defaultValue)); - } - - /** - * Get the value of option. - * - * @param type {@link ValueMetaType} - * @param Value type - * @return Value of option - */ - public @Nullable V getMeta(@NotNull ValueMetaType type) { - return getMeta(type, null); - } - - public boolean hasMeta(@NotNull ValueMetaType type) { - return metadata().containsKey(type) || type.hasDefaults(this); - } - - /** - * Set the value of meta, if the value is null, the meta will be removed. - *
Will only be changed in current holder. - * - * @param type {@link ValueMetaType} - * @param value Value of meta - * @param Value type - * @return Previous value of meta - */ - @SuppressWarnings("unchecked") - public @Nullable V setMeta(@NotNull ValueMetaType type, @Nullable V value) { - if (value == null || type.isDefault(this, value)) { - return (V) metadata().remove(type); - } else { - return (V) metadata().put(type, value); - } - } - - /** - * Set the value of meta, if the value is null, the meta will not be changed. - *
Will only be changed in current holder. - * - * @param type {@link ValueMetaType} - * @param value Value of meta - * @param Value type - */ - public void setMetaIfAbsent(@NotNull ValueMetaType type, @Nullable V value) { - if (value == null || type.isDefault(this, value)) { - metadata().remove(type); - } else { - metadata().putIfAbsent(type, value); - } - } - - /** - * Set the value of meta, if the value is null, the meta will not be changed. - *
Will only be changed in current holder. - * - * @param type {@link ValueMetaType} - * @param value Value of meta - * @param Value type - */ - @SuppressWarnings("unchecked") - public @Nullable V setMetaIfPresent(@NotNull ValueMetaType type, @Nullable V value) { - Object exists = metadata().get(type); - if (exists == null) return null; - - if (value == null || type.isDefault(this, value)) { - return (V) metadata().remove(type); - } else { - return (V) metadata().put(type, value); - } - } - - } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java index 6cd50ea..13b852d 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public abstract class CachedConfigValue extends ConfigValue { - + protected @Nullable T cachedValue; protected long parsedTime = -1; @@ -30,13 +30,24 @@ public abstract class CachedConfigValue extends ConfigValue { } protected final T getDefaultFirst(@Nullable T value) { - return updateCache(this.defaultSupplier == null ? value : this.defaultSupplier); + return updateCache(this.defaults() == null ? value : this.defaults()); } + /** + * Get the cached value or the default value if the cached value is null + * + * @return the cached value or the default value + */ protected @Nullable T getCachedOrDefault() { return getCachedOrDefault(null); } + /** + * Get the cached value or the default value if the cached value is null + * + * @param emptyValue the value to return if the cached value and the default value are null + * @return the cached value or the default value + */ @Contract("!null->!null") protected T getCachedOrDefault(@Nullable T emptyValue) { if (getCachedValue() != null) return getCachedValue(); diff --git a/core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java b/core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java deleted file mode 100644 index e4f8c8b..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/value/impl/ConfigValueMap.java +++ /dev/null @@ -1,213 +0,0 @@ -//package cc.carm.lib.configuration.value.impl; -// -//import cc.carm.lib.configuration.builder.map.ConfigMapCreator; -//import cc.carm.lib.configuration.function.ConfigDataFunction; -//import cc.carm.lib.configuration.value.ValueManifest; -//import org.jetbrains.annotations.NotNull; -//import org.jetbrains.annotations.Nullable; -//import org.jetbrains.annotations.Unmodifiable; -// -//import java.util.*; -//import java.util.function.Consumer; -//import java.util.function.Function; -//import java.util.function.Supplier; -// -//public abstract class ConfigValueMap extends CachedConfigValue> implements Map { -// -// public static @NotNull ConfigMapCreator builderOf(@NotNull Class keyClass, -// @NotNull Class valueClass) { -// return builder().asMap(keyClass, valueClass); -// } -// -// protected final @NotNull Supplier> supplier; -// -// protected final @NotNull Class sourceClass; -// protected final @NotNull Class keyClass; -// protected final @NotNull Class valueClass; -// -// protected final @NotNull ConfigDataFunction keyParser; -// protected final @NotNull ConfigDataFunction valueParser; -// -// protected final @NotNull ConfigDataFunction keySerializer; -// protected final @NotNull ConfigDataFunction valueSerializer; -// -// -// protected ConfigValueMap(@NotNull ValueManifest> manifest, @NotNull Class sourceClass, -// @NotNull Supplier> mapObjSupplier, -// @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, -// @NotNull Class valueClass, @NotNull ConfigDataFunction valueParser, -// @NotNull ConfigDataFunction keySerializer, -// @NotNull ConfigDataFunction valueSerializer) { -// super(manifest); -// this.supplier = mapObjSupplier; -// this.sourceClass = sourceClass; -// this.keyClass = keyClass; -// this.valueClass = valueClass; -// this.keyParser = keyParser; -// this.valueParser = valueParser; -// this.keySerializer = keySerializer; -// this.valueSerializer = valueSerializer; -// } -// -// public @NotNull Class getSourceClass() { -// return sourceClass; -// } -// -// public @NotNull Class getKeyClass() { -// return keyClass; -// } -// -// public @NotNull Class getValueClass() { -// return valueClass; -// } -// -// public @NotNull ConfigDataFunction getKeyParser() { -// return keyParser; -// } -// -// public @NotNull ConfigDataFunction getValueParser() { -// return valueParser; -// } -// -// public @NotNull ConfigDataFunction getKeySerializer() { -// return keySerializer; -// } -// -// public @NotNull ConfigDataFunction getValueSerializer() { -// return valueSerializer; -// } -// -// public abstract S getSource(ConfigurationWrapper section, String dataKey); -// -// @Override -// public @NotNull Map get() { -// if (!isExpired()) return getCachedOrDefault(supplier.get()); -// -// // 已过时的数据,需要重新解析一次。 -// Map map = supplier.get(); -// -// ConfigurationWrapper section = getConfiguration().getConfigurationSection(getConfigPath()); -// if (section == null) return getDefaultFirst(map); -// -// Set keys = section.getKeys(false); -// if (keys.isEmpty()) return getDefaultFirst(map); -// -// for (String dataKey : keys) { -// S dataVal = getSource(section, dataKey); -// if (dataVal == null) continue; -// try { -// K key = keyParser.parse(dataKey); -// V value = valueParser.parse(dataVal); -// map.put(key, value); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// -// return updateCache(map); -// } -// -// @Override -// public V get(Object key) { -// return get().get(key); -// } -// -// public V getNotNull(Object key) { -// return Objects.requireNonNull(get(key)); -// } -// -// @Override -// public void set(@Nullable Map value) { -// updateCache(value); -// if (value == null) setValue(null); -// else { -// Map data = new LinkedHashMap<>(); -// for (Map.Entry entry : value.entrySet()) { -// try { -// data.put( -// keySerializer.parse(entry.getKey()), -// valueSerializer.parse(entry.getValue()) -// ); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// setValue(data); -// } -// } -// -// public @NotNull T modifyValue(Function, T> function) { -// Map m = get(); -// T result = function.apply(m); -// set(m); -// return result; -// } -// -// public @NotNull Map modifyMap(Consumer> consumer) { -// Map m = get(); -// consumer.accept(m); -// set(m); -// return m; -// } -// -// @Override -// public int size() { -// return get().size(); -// } -// -// @Override -// public boolean isEmpty() { -// return get().isEmpty(); -// } -// -// @Override -// public boolean containsKey(Object key) { -// return get().containsKey(key); -// } -// -// @Override -// public boolean containsValue(Object value) { -// return get().containsValue(value); -// } -// -// @Nullable -// @Override -// public V put(K key, V value) { -// return modifyValue(m -> m.put(key, value)); -// } -// -// @Override -// public V remove(Object key) { -// return modifyValue(m -> m.remove(key)); -// } -// -// @Override -// public void putAll(@NotNull Map m) { -// modifyMap(map -> map.putAll(m)); -// } -// -// @Override -// public void clear() { -// modifyMap(Map::clear); -// } -// -// @NotNull -// @Override -// public Set keySet() { -// return get().keySet(); -// } -// -// @NotNull -// @Override -// public Collection values() { -// return get().values(); -// } -// -// @NotNull -// @Override -// @Unmodifiable -// public Set> entrySet() { -// return get().entrySet(); -// } -// -//} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaList.java b/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaList.java deleted file mode 100644 index abd0614..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaList.java +++ /dev/null @@ -1,11 +0,0 @@ -package cc.carm.lib.configuration.value.meta; - -public interface ValueMetaList { - - /** - * The value path in configuration. - * Also see {@link cc.carm.lib.configuration.option.ConfigurationOptions#PATH_SEPARATOR} - */ - ValueMetaType PATH = ValueMetaType.of(); - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaType.java b/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaType.java deleted file mode 100644 index 6c5d825..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/value/meta/ValueMetaType.java +++ /dev/null @@ -1,59 +0,0 @@ -package cc.carm.lib.configuration.value.meta; - -import cc.carm.lib.configuration.value.ValueManifest; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Function; -import java.util.function.Supplier; - -public class ValueMetaType { - - public static ValueMetaType of() { - return of(() -> null); - } - - public static ValueMetaType of(T defaults) { - return of(() -> defaults); - } - - public static ValueMetaType of(@NotNull Supplier<@Nullable T> defaults) { - return of(v -> defaults.get()); - } - - public static ValueMetaType of(@NotNull Function, @Nullable T> defaults) { - return new ValueMetaType<>(defaults); - } - - protected Function, @Nullable T> defaultFunction; - - public ValueMetaType(@NotNull Function, @Nullable T> defaults) { - this.defaultFunction = defaults; - } - - public boolean isDefault(ValueManifest manifest, @NotNull T value) { - return value.equals(defaults(manifest)); - } - - public boolean hasDefaults(ValueManifest manifest) { - return defaults(manifest) != null; - } - - public T getDefault(ValueManifest manifest, @Nullable T suppliedValue) { - T defaults = defaults(manifest); - return defaults == null ? suppliedValue : defaults; - } - - public @Nullable T defaults(ValueManifest manifest) { - return defaultFunction.apply(manifest); - } - - public void setDefaults(Function, T> defaultFunction) { - this.defaultFunction = defaultFunction; - } - - public void setDefaults(T value) { - setDefaults((v) -> value); - } - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java index b7c9713..e5907ff 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java @@ -1,229 +1,231 @@ -//package cc.carm.lib.configuration.value.standard; -// -//import cc.carm.lib.configuration.builder.list.ConfigListBuilder; -//import cc.carm.lib.configuration.function.ConfigDataFunction; -//import cc.carm.lib.configuration.value.ValueManifest; -//import cc.carm.lib.configuration.value.impl.CachedConfigValue; -//import org.jetbrains.annotations.NotNull; -//import org.jetbrains.annotations.Nullable; -// -//import java.util.*; -//import java.util.function.Consumer; -//import java.util.function.Function; -// -//public class ConfiguredList extends CachedConfigValue> implements List { -// -// public static @NotNull ConfigListBuilder builderOf(@NotNull Class valueClass) { -// return builder().asList(valueClass); -// } -// -// public static @NotNull ConfiguredList of(@NotNull Class valueClass, @NotNull Collection defaults) { -// return builderOf(valueClass).fromObject().defaults(defaults).build(); -// } -// -// @SafeVarargs -// public static @NotNull ConfiguredList of(@NotNull Class valueClass, @NotNull V... defaults) { -// return builderOf(valueClass).fromObject().defaults(defaults).build(); -// } -// -// @SafeVarargs -// @SuppressWarnings("unchecked") -// public static @NotNull ConfiguredList of(@NotNull V defaultValue, @NotNull V... moreDefaults) { -// Collection values = new ArrayList<>(); -// values.add(defaultValue); -// values.addAll(Arrays.asList(moreDefaults)); -// return of((Class) defaultValue.getClass(), values); -// } -// -// protected final @NotNull Class valueClass; -// -// protected final @NotNull ConfigDataFunction parser; -// protected final @NotNull ConfigDataFunction serializer; -// -// public ConfiguredList(@NotNull ValueManifest> manifest, @NotNull Class valueClass, -// @NotNull ConfigDataFunction parser, -// @NotNull ConfigDataFunction serializer) { -// super(manifest); -// this.valueClass = valueClass; -// this.parser = parser; -// this.serializer = serializer; -// } -// -// @Override -// public @NotNull List get() { -// if (!isExpired()) return getCachedOrDefault(new ArrayList<>()); -// // Data that is outdated and needs to be parsed again. -// List list = new ArrayList<>(); -// List data = getConfiguration().contains(getConfigPath()) ? -// getConfiguration().getList(getConfigPath()) : null; -// if (data == null) return getDefaultFirst(list); -// for (Object dataVal : data) { -// if (dataVal == null) continue; -// try { -// list.add(parser.parse(dataVal)); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// return updateCache(list); -// } -// -// @Override -// public V get(int index) { -// return get().get(index); -// } -// -// public @NotNull List copy() { -// return new ArrayList<>(get()); -// } -// -// public @NotNull T handle(Function, T> function) { -// List list = get(); -// T result = function.apply(list); -// set(list); -// return result; -// } -// -// public @NotNull List modify(Consumer> consumer) { -// List list = get(); -// consumer.accept(list); -// set(list); -// return list; -// } -// -// @Override -// public void set(@Nullable List value) { -// updateCache(value); -// if (value == null) setValue(null); -// else { -// List data = new ArrayList<>(); -// for (V val : value) { -// if (val == null) continue; -// try { -// data.add(serializer.parse(val)); -// } catch (Exception ex) { -// ex.printStackTrace(); -// } -// } -// setValue(data); -// } -// } -// -// @Override -// public V set(int index, V element) { -// return handle(list -> list.set(index, element)); -// } -// -// @Override -// public int size() { -// return get().size(); -// } -// -// @Override -// public boolean isEmpty() { -// return get().isEmpty(); -// } -// -// @Override -// public boolean contains(Object o) { -// return get().contains(o); -// } -// -// @NotNull -// @Override -// public Iterator iterator() { -// return get().iterator(); -// } -// -// @NotNull -// @Override -// public Object @NotNull [] toArray() { -// return get().toArray(); -// } -// -// @NotNull -// @Override -// public T @NotNull [] toArray(@NotNull T[] a) { -// return get().toArray(a); -// } -// -// @Override -// public boolean containsAll(@NotNull Collection c) { -// return new HashSet<>(get()).containsAll(c); -// } -// -// @Override -// public boolean add(V v) { -// handle(list -> list.add(v)); -// return true; -// } -// -// @Override -// public void add(int index, V element) { -// modify(list -> list.add(index, element)); -// } -// -// @Override -// public boolean addAll(@NotNull Collection c) { -// return handle(list -> list.addAll(c)); -// } -// -// @Override -// public boolean addAll(int index, @NotNull Collection c) { -// return handle(list -> list.addAll(index, c)); -// } -// -// @Override -// public boolean remove(Object o) { -// return handle(list -> list.remove(o)); -// } -// -// @Override -// public V remove(int index) { -// return handle(list -> list.remove(index)); -// } -// -// @Override -// public boolean removeAll(@NotNull Collection c) { -// return handle(list -> list.removeAll(c)); -// } -// -// @Override -// public boolean retainAll(@NotNull Collection c) { -// return handle(list -> list.retainAll(c)); -// } -// -// @Override -// public void clear() { -// modify(List::clear); -// } -// -// @Override -// public int indexOf(Object o) { -// return get().indexOf(o); -// } -// -// @Override -// public int lastIndexOf(Object o) { -// return get().lastIndexOf(o); -// } -// -// @NotNull -// @Override -// public ListIterator listIterator() { -// return get().listIterator(); -// } -// -// @NotNull -// @Override -// public ListIterator listIterator(int index) { -// return get().listIterator(index); -// } -// -// @NotNull -// @Override -// public List subList(int fromIndex, int toIndex) { -// return get().subList(fromIndex, toIndex); -// } -// -//} +package cc.carm.lib.configuration.value.standard; + +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.value.ValueManifest; +import cc.carm.lib.configuration.value.impl.CachedConfigValue; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; + +public class ConfiguredList extends CachedConfigValue> implements List { + + protected final @NotNull ValueType valueType; + protected final @Nullable ValueParser parser; + protected final @Nullable ValueSerializer serializer; + + private ConfiguredList(@NotNull ValueManifest> manifest, @NotNull ValueType valueType, + @Nullable ValueParser parser, @Nullable ValueSerializer serializer) { + super(manifest); + this.valueType = valueType; + this.parser = parser; + this.serializer = serializer; + } + + /** + * @return Value's parser, parse base object to value. + */ + public @Nullable ValueParser parser() { + return parser; + } + + /** + * @return Value's serializer, parse value to base object. + */ + public @Nullable ValueSerializer serializer() { + return serializer; + } + + public @NotNull ValueType valueType() { + return valueType; + } + + @Override + public @NotNull List get() { + if (!isExpired()) return getCachedOrDefault(new ArrayList<>()); + // Data that is outdated and needs to be parsed again. + List list = new ArrayList<>(); + List data = config().contains(path()) ? config().getList(path()) : null; + if (data == null) return getDefaultFirst(list); + + ValueParser parser = this.parser; + if (parser == null) return getDefaultFirst(list); + + for (Object dataVal : data) { + if (dataVal == null) continue; + try { + list.add(parser.deserialize(provider(), valueType(), dataVal)); + } catch (Exception e) { + e.printStackTrace(); + } + } + return updateCache(list); + } + + @Override + public void set(@Nullable List value) { + updateCache(value); + if (value == null) { + setData(null); + return; + } + + ValueSerializer serializer = serializer(); + if (serializer == null) return; + List data = new ArrayList<>(); + for (V val : value) { + if (val == null) continue; + try { + data.add(serializer.serialize(provider(), valueType, val)); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + setData(data); + } + + @Override + public V get(int index) { + return getNotNull().get(index); + } + + public @NotNull List copy() { + return new ArrayList<>(getNotNull()); + } + + public @NotNull T handle(Function, T> function) { + List list = getNotNull(); + T result = function.apply(list); + set(list); + return result; + } + + public @NotNull ConfiguredList modify(Consumer> consumer) { + List list = getNotNull(); + consumer.accept(list); + set(list); + return this; + } + + @Override + public V set(int index, V element) { + return handle(list -> list.set(index, element)); + } + + @Override + public int size() { + return getNotNull().size(); + } + + @Override + public boolean isEmpty() { + return getNotNull().isEmpty(); + } + + @Override + public boolean contains(Object o) { + return getNotNull().contains(o); + } + + @NotNull + @Override + public Iterator iterator() { + return getNotNull().iterator(); + } + + @NotNull + @Override + public Object @NotNull [] toArray() { + return getNotNull().toArray(); + } + + @NotNull + @Override + public T @NotNull [] toArray(@NotNull T[] a) { + return getNotNull().toArray(a); + } + + @Override + public boolean containsAll(@NotNull Collection c) { + return new HashSet<>(getNotNull()).containsAll(c); + } + + @Override + public boolean add(V v) { + handle(list -> list.add(v)); + return true; + } + + @Override + public void add(int index, V element) { + modify(list -> list.add(index, element)); + } + + @Override + public boolean addAll(@NotNull Collection c) { + return handle(list -> list.addAll(c)); + } + + @Override + public boolean addAll(int index, @NotNull Collection c) { + return handle(list -> list.addAll(index, c)); + } + + @Override + public boolean remove(Object o) { + return handle(list -> list.remove(o)); + } + + @Override + public V remove(int index) { + return handle(list -> list.remove(index)); + } + + @Override + public boolean removeAll(@NotNull Collection c) { + return handle(list -> list.removeAll(c)); + } + + @Override + public boolean retainAll(@NotNull Collection c) { + return handle(list -> list.retainAll(c)); + } + + @Override + public void clear() { + modify(List::clear); + } + + @Override + public int indexOf(Object o) { + return getNotNull().indexOf(o); + } + + @Override + public int lastIndexOf(Object o) { + return getNotNull().lastIndexOf(o); + } + + @NotNull + @Override + public ListIterator listIterator() { + return getNotNull().listIterator(); + } + + @NotNull + @Override + public ListIterator listIterator(int index) { + return getNotNull().listIterator(index); + } + + @NotNull + @Override + public List subList(int fromIndex, int toIndex) { + return getNotNull().subList(fromIndex, toIndex); + } + +} \ No newline at end of file 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 deleted file mode 100644 index 1513734..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java +++ /dev/null @@ -1,27 +0,0 @@ -//package cc.carm.lib.configuration.value.standard; -// -//import cc.carm.lib.configuration.function.ConfigDataFunction; -//import cc.carm.lib.configuration.value.ValueManifest; -//import cc.carm.lib.configuration.value.impl.ConfigValueMap; -//import org.jetbrains.annotations.NotNull; -// -//import java.util.Map; -//import java.util.function.Supplier; -// -//public class ConfiguredMap extends ConfigValueMap { -// -// public ConfiguredMap(@NotNull ValueManifest> manifest, -// @NotNull Supplier> mapObjSupplier, -// @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, -// @NotNull Class valueClass, @NotNull ConfigDataFunction valueParser, -// @NotNull ConfigDataFunction keySerializer, -// @NotNull ConfigDataFunction valueSerializer) { -// super(manifest, Object.class, mapObjSupplier, keyClass, keyParser, valueClass, valueParser, keySerializer, valueSerializer); -// } -// -// @Override -// public Object getSource(ConfigurationWrapper section, String dataKey) { -// return section.get(dataKey); -// } -// -//} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java deleted file mode 100644 index 2630953..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSection.java +++ /dev/null @@ -1,96 +0,0 @@ -//package cc.carm.lib.configuration.value.standard; -// -//import cc.carm.lib.configuration.builder.value.SectionValueBuilder; -//import cc.carm.lib.configuration.function.ConfigDataFunction; -//import cc.carm.lib.configuration.function.ConfigValueParser; -//import cc.carm.lib.configuration.value.ValueManifest; -//import cc.carm.lib.configuration.value.impl.CachedConfigValue; -//import org.jetbrains.annotations.NotNull; -//import org.jetbrains.annotations.Nullable; -// -//import java.util.Map; -// -//public class ConfiguredSection extends CachedConfigValue { -// -// public static @NotNull SectionValueBuilder builderOf(@NotNull Class valueClass) { -// return builder().asValue(valueClass).fromSection(); -// } -// -// protected final @NotNull Class valueClass; -// -// protected final @NotNull ConfigValueParser, V> parser; -// protected final @NotNull ConfigDataFunction> serializer; -// -// public ConfiguredSection(@NotNull ValueManifest manifest, @NotNull Class valueClass, -// @NotNull ConfigValueParser, V> parser, -// @NotNull ConfigDataFunction> serializer) { -// super(manifest); -// this.valueClass = valueClass; -// this.parser = parser; -// this.serializer = serializer; -// } -// -// /** -// * @return Value's type class -// */ -// public @NotNull Class getValueClass() { -// return valueClass; -// } -// -// /** -// * @return Value's parser, cast value from section. -// */ -// public @NotNull ConfigValueParser, V> getParser() { -// return parser; -// } -// -// /** -// * @return Value's serializer, serialize value to section. -// */ -// public @NotNull ConfigDataFunction> getSerializer() { -// return serializer; -// } -// -// /** -// * @return Get the value that parsed from the configuration section. -// */ -// @Override -// public @Nullable V get() { -// if (!isExpired()) return getCachedOrDefault(); -// // Data that is outdated and needs to be parsed again. -// -// ConfigurationWrapper section = getConfiguration().getConfigurationSection(getConfigPath()); -// if (section == null) return getDefaultValue(); -// -// try { -// // If there are no errors, update the cache and return. -// return updateCache(this.parser.parse(section, this.defaultValue)); -// } catch (Exception e) { -// // There was a parsing error, prompted and returned the default value. -// e.printStackTrace(); -// return getDefaultValue(); -// } -// -// } -// -// /** -// * Use the specified value to update the configuration section. -// * Will use {@link #getSerializer()} to serialize the value to section. -// * -// * @param value The value that needs to be set in the configuration. -// */ -// @Override -// public void set(V value) { -// updateCache(value); -// if (value == null) setValue(null); -// else { -// try { -// setValue(serializer.parse(value)); -// } catch (Exception e) { -// e.printStackTrace(); -// } -// } -// } -// -// -//} diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java deleted file mode 100644 index 82434df..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredSectionMap.java +++ /dev/null @@ -1,31 +0,0 @@ -//package cc.carm.lib.configuration.value.standard; -// -//import cc.carm.lib.configuration.function.ConfigDataFunction; -//import cc.carm.lib.configuration.value.ValueManifest; -//import cc.carm.lib.configuration.value.impl.ConfigValueMap; -//import org.jetbrains.annotations.NotNull; -// -//import java.util.Map; -//import java.util.function.Supplier; -// -//public class ConfiguredSectionMap extends ConfigValueMap> { -// -// public ConfiguredSectionMap(@NotNull ValueManifest> manifest, -// @NotNull Supplier> mapObjSupplier, -// @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, -// @NotNull Class valueClass, @NotNull ConfigDataFunction, V> valueParser, -// @NotNull ConfigDataFunction keySerializer, -// @NotNull ConfigDataFunction> valueSerializer) { -// super( -// manifest, ConfigurationWrapper.class, mapObjSupplier, -// keyClass, keyParser, valueClass, valueParser, -// keySerializer, valueSerializer.andThen(s -> (Object) s) -// ); -// } -// -// @Override -// public ConfigurationWrapper getSource(ConfigurationWrapper section, String dataKey) { -// return section.getConfigurationSection(dataKey); -// } -// -//} 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 5117d26..d444034 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 @@ -1,62 +1,79 @@ package cc.carm.lib.configuration.value.standard; -import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.function.ConfigValueParser; +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.builder.value.ConfigValueBuilder; +import cc.carm.lib.configuration.source.ConfigurationProvider; import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; public class ConfiguredValue extends CachedConfigValue { -// public static ConfigValueBuilder builderOf(Class valueClass) { -// return builder().asValue(valueClass); -// } -// -// @SuppressWarnings("unchecked") -// public static ConfiguredValue of(@NotNull V defaultValue) { -// return of((Class) defaultValue.getClass(), defaultValue); -// } -// -// public static ConfiguredValue of(Class valueClass) { -// return of(valueClass, null); -// } -// -// public static ConfiguredValue of(Class valueClass, @Nullable V defaultValue) { -// return builderOf(valueClass).fromObject().defaults(defaultValue).build(); -// } + public static ConfigValueBuilder builderOf(@NotNull Class type) { + return new ConfigValueBuilder<>(ValueType.of(type)); + } - protected final @NotNull Class valueClass; + public static ConfigValueBuilder builderOf(@NotNull ValueType type) { + return new ConfigValueBuilder<>(type); + } - protected final @NotNull ConfigValueParser parser; - protected final @NotNull ConfigDataFunction serializer; + public static ConfiguredValue of(@NotNull V defaults) { + return of(ValueType.of(defaults), () -> defaults); + } - public ConfiguredValue(@NotNull ValueManifest manifest, @NotNull Class valueClass, - @NotNull ConfigValueParser parser, - @NotNull ConfigDataFunction serializer) { + public static ConfiguredValue of(@NotNull Class type) { + return of(ValueType.of(type), () -> null); + } + + public static ConfiguredValue of(@NotNull Class type, @NotNull Supplier<@Nullable V> defaultSupplier) { + return of(ValueType.of(type), defaultSupplier); + } + + public static ConfiguredValue of(@NotNull ValueType type) { + return of(type, () -> null); + } + + public static ConfiguredValue of(@NotNull ValueType type, @NotNull Supplier<@Nullable V> defaultSupplier) { + return of( + new ValueManifest<>(type, defaultSupplier), + (provider, t, data) -> provider.deserialize(type, data), + (provider, t, value) -> provider.serialize(value) + ); + } + + public static ConfiguredValue of(@NotNull ValueManifest manifest, + @Nullable ValueParser parser, + @Nullable ValueSerializer serializer) { + return new ConfiguredValue<>(manifest, parser, serializer); + } + + protected final @Nullable ValueParser parser; + protected final @Nullable ValueSerializer serializer; + + public ConfiguredValue(@NotNull ValueManifest manifest, + @Nullable ValueParser parser, + @Nullable ValueSerializer serializer) { super(manifest); - this.valueClass = valueClass; this.parser = parser; this.serializer = serializer; } /** - * @return Value's type class + * @return Value's parser, parse base object to value. */ - public @NotNull Class getValueClass() { - return valueClass; - } - - /** - * @return Value's parser, cast value from base object. - */ - public @NotNull ConfigValueParser getParser() { + public @Nullable ValueParser parser() { return parser; } /** - * @return Value's serializer, serialize value to base object. + * @return Value's serializer, parse value to base object. */ - public @NotNull ConfigDataFunction getSerializer() { + public @Nullable ValueSerializer serializer() { return serializer; } @@ -65,12 +82,15 @@ public class ConfiguredValue extends CachedConfigValue { if (!isExpired()) return getCachedOrDefault(); // Data that is outdated and needs to be parsed again. - Object value = getValue(); - if (value == null) return defaults(); + Object data = getData(); + if (data == null) return defaults(); + + ValueParser parser = parser(); + if (parser == null) return defaults(); // No parser, return default value. try { // If there are no errors, update the cache and return. - return updateCache(this.parser.parse(provider(), value, defaults())); + return updateCache(parser.deserialize(provider(), type(), data)); } catch (Exception e) { // There was a parsing error, prompted and returned the default value. e.printStackTrace(); @@ -81,21 +101,27 @@ public class ConfiguredValue extends CachedConfigValue { /** * Set the value of the configuration path. - * Will use {@link #getSerializer()} to serialize the value. + * Will use {@link #serializer()} to serialize the value. * * @param value The value to be set */ @Override public void set(V value) { - updateCache(value); - if (value == null) setValue(null); - else { - try { - setValue(serializer.parse(value)); - } catch (Exception e) { - e.printStackTrace(); - } + updateCache(value); // Update cache + if (value == null) { + setData(null); + return; } + + ValueSerializer serializer = serializer(); + if (serializer == null) return; // No serializer, do nothing. + + try { + setData(serializer.serialize(provider(), type(), value)); + } catch (Exception e) { + e.printStackTrace(); + } + } } diff --git a/core/src/main/old/ValueManifestv.java b/core/src/main/old/ValueManifestv.java deleted file mode 100644 index eb282ce..0000000 --- a/core/src/main/old/ValueManifestv.java +++ /dev/null @@ -1,123 +0,0 @@ -package cc.carm.lib.configuration.value; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Unmodifiable; - -import java.util.List; -import java.util.Optional; - -/** - * ConfigValue Manifests. - * The basic information that describes a configuration value. - * - * @param Value type - * @author CarmJos - */ -public class ValueManifest { - - public static ValueManifest of(@Nullable ConfigurationProvider provider, @Nullable String configPath, - @Nullable List headerComments, @Nullable String inlineComments) { - return new ValueManifest<>(provider, configPath, headerComments, inlineComments, null); - } - - public static ValueManifest of(@Nullable ConfigurationProvider provider, @Nullable String configPath, - @Nullable List headerComments, @Nullable String inlineComments, - @Nullable V defaultValue) { - return new ValueManifest<>(provider, configPath, headerComments, inlineComments, defaultValue); - } - - protected @Nullable ConfigurationProvider provider; - protected @Nullable String configPath; - - protected @Nullable List headerComments; - protected @Nullable String inlineComment; - - protected @Nullable T defaultValue; - - /** - * @param provider Provider of config files {@link ConfigurationProvider} - * @param configPath Config path of this value - * @param headerComments Header comment contents - * @param inlineComment Inline comment content - * @param defaultValue The default value - */ - public ValueManifest(@Nullable ConfigurationProvider provider, @Nullable String configPath, - @Nullable List headerComments, @Nullable String inlineComment, - @Nullable T defaultValue) { - this.provider = provider; - this.configPath = configPath; - this.headerComments = headerComments; - this.inlineComment = inlineComment; - this.defaultValue = defaultValue; - } - - /** - * The initialize method for {@link ConfigInitializer}, which is used to initialize the value. - * - * @param provider Provider of config files {@link ConfigurationProvider} - * @param configPath Config path of this value - * @param headerComments Header comment contents - * @param inlineComment Inline comment content - */ - protected void initialize(@NotNull ConfigurationProvider provider, @NotNull String configPath, - @Nullable List headerComments, @Nullable String inlineComment) { - if (this.provider == null) this.provider = provider; - if (this.configPath == null) this.configPath = configPath; - if (this.headerComments == null) this.headerComments = headerComments; - if (this.inlineComment == null) this.inlineComment = inlineComment; - - if (getHeaderComments() != null) { - this.provider.setHeaderComment(getConfigPath(), getHeaderComments()); - } - if (getInlineComment() != null) { - this.provider.setInlineComment(getConfigPath(), getInlineComment()); - } - } - - public @Nullable T getDefaultValue() { - return this.defaultValue; - } - - public void setDefaultValue(@Nullable T defaultValue) { - this.defaultValue = defaultValue; - } - - public @NotNull ConfigurationProvider getProvider() { - return Optional.ofNullable(this.provider) - .orElseThrow(() -> new IllegalStateException("Value(" + configPath + ") does not have a provider.")); - } - - public final @NotNull ConfigurationWrapper getConfiguration() { - try { - return getProvider().getConfiguration(); - } catch (Exception ex) { - throw new IllegalStateException("Value(" + configPath + ") has not been initialized", ex); - } - } - - public @NotNull String getConfigPath() { - return Optional.ofNullable(this.configPath) - .orElseThrow(() -> new IllegalStateException("No section path provided.")); - } - - protected Object getValue() { - String path = getConfigPath(); // 当未指定路径时,优先抛出异常 - return getConfiguration().get(path); - } - - protected void setValue(@Nullable Object value) { - getConfiguration().set(getConfigPath(), value); - } - - public @Nullable String getInlineComment() { - return inlineComment; - } - - @Unmodifiable - public @Nullable List getHeaderComments() { - return headerComments; - } - - -} diff --git a/core/src/main/old/builder/AbstractConfigBuilder.java b/core/src/main/old/builder/AbstractConfigBuilder.java index 25429ba..c8f2270 100644 --- a/core/src/main/old/builder/AbstractConfigBuilder.java +++ b/core/src/main/old/builder/AbstractConfigBuilder.java @@ -31,12 +31,12 @@ public abstract class AbstractConfigBuilder comments) { this.headerComments = comments; - return getThis(); + return self(); } public @NotNull B inlineComment(@NotNull String comment) { this.inlineComment = comment; - return getThis(); + return self(); } public @NotNull B defaults(@Nullable T defaultValue) { this.defaultValue = defaultValue; - return getThis(); + return self(); } public @NotNull B defaults(@NotNull Supplier<@Nullable T> defaultValueSupplier) { diff --git a/core/src/main/old/builder/ConfigBuilder.java b/core/src/main/old/builder/ConfigBuilder.java deleted file mode 100644 index 2dd7dc0..0000000 --- a/core/src/main/old/builder/ConfigBuilder.java +++ /dev/null @@ -1,43 +0,0 @@ -package cc.carm.lib.configuration.builder; - -import cc.carm.lib.configuration.builder.map.ConfigMapBuilder; -import cc.carm.lib.configuration.builder.map.ConfigMapCreator; -import cc.carm.lib.configuration.builder.list.ConfigListBuilder; -import cc.carm.lib.configuration.builder.value.ConfigValueBuilder; -import org.jetbrains.annotations.NotNull; - -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.TreeMap; - -public class ConfigBuilder { - - public @NotNull ConfigValueBuilder asValue(@NotNull Class valueClass) { - return new ConfigValueBuilder<>(valueClass); - } - - public @NotNull ConfigListBuilder asList(@NotNull Class valueClass) { - return new ConfigListBuilder<>(valueClass); - } - - public @NotNull ConfigMapCreator asMap(@NotNull Class keyClass, - @NotNull Class valueClass) { - return new ConfigMapCreator<>(keyClass, valueClass); - } - - public @NotNull ConfigMapBuilder, K, V> asHashMap(@NotNull Class keyClass, - @NotNull Class valueClass) { - return asMap(keyClass, valueClass).asHashMap(); - } - - public @NotNull ConfigMapBuilder, K, V> asLinkedMap(@NotNull Class keyClass, - @NotNull Class valueClass) { - return asMap(keyClass, valueClass).asLinkedMap(); - } - - public , V> @NotNull ConfigMapBuilder, K, V> asTreeMap(@NotNull Class keyClass, - @NotNull Class valueClass) { - return asMap(keyClass, valueClass).asTreeMap(); - } - -} diff --git a/core/src/main/old/builder/value/SectionValueBuilder.java b/core/src/main/old/builder/value/SectionValueBuilder.java index dbdf6de..4670fc8 100644 --- a/core/src/main/old/builder/value/SectionValueBuilder.java +++ b/core/src/main/old/builder/value/SectionValueBuilder.java @@ -3,7 +3,6 @@ package cc.carm.lib.configuration.builder.value; import cc.carm.lib.configuration.builder.CommonConfigBuilder; import cc.carm.lib.configuration.function.ConfigDataFunction; import cc.carm.lib.configuration.function.ConfigValueParser; -import cc.carm.lib.configuration.value.standard.ConfiguredSection; import org.jetbrains.annotations.NotNull; import java.util.Map; diff --git a/core/src/test/java/AdaptTest.java b/core/src/test/java/AdaptTest.java index e4cc97c..e1ede3a 100644 --- a/core/src/test/java/AdaptTest.java +++ b/core/src/test/java/AdaptTest.java @@ -1,14 +1,18 @@ import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; -import cc.carm.lib.configuration.adapter.strandard.EnumAdapter; +import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters; import cc.carm.lib.configuration.source.ConfigurationProvider; -import cc.carm.lib.configuration.loader.ConfigurationLoader; -import cc.carm.lib.easyoptions.OptionHolder; +import cc.carm.lib.configuration.source.loader.ConfigurationLoader; +import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; +import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.test.config.TestSource; import org.junit.Test; import java.time.Duration; +import java.time.LocalDate; import java.time.LocalTime; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class AdaptTest { @@ -16,42 +20,29 @@ public class AdaptTest { public void test() throws Exception { ValueAdapterRegistry registry = new ValueAdapterRegistry(); - registry.register(Long.class, PrimitiveAdapters.ofLong()); - registry.register(long.class, PrimitiveAdapters.ofLong()); - registry.register(Integer.class, PrimitiveAdapters.ofInteger()); - registry.register(int.class, PrimitiveAdapters.ofInteger()); - registry.register(Double.class, PrimitiveAdapters.ofDouble()); - registry.register(double.class, PrimitiveAdapters.ofDouble()); - registry.register(Float.class, PrimitiveAdapters.ofFloat()); - registry.register(float.class, PrimitiveAdapters.ofFloat()); - registry.register(Short.class, PrimitiveAdapters.ofShort()); - registry.register(short.class, PrimitiveAdapters.ofShort()); - registry.register(Byte.class, PrimitiveAdapters.ofByte()); - registry.register(byte.class, PrimitiveAdapters.ofByte()); - registry.register(Character.class, PrimitiveAdapters.ofCharacter()); - registry.register(char.class, PrimitiveAdapters.ofCharacter()); - registry.register(Boolean.class, PrimitiveAdapters.ofBoolean()); - registry.register(boolean.class, PrimitiveAdapters.ofBoolean()); - registry.register(String.class, PrimitiveAdapters.ofString()); - registry.register(new EnumAdapter()); + registry.register(PrimitiveAdapters.ADAPTERS); + registry.register(PrimitiveAdapters.ofEnum()); - registry.register(Long.class, Duration.class, Duration::ofSeconds, Duration::getSeconds); + + registry.register(ValueType.of(Long.class), ValueType.of(Duration.class), Duration::ofMillis, Duration::toMillis); registry.register( - Duration.class, LocalTime.class, + ValueType.of(Duration.class), ValueType.of(LocalTime.class), duration -> LocalTime.now().plus(duration), data -> Duration.between(LocalTime.now(), data) ); - ConfigurationProvider provider = new ConfigurationProvider<>(new TestSource(), new ConfigurationLoader(), registry, new OptionHolder()); + ConfigurationProvider provider = new ConfigurationProvider<>( + new TestSource(), new ConfigurationLoader(), + registry, new ConfigurationOptionHolder(), new ConcurrentHashMap<>() + ); - LocalTime v = registry.deserialize(provider, LocalTime.class, "600"); + LocalTime v = registry.deserialize(provider, LocalTime.class, 600000L); Object d = registry.serialize(provider, v); System.out.println(v); System.out.println(d); - System.out.println(registry.deserialize(provider, TestEnum.class, "b")); + System.out.println(registry.deserialize(provider, TestEnum.class, "C")); System.out.println(registry.serialize(provider, TestEnum.C).getClass()); - } enum TestEnum { diff --git a/core/src/test/java/NameTest.java b/core/src/test/java/NameTest.java index d1d09a9..604057c 100644 --- a/core/src/test/java/NameTest.java +++ b/core/src/test/java/NameTest.java @@ -1,4 +1,4 @@ -import cc.carm.lib.configuration.loader.PathGenerator; +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 aa3de0a..7210546 100644 --- a/core/src/test/java/cc/carm/test/config/LoaderTest.java +++ b/core/src/test/java/cc/carm/test/config/LoaderTest.java @@ -4,15 +4,17 @@ import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.source.ConfigurationProvider; -import cc.carm.lib.configuration.loader.ConfigurationLoader; -import cc.carm.lib.easyoptions.OptionHolder; +import cc.carm.lib.configuration.source.loader.ConfigurationLoader; +import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; import org.junit.Test; +import java.util.concurrent.ConcurrentHashMap; + public class LoaderTest { @Test public void test() throws Exception { - ConfigurationProvider provider = new ConfigurationProvider<>(new TestSource(), new ConfigurationLoader(), new ValueAdapterRegistry(), new OptionHolder()); + ConfigurationProvider provider = new ConfigurationProvider<>(new TestSource(), new ConfigurationLoader(), new ValueAdapterRegistry(), new ConfigurationOptionHolder(), new ConcurrentHashMap<>()); ConfigurationLoader loader = new ConfigurationLoader(); loader.load(provider, ROOT.class); 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 30247a3..c836e4c 100644 --- a/core/src/test/java/cc/carm/test/config/TestSource.java +++ b/core/src/test/java/cc/carm/test/config/TestSource.java @@ -1,7 +1,7 @@ package cc.carm.test.config; -import cc.carm.lib.configuration.source.ConfigurationSection; -import cc.carm.lib.configuration.source.ConfigurationSource; +import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.source.section.ConfigurationSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -16,7 +16,7 @@ public class TestSource extends ConfigurationSource> HEADER_COMMENTS = ValueMetaType.of(Collections.emptyList()); + PathMetadata> HEADER_COMMENTS = PathMetadata.of(Collections.emptyList()); /** * Configuration's {@link InlineComment} */ - ValueMetaType INLINE_COMMENT_VALUE = ValueMetaType.of(); + PathMetadata INLINE_COMMENT_VALUE = PathMetadata.of(); } diff --git a/features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java b/features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java index 3bc585b..1c8a413 100644 --- a/features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java +++ b/features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.option; -import cc.carm.lib.easyoptions.OptionType; +import cc.carm.lib.configuration.source.option.ConfigurationOption; public interface CommentableOptions { @@ -8,7 +8,7 @@ public interface CommentableOptions { * Whether to keep modified comments in configuration, * that means we only set comments for values that are not exists in configuration. */ - OptionType KEEP_COMMENTS = OptionType.of(true); + ConfigurationOption KEEP_COMMENTS = ConfigurationOption.of(true); /** * Whether to comment values name that are not exists in configuration and no default value offered. @@ -19,6 +19,6 @@ public interface CommentableOptions { * # foo: * */ - OptionType COMMENT_NO_DEFAULT = OptionType.of(true); + ConfigurationOption COMMENT_NO_DEFAULT = ConfigurationOption.of(true); } diff --git a/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java b/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java index 4868651..30741e7 100644 --- a/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java +++ b/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java @@ -1,15 +1,12 @@ package cc.carm.lib.configuration.option; -import cc.carm.lib.easyoptions.OptionType; - -import static cc.carm.lib.easyoptions.OptionType.of; +import cc.carm.lib.configuration.source.option.ConfigurationOption; public class FileConfigOptions { /** * Whether to copy files from resource if exists. */ - OptionType COPY_DEFAULTS = of(true); - + ConfigurationOption COPY_DEFAULTS = ConfigurationOption.of(true); } diff --git a/features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java b/features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java new file mode 100644 index 0000000..f10b3da --- /dev/null +++ b/features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java @@ -0,0 +1,21 @@ +package cc.carm.lib.configuration.source; + +import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; +import cc.carm.lib.configuration.meta.PathMetadata; +import cc.carm.lib.configuration.source.loader.ConfigurationLoader; +import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; +import cc.carm.lib.configuration.source.section.ConfigurationSource; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public abstract class FileProvider> extends ConfigurationProvider { + + public FileProvider(@NotNull S source, @NotNull ConfigurationLoader loader, + @NotNull ValueAdapterRegistry adapters, @NotNull ConfigurationOptionHolder options, + @NotNull Map, Object>> pathMetadata) { + super(source, loader, adapters, options, pathMetadata); + } + + +} diff --git a/pom.xml b/pom.xml index f2d2d0f..29de05d 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ - + providers/gson diff --git a/providers/gson/pom.xml b/providers/gson/pom.xml index df5abd9..9668214 100644 --- a/providers/gson/pom.xml +++ b/providers/gson/pom.xml @@ -27,6 +27,13 @@ compile + + ${project.parent.groupId} + easyconfiguration-feature-file + ${project.parent.version} + compile + + ${project.parent.groupId} easyconfiguration-demo diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigSource.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigSource.java new file mode 100644 index 0000000..d8e7d8e --- /dev/null +++ b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigSource.java @@ -0,0 +1,4 @@ +package cc.carm.lib.configuration.yaml; + +public class YAMLConfigSource { +} From 8ac1faf3009d17d15a6a7e4138e1c14f5505454e Mon Sep 17 00:00:00 2001 From: Carm Date: Sun, 2 Feb 2025 23:11:16 +0800 Subject: [PATCH 08/17] feat!(value): Finished the standard configured values --- .../configuration/adapter/ValueAdapter.java | 8 +- .../adapter/ValueAdapterRegistry.java | 10 +- .../configuration/adapter/ValueParser.java | 2 +- .../adapter/strandard/PrimitiveAdapters.java | 2 +- .../builder/value/ConfigValueBuilder.java | 34 +-- .../builder/value/SectionValueBuilder.java | 16 +- .../builder/value/SourceValueBuilder.java | 2 +- .../value/impl/CachedConfigValue.java | 23 ++ .../value/standard/ConfiguredList.java | 46 ++-- .../value/standard/ConfiguredMap.java | 196 ++++++++++++++++++ .../value/standard/ConfiguredValue.java | 34 +-- 11 files changed, 291 insertions(+), 82 deletions(-) create mode 100644 core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.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 6fe33a3..99ef7ef 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 @@ -38,7 +38,7 @@ public class ValueAdapter return serializer; } - public @Nullable ValueParser deserializer() { + public @Nullable ValueParser parser() { return deserializer; } @@ -46,7 +46,7 @@ public class ValueAdapter this.serializer = serializer; } - public void deserializer(@Nullable ValueParser deserializer) { + public void parser(@Nullable ValueParser deserializer) { this.deserializer = deserializer; } @@ -57,9 +57,9 @@ public class ValueAdapter } @Override - public TYPE deserialize(@NotNull ConfigurationProvider provider, @NotNull ValueType type, @NotNull Object value) throws Exception { + public TYPE parse(@NotNull ConfigurationProvider provider, @NotNull ValueType type, @NotNull Object value) throws Exception { if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported"); - return deserializer.deserialize(provider, type, value); + return deserializer.parse(provider, 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 3bb7e67..2864261 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 @@ -27,7 +27,7 @@ public class ValueAdapterRegistry { if (fromAdapter == null) throw new IllegalArgumentException("No adapter for type " + from); register(to, serializer == null ? null : (provider, type, value) -> fromAdapter.serialize(provider, from, serializer.handle(value)), - parser == null ? null : (provider, type, data) -> parser.handle(fromAdapter.deserialize(provider, from, data)) + parser == null ? null : (provider, type, data) -> parser.handle(fromAdapter.parse(provider, from, data)) ); } @@ -55,7 +55,7 @@ public class ValueAdapterRegistry { public void register(@NotNull ValueType type, @NotNull ValueParser deserializer) { ValueAdapter existing = adapterOf(type); if (existing != null) { - existing.deserializer(deserializer); + existing.parser(deserializer); } else { register(new ValueAdapter<>(type, null, deserializer)); } @@ -66,7 +66,7 @@ public class ValueAdapterRegistry { ValueAdapter existing = adapterOf(type); if (existing != null) { if (serializer != null) existing.serializer(serializer); - if (deserializer != null) existing.deserializer(deserializer); + if (deserializer != null) existing.parser(deserializer); } else { register(new ValueAdapter<>(type, serializer, deserializer)); } @@ -81,7 +81,7 @@ public class ValueAdapterRegistry { } @SuppressWarnings("unchecked") - public ValueAdapter adapterOf(@NotNull ValueType type) { + public @Nullable ValueAdapter adapterOf(@NotNull ValueType type) { ValueAdapter matched = adapters.stream().filter(adapter -> adapter.type().equals(type)).findFirst().orElse(null); if (matched != null) return (ValueAdapter) matched; @@ -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.deserialize(provider, type, source); + return adapter.parse(provider, type, source); } @Contract("_,null -> null") diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java index b35b089..d375456 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; @FunctionalInterface public interface ValueParser { - TYPE deserialize( + TYPE parse( @NotNull ConfigurationProvider provider, @NotNull ValueType type, @NotNull Object data ) throws Exception; diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java index f522bed..1017820 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java @@ -18,7 +18,7 @@ public class PrimitiveAdapters extends ValueAdapter { public static ValueAdapter> ofEnum() { ValueAdapter> adapter = new ValueAdapter<>(new ValueType>() { }); - adapter.deserializer((provider, type, data) -> Enum.valueOf((Class) type.getRawType(), data.toString())); + adapter.parser((provider, type, data) -> Enum.valueOf((Class) type.getRawType(), data.toString())); adapter.serializer((provider, type, value) -> value.name()); return adapter; } 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 113fabf..5a41e9a 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 @@ -34,44 +34,12 @@ public class ConfigValueBuilder { return from(String.class); } - public @NotNull SourceValueBuilder fromInteger() { - return from(Integer.class); - } - - public @NotNull SourceValueBuilder fromLong() { - return from(Long.class); - } - - public @NotNull SourceValueBuilder fromDouble() { - return from(Double.class); - } - - public @NotNull SourceValueBuilder fromFloat() { - return from(Float.class); - } - - public @NotNull SourceValueBuilder fromBoolean() { - return from(Boolean.class); - } - - public @NotNull SourceValueBuilder fromCharacter() { - return from(Character.class); - } - - public @NotNull SourceValueBuilder fromByte() { - return from(Byte.class); - } - - public @NotNull SourceValueBuilder fromShort() { - return from(Short.class); - } - public @NotNull SectionValueBuilder fromSection() { return new SectionValueBuilder<>(this.type); } public @NotNull SectionValueBuilder fromSection(@NotNull ConfigValueHandler valueParser, - @NotNull ConfigValueHandler> valueSerializer) { + @NotNull ConfigValueHandler> 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 a4a4dae..1dc7f5b 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 @@ -17,7 +17,7 @@ public class SectionValueBuilder extends CommonConfigBuilder valueType; protected @NotNull ConfigValueHandler parser; - protected @NotNull ConfigValueHandler> serializer; + protected @NotNull ConfigValueHandler> serializer; public SectionValueBuilder(@NotNull ValueType valueType) { this(valueType, ConfigValueHandler.required(), ConfigValueHandler.required()); @@ -25,7 +25,7 @@ public class SectionValueBuilder extends CommonConfigBuilder valueType, @NotNull ConfigValueHandler parser, - @NotNull ConfigValueHandler> serializer) { + @NotNull ConfigValueHandler> serializer) { this.valueType = valueType; this.parser = parser; this.serializer = serializer; @@ -45,18 +45,18 @@ public class SectionValueBuilder extends CommonConfigBuilder serialize(ConfigDataFunction> serializer) { + public @NotNull SectionValueBuilder serialize(ConfigDataFunction> serializer) { return serialize((p, value) -> serializer.handle(value)); } - public @NotNull SectionValueBuilder serialize(ConfigValueHandler> serializer) { + public @NotNull SectionValueBuilder serialize(ConfigValueHandler> serializer) { this.serializer = serializer; return this; } - public @NotNull SectionValueBuilder serialize(Consumer> serializer) { + public @NotNull SectionValueBuilder serialize(Consumer> serializer) { return serialize((p, value) -> { - Map map = new LinkedHashMap<>(); + Map map = new LinkedHashMap<>(); serializer.accept(map); return map; }); @@ -64,7 +64,7 @@ public class SectionValueBuilder extends CommonConfigBuilder build() { - return new ConfiguredValue<>( + return ConfiguredValue.of( buildManifest(), (p, type, data) -> { ConfigurationSection section = p.deserialize(ConfigurationSection.class, data); @@ -72,7 +72,7 @@ public class SectionValueBuilder extends CommonConfigBuilder { - Map map = this.serializer.handle(p, data); + Map map = this.serializer.handle(p, data); return map == null || map.isEmpty() ? null : map; // Map is a type of original data } ); diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java index fd8bc29..aa8dd88 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java @@ -52,7 +52,7 @@ public class SourceValueBuilder extends CommonConfigBuilder build() { - return new ConfiguredValue<>( + return ConfiguredValue.of( buildManifest(), (p, type, data) -> { S source = p.deserialize(this.sourceType, data); diff --git a/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java index 13b852d..7f52e43 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java @@ -1,5 +1,8 @@ package cc.carm.lib.configuration.value.impl; +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.value.ConfigValue; import cc.carm.lib.configuration.value.ValueManifest; import org.jetbrains.annotations.Contract; @@ -55,4 +58,24 @@ public abstract class CachedConfigValue extends ConfigValue { else return emptyValue; } + /** + * @return Value's parser, parse base object to value. + */ + protected @Nullable ValueParser parserFor(@NotNull ValueAdapter adapter) { + if (adapter.parser() != null) return adapter.parser(); + ValueAdapter registered = provider().adapters().adapterOf(adapter.type()); + if (registered == null) return null; + return registered.parser(); + } + + /** + * @return Value's serializer, parse value to base object. + */ + protected @Nullable ValueSerializer serializerFor(@NotNull ValueAdapter adapter) { + if (adapter.serializer() != null) return adapter.serializer(); + ValueAdapter registered = provider().adapters().adapterOf(adapter.type()); + if (registered == null) return null; + return registered.serializer(); + } + } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java index e5907ff..e76718d 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java @@ -1,5 +1,6 @@ package cc.carm.lib.configuration.value.standard; +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; @@ -11,54 +12,65 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; public class ConfiguredList extends CachedConfigValue> implements List { - protected final @NotNull ValueType valueType; - protected final @Nullable ValueParser parser; - protected final @Nullable ValueSerializer serializer; + protected final @NotNull Supplier> constructor; + protected final @NotNull ValueAdapter paramAdapter; - private ConfiguredList(@NotNull ValueManifest> manifest, @NotNull ValueType valueType, - @Nullable ValueParser parser, @Nullable ValueSerializer serializer) { + private ConfiguredList(@NotNull ValueManifest> manifest, + @NotNull Supplier> constructor, + @NotNull ValueAdapter paramAdapter) { super(manifest); - this.valueType = valueType; - this.parser = parser; - this.serializer = serializer; + this.constructor = constructor; + this.paramAdapter = paramAdapter; + } + + /** + * @return Adapter of this value. + */ + public @NotNull ValueAdapter adapter() { + return this.paramAdapter; + } + + public @NotNull ValueType paramType() { + return adapter().type(); } /** * @return Value's parser, parse base object to value. */ public @Nullable ValueParser parser() { - return parser; + return parserFor(adapter()); } /** * @return Value's serializer, parse value to base object. */ public @Nullable ValueSerializer serializer() { - return serializer; + return serializerFor(adapter()); } - public @NotNull ValueType valueType() { - return valueType; + private @NotNull List createList() { + return constructor.get(); } @Override public @NotNull List get() { - if (!isExpired()) return getCachedOrDefault(new ArrayList<>()); + if (!isExpired()) return getCachedOrDefault(createList()); // Data that is outdated and needs to be parsed again. - List list = new ArrayList<>(); + List list = createList(); List data = config().contains(path()) ? config().getList(path()) : null; if (data == null) return getDefaultFirst(list); - ValueParser parser = this.parser; + ValueParser parser = parser(); if (parser == null) return getDefaultFirst(list); for (Object dataVal : data) { if (dataVal == null) continue; try { - list.add(parser.deserialize(provider(), valueType(), dataVal)); + list.add(parser.parse(provider(), paramType(), dataVal)); } catch (Exception e) { e.printStackTrace(); } @@ -80,7 +92,7 @@ public class ConfiguredList extends CachedConfigValue> implements Lis for (V val : value) { if (val == null) continue; try { - data.add(serializer.serialize(provider(), valueType, val)); + data.add(serializer.serialize(provider(), paramType(), val)); } catch (Exception ex) { ex.printStackTrace(); } 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 new file mode 100644 index 0000000..4eb4a1d --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredMap.java @@ -0,0 +1,196 @@ +package cc.carm.lib.configuration.value.standard; + +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.value.ValueManifest; +import cc.carm.lib.configuration.value.impl.CachedConfigValue; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; + +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +public class ConfiguredMap extends CachedConfigValue> implements Map { + + protected final @NotNull Supplier> constructor; + + protected final @NotNull ValueAdapter keyAdapter; + protected final @NotNull ValueAdapter valueAdapter; + + protected ConfiguredMap(@NotNull ValueManifest> manifest, + @NotNull Supplier> constructor, + @NotNull ValueAdapter keyAdapter, @NotNull ValueAdapter valueAdapter) { + super(manifest); + this.constructor = constructor; + this.keyAdapter = keyAdapter; + this.valueAdapter = valueAdapter; + } + + public @NotNull ValueAdapter keyAdapter() { + return keyAdapter; + } + + public @NotNull ValueType keyType() { + return keyAdapter().type(); + } + + public @NotNull ValueAdapter valueAdapter() { + return valueAdapter; + } + + public @NotNull ValueType valueType() { + return valueAdapter().type(); + } + + private Map createMap() { + return this.constructor.get(); + } + + @Override + public @NotNull Map get() { + if (!isExpired()) return getCachedOrDefault(createMap()); + // If the value is expired, we need to update it + Map map = createMap(); + + ConfigurationSection section = config().getSection(path()); + if (section == null) return getDefaultFirst(map); + + Set keys = section.getKeys(false); + if (keys.isEmpty()) return getDefaultFirst(map); + + ValueParser keyParser = parserFor(keyAdapter); + ValueParser valueParser = parserFor(valueAdapter); + if (keyParser == null || valueParser == null) return getDefaultFirst(map); + + for (String dataKey : keys) { + Object dataVal = section.get(dataKey); + if (dataVal == null) continue; + try { + K key = keyParser.parse(provider(), keyType(), dataKey); + V value = valueParser.parse(provider(), valueType(), dataVal); + map.put(key, value); + } catch (Exception e) { + e.printStackTrace(); + } + } + + return updateCache(map); + } + + @Override + public V get(Object key) { + return get().get(key); + } + + public V getNotNull(Object key) { + return Objects.requireNonNull(get(key)); + } + + @Override + public void set(@Nullable Map value) { + updateCache(value); + if (value == null) { + setData(null); + return; + } + + ValueSerializer keySerializer = serializerFor(keyAdapter); + ValueSerializer valueSerializer = serializerFor(valueAdapter); + if (keySerializer == null || valueSerializer == null) return; + + Map data = new LinkedHashMap<>(); + + for (Map.Entry entry : value.entrySet()) { + try { + data.put( + keySerializer.serialize(provider(), keyType(), entry.getKey()), + valueSerializer.serialize(provider(), valueType(), entry.getValue()) + ); + } catch (Exception e) { + e.printStackTrace(); + } + } + setData(data); + } + + public @NotNull T handle(Function, T> function) { + Map m = get(); + T result = function.apply(m); + set(m); + return result; + } + + public @NotNull ConfiguredMap modify(Consumer> consumer) { + Map m = get(); + consumer.accept(m); + set(m); + return this; + } + + @Override + public int size() { + return get().size(); + } + + @Override + public boolean isEmpty() { + return get().isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return get().containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return get().containsValue(value); + } + + @Nullable + @Override + public V put(K key, V value) { + return handle(m -> m.put(key, value)); + } + + @Override + public V remove(Object key) { + return handle(m -> m.remove(key)); + } + + @Override + public void putAll(@NotNull Map m) { + modify(map -> map.putAll(m)); + } + + @Override + public void clear() { + modify(Map::clear); + } + + @NotNull + @Override + public Set keySet() { + return get().keySet(); + } + + @NotNull + @Override + public Collection values() { + return get().values(); + } + + @NotNull + @Override + @Unmodifiable + public Set> entrySet() { + return get().entrySet(); + } + +} 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 d444034..8df3683 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 @@ -1,10 +1,10 @@ package cc.carm.lib.configuration.value.standard; +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.builder.value.ConfigValueBuilder; -import cc.carm.lib.configuration.source.ConfigurationProvider; import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; @@ -49,32 +49,42 @@ public class ConfiguredValue extends CachedConfigValue { public static ConfiguredValue of(@NotNull ValueManifest manifest, @Nullable ValueParser parser, @Nullable ValueSerializer serializer) { - return new ConfiguredValue<>(manifest, parser, serializer); + ValueAdapter adapter = new ValueAdapter<>(manifest.type()); + adapter.parser(parser); + adapter.serializer(serializer); + return of(manifest, adapter); } - protected final @Nullable ValueParser parser; - protected final @Nullable ValueSerializer serializer; + public static ConfiguredValue of(@NotNull ValueManifest manifest, @NotNull ValueAdapter adapter) { + return new ConfiguredValue<>(manifest, adapter); + } - public ConfiguredValue(@NotNull ValueManifest manifest, - @Nullable ValueParser parser, - @Nullable ValueSerializer serializer) { + protected final @NotNull ValueAdapter adapter; + + public ConfiguredValue(@NotNull ValueManifest manifest, @NotNull ValueAdapter adapter) { super(manifest); - this.parser = parser; - this.serializer = serializer; + this.adapter = adapter; + } + + /** + * @return Adapter of this value. + */ + public @NotNull ValueAdapter adapter() { + return adapter; } /** * @return Value's parser, parse base object to value. */ public @Nullable ValueParser parser() { - return parser; + return parserFor(adapter()); } /** * @return Value's serializer, parse value to base object. */ public @Nullable ValueSerializer serializer() { - return serializer; + return serializerFor(adapter()); } @Override @@ -90,7 +100,7 @@ public class ConfiguredValue extends CachedConfigValue { try { // If there are no errors, update the cache and return. - return updateCache(parser.deserialize(provider(), type(), data)); + return updateCache(parser.parse(provider(), type(), data)); } catch (Exception e) { // There was a parsing error, prompted and returned the default value. e.printStackTrace(); From 205db6e5b9e465322ac19067bb88717ac1051cc8 Mon Sep 17 00:00:00 2001 From: Carm Date: Sun, 2 Feb 2025 23:59:13 +0800 Subject: [PATCH 09/17] feat!(value): Finished the standard configured values --- .../configuration/adapter/ValueAdapter.java | 10 +- .../builder/AbstractConfigBuilder.java | 36 +++--- .../builder/CommonConfigBuilder.java | 10 +- .../builder/impl/AbstractSectionBuilder.java | 74 ++++++++++++ .../builder/impl/AbstractSourceBuilder.java | 63 +++++++++++ .../builder/list/ConfigListBuilder.java | 34 ++++++ .../builder/list/SectionListBuilder.java | 53 +++++++++ .../builder/list/SourceListBuilder.java | 47 ++++++++ .../builder/value/ConfigValueBuilder.java | 13 ++- .../builder/value/SectionValueBuilder.java | 61 +--------- .../builder/value/SourceValueBuilder.java | 51 +-------- .../value/standard/ConfiguredList.java | 15 ++- .../old/builder/AbstractConfigBuilder.java | 76 ------------- .../main/old/builder/CommonConfigBuilder.java | 10 -- .../old/builder/list/ConfigListBuilder.java | 58 ---------- .../old/builder/list/SourceListBuilder.java | 80 ------------- .../old/builder/map/ConfigMapBuilder.java | 68 ----------- .../old/builder/map/ConfigMapCreator.java | 38 ------- .../old/builder/map/SectionMapBuilder.java | 98 ---------------- .../old/builder/map/SourceMapBuilder.java | 107 ------------------ .../old/builder/value/ConfigValueBuilder.java | 63 ----------- .../builder/value/SectionValueBuilder.java | 52 --------- .../old/builder/value/SourceValueBuilder.java | 70 ------------ 23 files changed, 335 insertions(+), 852 deletions(-) create mode 100644 core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSectionBuilder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSourceBuilder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/builder/list/ConfigListBuilder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/builder/list/SectionListBuilder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/builder/list/SourceListBuilder.java delete mode 100644 core/src/main/old/builder/AbstractConfigBuilder.java delete mode 100644 core/src/main/old/builder/CommonConfigBuilder.java delete mode 100644 core/src/main/old/builder/list/ConfigListBuilder.java delete mode 100644 core/src/main/old/builder/list/SourceListBuilder.java delete mode 100644 core/src/main/old/builder/map/ConfigMapBuilder.java delete mode 100644 core/src/main/old/builder/map/ConfigMapCreator.java delete mode 100644 core/src/main/old/builder/map/SectionMapBuilder.java delete mode 100644 core/src/main/old/builder/map/SourceMapBuilder.java delete mode 100644 core/src/main/old/builder/value/ConfigValueBuilder.java delete mode 100644 core/src/main/old/builder/value/SectionValueBuilder.java delete mode 100644 core/src/main/old/builder/value/SourceValueBuilder.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 99ef7ef..9785e04 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 @@ -24,10 +24,10 @@ public class ValueAdapter public ValueAdapter(@NotNull ValueType type, @Nullable ValueSerializer serializer, - @Nullable ValueParser deserializer) { + @Nullable ValueParser parser) { this.type = type; this.serializer = serializer; - this.deserializer = deserializer; + this.deserializer = parser; } public @NotNull ValueType type() { @@ -42,12 +42,14 @@ public class ValueAdapter return deserializer; } - public void serializer(@Nullable ValueSerializer serializer) { + public ValueAdapter serializer(@Nullable ValueSerializer serializer) { this.serializer = serializer; + return this; } - public void parser(@Nullable ValueParser deserializer) { + public ValueAdapter parser(@Nullable ValueParser deserializer) { this.deserializer = deserializer; + return this; } @Override diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java index 0481d70..1d466de 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java @@ -1,5 +1,6 @@ package cc.carm.lib.configuration.builder; +import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.source.ConfigurationProvider; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ValueManifest; @@ -8,44 +9,53 @@ import org.jetbrains.annotations.Nullable; import java.util.function.Supplier; -public abstract class AbstractConfigBuilder, P extends ConfigurationProvider> { +public abstract class AbstractConfigBuilder< + TYPE, RESULT extends ConfigValue, PROVIDER extends ConfigurationProvider, + SELF extends AbstractConfigBuilder + > { - protected final Class providerClass; + protected final Class providerClass; + protected final ValueType type; - protected @Nullable P provider; + protected @Nullable PROVIDER provider; protected @Nullable String path; - protected @NotNull Supplier defaultValueSupplier = () -> null; + protected @NotNull Supplier defaultValueSupplier = () -> null; - protected AbstractConfigBuilder(Class providerClass) { + protected AbstractConfigBuilder(Class providerClass, ValueType type) { this.providerClass = providerClass; + this.type = type; } - protected abstract @NotNull B self(); + public @NotNull ValueType type() { + return type; + } - public abstract @NotNull ConfigValue build(); + protected abstract @NotNull SELF self(); - public @NotNull B from(@Nullable P provider) { + public abstract @NotNull RESULT build(); + + public @NotNull SELF from(@Nullable PROVIDER provider) { this.provider = provider; return self(); } - public @NotNull B path(@Nullable String path) { + public @NotNull SELF path(@Nullable String path) { this.path = path; return self(); } - public @NotNull B defaults(@Nullable T defaultValue) { + public @NotNull SELF defaults(@Nullable TYPE defaultValue) { return defaults(() -> defaultValue); } - public @NotNull B defaults(@NotNull Supplier<@Nullable T> supplier) { + public @NotNull SELF defaults(@NotNull Supplier<@Nullable TYPE> supplier) { this.defaultValueSupplier = supplier; return self(); } - protected @NotNull ValueManifest buildManifest() { - return null; + protected @NotNull ValueManifest buildManifest() { + return new ValueManifest<>(type(), this.provider, this.path, this.defaultValueSupplier); } } diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java index 10a1fe1..1d52039 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java @@ -1,12 +1,14 @@ package cc.carm.lib.configuration.builder; +import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.value.ConfigValue; -public abstract class CommonConfigBuilder> - extends AbstractConfigBuilder> { +public abstract class CommonConfigBuilder, SELF extends CommonConfigBuilder> + extends AbstractConfigBuilder, SELF> { - protected CommonConfigBuilder() { - super(ConfigurationProvider.class); + protected CommonConfigBuilder(ValueType type) { + super(ConfigurationProvider.class, type); } } 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 new file mode 100644 index 0000000..91879d3 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSectionBuilder.java @@ -0,0 +1,74 @@ +package cc.carm.lib.configuration.builder.impl; + +import cc.carm.lib.configuration.adapter.ValueAdapter; +import cc.carm.lib.configuration.adapter.ValueType; +import cc.carm.lib.configuration.builder.CommonConfigBuilder; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.value.ConfigValue; +import org.jetbrains.annotations.NotNull; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Consumer; + +public abstract class AbstractSectionBuilder< + TYPE, PARAM, + RESULT extends ConfigValue, + SELF extends AbstractSectionBuilder + > extends CommonConfigBuilder { + + protected final @NotNull ValueType paramType; + + protected @NotNull ConfigValueHandler parser; + protected @NotNull ConfigValueHandler> serializer; + + public AbstractSectionBuilder(@NotNull ValueType type, @NotNull ValueType paramType, + @NotNull ConfigValueHandler parser, + @NotNull ConfigValueHandler> serializer) { + super(type); + this.paramType = paramType; + this.parser = parser; + this.serializer = serializer; + } + + public @NotNull SELF parse(ConfigDataFunction valueParser) { + return parse((p, section) -> valueParser.handle(section)); + } + + public @NotNull SELF parse(ConfigValueHandler valueParser) { + this.parser = valueParser; + return self(); + } + + public @NotNull SELF serialize(ConfigDataFunction> serializer) { + return serialize((p, value) -> serializer.handle(value)); + } + + public @NotNull SELF serialize(ConfigValueHandler> serializer) { + this.serializer = serializer; + return self(); + } + + public @NotNull SELF serialize(Consumer> serializer) { + return serialize((p, value) -> { + Map map = new LinkedHashMap<>(); + serializer.accept(map); + return map; + }); + } + + protected ValueAdapter buildAdapter() { + return new ValueAdapter<>(this.paramType) + .parser((p, type, data) -> { + ConfigurationSection section = p.deserialize(ConfigurationSection.class, data); + if (section == null) return null; + return this.parser.handle(p, section); + }) + .serializer((p, type, 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 new file mode 100644 index 0000000..a9830d3 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/builder/impl/AbstractSourceBuilder.java @@ -0,0 +1,63 @@ +package cc.carm.lib.configuration.builder.impl; + +import cc.carm.lib.configuration.adapter.ValueAdapter; +import cc.carm.lib.configuration.adapter.ValueType; +import cc.carm.lib.configuration.builder.CommonConfigBuilder; +import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.value.ConfigValue; +import org.jetbrains.annotations.NotNull; + +public abstract class AbstractSourceBuilder< + V, SOURCE, PARAM, RESULT extends ConfigValue, + SELF extends AbstractSourceBuilder + > extends CommonConfigBuilder { + + protected final @NotNull ValueType sourceType; + protected final @NotNull ValueType paramType; + protected @NotNull ConfigValueHandler valueParser; + protected @NotNull ConfigValueHandler valueSerializer; + + public AbstractSourceBuilder(@NotNull ValueType type, + @NotNull ValueType sourceType, @NotNull ValueType paramType, + @NotNull ConfigValueHandler parser, + @NotNull ConfigValueHandler serializer) { + super(type); + this.sourceType = sourceType; + this.paramType = paramType; + this.valueParser = parser; + this.valueSerializer = serializer; + } + + public @NotNull SELF parse(ConfigDataFunction parser) { + return parse((p, source) -> parser.handle(source)); + } + + public @NotNull SELF parse(@NotNull ConfigValueHandler parser) { + this.valueParser = parser; + return self(); + } + + public @NotNull SELF serialize(@NotNull ConfigValueHandler serializer) { + this.valueSerializer = serializer; + return self(); + } + + public @NotNull SELF serialize(@NotNull ConfigDataFunction serializer) { + return serialize((p, value) -> serializer.handle(value)); + } + + 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); + }) + .serializer((p, type, data) -> { + SOURCE source = this.valueSerializer.handle(p, data); + return p.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 new file mode 100644 index 0000000..cd7e8f1 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/builder/list/ConfigListBuilder.java @@ -0,0 +1,34 @@ +package cc.carm.lib.configuration.builder.list; + +import cc.carm.lib.configuration.adapter.ValueType; +import cc.carm.lib.configuration.function.ConfigValueHandler; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; + +public class ConfigListBuilder { + + protected final @NotNull ValueType type; + + public ConfigListBuilder(@NotNull ValueType type) { + this.type = type; + } + + public @NotNull SourceListBuilder from(@NotNull Class sourceType) { + return from(ValueType.of(sourceType)); + } + + public @NotNull SourceListBuilder from(@NotNull ValueType sourceType) { + return new SourceListBuilder<>(sourceType, type, ConfigValueHandler.required(), ConfigValueHandler.required(), ArrayList::new); + } + + public @NotNull SourceListBuilder fromString() { + return from(String.class); + } + + public @NotNull SectionListBuilder fromSection() { + return new SectionListBuilder<>(type, ConfigValueHandler.required(), ConfigValueHandler.required(), ArrayList::new); + } + + +} 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 new file mode 100644 index 0000000..d808a01 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/builder/list/SectionListBuilder.java @@ -0,0 +1,53 @@ +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.ConfigValueHandler; +import cc.carm.lib.configuration.source.section.ConfigurationSection; +import cc.carm.lib.configuration.value.standard.ConfiguredList; +import org.jetbrains.annotations.NotNull; + +import java.util.*; +import java.util.function.Supplier; + +public class SectionListBuilder extends AbstractSectionBuilder, V, ConfiguredList, SectionListBuilder> { + + protected @NotNull Supplier> constructor; + + public SectionListBuilder(@NotNull ValueType paramType, + @NotNull ConfigValueHandler parser, + @NotNull ConfigValueHandler> serializer, + @NotNull Supplier> constructor) { + super(new ValueType>() { + }, paramType, parser, serializer); + this.constructor = constructor; + } + + @SafeVarargs + public final @NotNull SectionListBuilder defaults(@NotNull V... values) { + return defaults(new ArrayList<>(Arrays.asList(values))); + } + + public final @NotNull SectionListBuilder defaults(@NotNull Collection values) { + return defaults(new ArrayList<>(values)); + } + + public SectionListBuilder constructor(@NotNull Supplier> constructor) { + this.constructor = constructor; + return this; + } + + public > SectionListBuilder construct(@NotNull LIST list) { + return constructor(() -> list); + } + + @Override + protected @NotNull SectionListBuilder self() { + return this; + } + + @Override + public @NotNull ConfiguredList build() { + return new ConfiguredList<>(buildManifest(), constructor, buildAdapter()); + } +} diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/list/SourceListBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/list/SourceListBuilder.java new file mode 100644 index 0000000..bb73610 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/builder/list/SourceListBuilder.java @@ -0,0 +1,47 @@ +package cc.carm.lib.configuration.builder.list; + +import cc.carm.lib.configuration.adapter.ValueType; +import cc.carm.lib.configuration.builder.impl.AbstractSourceBuilder; +import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.value.standard.ConfiguredList; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.function.Supplier; + +public class SourceListBuilder + extends AbstractSourceBuilder, SOURCE, V, ConfiguredList, SourceListBuilder> { + + protected @NotNull Supplier> constructor; + + public SourceListBuilder(@NotNull ValueType sourceType, @NotNull ValueType paramType, + @NotNull ConfigValueHandler parser, @NotNull ConfigValueHandler serializer, + @NotNull Supplier> constructor) { + super(new ValueType>() { + }, sourceType, paramType, parser, serializer); + this.constructor = constructor; + } + + @SafeVarargs + public final @NotNull SourceListBuilder defaults(@NotNull V... values) { + return defaults(new ArrayList<>(Arrays.asList(values))); + } + + public final @NotNull SourceListBuilder defaults(@NotNull Collection values) { + return defaults(new ArrayList<>(values)); + } + + @Override + protected @NotNull SourceListBuilder self() { + return this; + } + + @Override + public @NotNull ConfiguredList build() { + return new ConfiguredList<>(buildManifest(), this.constructor, buildAdapter()); + } + +} 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 5a41e9a..b9447d0 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 @@ -1,7 +1,6 @@ package cc.carm.lib.configuration.builder.value; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.function.ConfigDataFunction; import cc.carm.lib.configuration.function.ConfigValueHandler; import cc.carm.lib.configuration.source.section.ConfigurationSection; import org.jetbrains.annotations.NotNull; @@ -17,11 +16,11 @@ public class ConfigValueBuilder { } public @NotNull SourceValueBuilder from(@NotNull Class clazz) { - return new SourceValueBuilder<>(ValueType.of(clazz), this.type); + return from(ValueType.of(clazz)); } public @NotNull SourceValueBuilder from(@NotNull ValueType sourceType) { - return new SourceValueBuilder<>(sourceType, this.type); + return from(sourceType, ConfigValueHandler.required(), ConfigValueHandler.required()); } public @NotNull SourceValueBuilder from(@NotNull ValueType sourceType, @@ -35,11 +34,13 @@ public class ConfigValueBuilder { } public @NotNull SectionValueBuilder fromSection() { - return new SectionValueBuilder<>(this.type); + return fromSection(ConfigValueHandler.required(), ConfigValueHandler.required()); } - public @NotNull SectionValueBuilder fromSection(@NotNull ConfigValueHandler valueParser, - @NotNull ConfigValueHandler> valueSerializer) { + public @NotNull SectionValueBuilder fromSection( + @NotNull ConfigValueHandler valueParser, + @NotNull ConfigValueHandler> 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 1dc7f5b..5d6577a 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 @@ -1,34 +1,20 @@ package cc.carm.lib.configuration.builder.value; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.builder.impl.AbstractSectionBuilder; import cc.carm.lib.configuration.function.ConfigValueHandler; import cc.carm.lib.configuration.source.section.ConfigurationSection; import cc.carm.lib.configuration.value.standard.ConfiguredValue; import org.jetbrains.annotations.NotNull; -import java.util.LinkedHashMap; import java.util.Map; -import java.util.function.Consumer; -public class SectionValueBuilder extends CommonConfigBuilder> { +public class SectionValueBuilder extends AbstractSectionBuilder, SectionValueBuilder> { - protected final @NotNull ValueType valueType; - - protected @NotNull ConfigValueHandler parser; - protected @NotNull ConfigValueHandler> serializer; - - public SectionValueBuilder(@NotNull ValueType valueType) { - this(valueType, ConfigValueHandler.required(), ConfigValueHandler.required()); - } - - public SectionValueBuilder(@NotNull ValueType valueType, + public SectionValueBuilder(@NotNull ValueType type, @NotNull ConfigValueHandler parser, @NotNull ConfigValueHandler> serializer) { - this.valueType = valueType; - this.parser = parser; - this.serializer = serializer; + super(type, type, parser, serializer); } @Override @@ -36,46 +22,9 @@ public class SectionValueBuilder extends CommonConfigBuilder parse(ConfigDataFunction valueParser) { - return parse((p, section) -> valueParser.handle(section)); - } - - public @NotNull SectionValueBuilder parse(ConfigValueHandler valueParser) { - this.parser = valueParser; - return this; - } - - public @NotNull SectionValueBuilder serialize(ConfigDataFunction> serializer) { - return serialize((p, value) -> serializer.handle(value)); - } - - public @NotNull SectionValueBuilder serialize(ConfigValueHandler> serializer) { - this.serializer = serializer; - return this; - } - - public @NotNull SectionValueBuilder serialize(Consumer> serializer) { - return serialize((p, value) -> { - Map map = new LinkedHashMap<>(); - serializer.accept(map); - return map; - }); - } - @Override public @NotNull ConfiguredValue build() { - return ConfiguredValue.of( - buildManifest(), - (p, type, data) -> { - ConfigurationSection section = p.deserialize(ConfigurationSection.class, data); - if (section == null) return null; - return this.parser.handle(p, section); - }, - (p, type, data) -> { - Map map = this.serializer.handle(p, data); - return map == null || map.isEmpty() ? null : map; // Map is a type of original data - } - ); + return ConfiguredValue.of(buildManifest(), buildAdapter()); } } diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java index aa8dd88..ee0e943 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java @@ -1,30 +1,17 @@ package cc.carm.lib.configuration.builder.value; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.builder.impl.AbstractSourceBuilder; import cc.carm.lib.configuration.function.ConfigValueHandler; import cc.carm.lib.configuration.value.standard.ConfiguredValue; import org.jetbrains.annotations.NotNull; -public class SourceValueBuilder extends CommonConfigBuilder> { +public class SourceValueBuilder extends AbstractSourceBuilder, SourceValueBuilder> { - protected final @NotNull ValueType sourceType; - protected final @NotNull ValueType valueType; - protected @NotNull ConfigValueHandler valueParser; - protected @NotNull ConfigValueHandler valueSerializer; - - public SourceValueBuilder(@NotNull ValueType sourceType, @NotNull ValueType valueType) { - this(sourceType, valueType, ConfigValueHandler.required(), ConfigValueHandler.required()); - } public SourceValueBuilder(@NotNull ValueType sourceType, @NotNull ValueType valueType, - @NotNull ConfigValueHandler valueParser, - @NotNull ConfigValueHandler valueSerializer) { - this.sourceType = sourceType; - this.valueType = valueType; - this.valueParser = valueParser; - this.valueSerializer = valueSerializer; + @NotNull ConfigValueHandler parser, @NotNull ConfigValueHandler serializer) { + super(valueType, sourceType, valueType, parser, serializer); } @Override @@ -32,37 +19,9 @@ public class SourceValueBuilder extends CommonConfigBuilder parse(ConfigDataFunction parser) { - return parse((p, source) -> parser.handle(source)); - } - - public @NotNull SourceValueBuilder parse(@NotNull ConfigValueHandler parser) { - this.valueParser = parser; - return this; - } - - public @NotNull SourceValueBuilder serialize(@NotNull ConfigValueHandler serializer) { - this.valueSerializer = serializer; - return this; - } - - public @NotNull SourceValueBuilder serialize(@NotNull ConfigDataFunction serializer) { - return serialize((p, value) -> serializer.handle(value)); - } - @Override public @NotNull ConfiguredValue build() { - return ConfiguredValue.of( - buildManifest(), - (p, type, data) -> { - S source = p.deserialize(this.sourceType, data); - return this.valueParser.handle(p, source); - }, - (p, type, value) -> { - S source = this.valueSerializer.handle(p, value); - return p.serialize(source); - } - ); + return new ConfiguredValue<>(buildManifest(), buildAdapter()); } } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java index e76718d..1c2e02a 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java @@ -4,6 +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.builder.list.ConfigListBuilder; import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; @@ -16,12 +17,20 @@ import java.util.function.Supplier; public class ConfiguredList extends CachedConfigValue> implements List { + public static @NotNull ConfigListBuilder builderOf(@NotNull Class type) { + return builderOf(ValueType.of(type)); + } + + public static @NotNull ConfigListBuilder builderOf(@NotNull ValueType type) { + return new ConfigListBuilder<>(type); + } + protected final @NotNull Supplier> constructor; protected final @NotNull ValueAdapter paramAdapter; - private ConfiguredList(@NotNull ValueManifest> manifest, - @NotNull Supplier> constructor, - @NotNull ValueAdapter paramAdapter) { + public ConfiguredList(@NotNull ValueManifest> manifest, + @NotNull Supplier> constructor, + @NotNull ValueAdapter paramAdapter) { super(manifest); this.constructor = constructor; this.paramAdapter = paramAdapter; diff --git a/core/src/main/old/builder/AbstractConfigBuilder.java b/core/src/main/old/builder/AbstractConfigBuilder.java deleted file mode 100644 index c8f2270..0000000 --- a/core/src/main/old/builder/AbstractConfigBuilder.java +++ /dev/null @@ -1,76 +0,0 @@ -package cc.carm.lib.configuration.builder; - -import cc.carm.lib.configuration.value.ConfigValue; -import cc.carm.lib.configuration.value.ValueManifest; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; -import java.util.List; -import java.util.function.Supplier; - -public abstract class AbstractConfigBuilder, P extends ConfigurationProvider> { - - protected final Class providerClass; - - protected @Nullable P provider; - protected @Nullable String path; - - protected @Nullable List headerComments; - protected @Nullable String inlineComment; - - protected @Nullable T defaultValue; - - protected AbstractConfigBuilder(Class providerClass) { - this.providerClass = providerClass; - } - - protected abstract @NotNull B getThis(); - - public abstract @NotNull ConfigValue build(); - - public @NotNull B from(@Nullable P provider) { - this.provider = provider; - return self(); - } - - public @NotNull B path(@Nullable String path) { - this.path = path; - return self(); - } - - public @NotNull B comments(@NotNull String... comments) { - return headerComments(comments); - } - - public @NotNull B headerComments(@NotNull String... comments) { - return headerComments(Arrays.asList(comments)); - } - - public @NotNull B headerComments(@NotNull List comments) { - this.headerComments = comments; - return self(); - } - - public @NotNull B inlineComment(@NotNull String comment) { - this.inlineComment = comment; - return self(); - } - - public @NotNull B defaults(@Nullable T defaultValue) { - this.defaultValue = defaultValue; - return self(); - } - - public @NotNull B defaults(@NotNull Supplier<@Nullable T> defaultValueSupplier) { - return defaults(defaultValueSupplier.get()); - } - - protected @NotNull ValueManifest buildManifest() { - return ValueManifest.of( - this.provider, this.path, - this.headerComments, this.inlineComment, this.defaultValue - ); - } - -} diff --git a/core/src/main/old/builder/CommonConfigBuilder.java b/core/src/main/old/builder/CommonConfigBuilder.java deleted file mode 100644 index b9e26f3..0000000 --- a/core/src/main/old/builder/CommonConfigBuilder.java +++ /dev/null @@ -1,10 +0,0 @@ -package cc.carm.lib.configuration.builder; - -public abstract class CommonConfigBuilder> - extends AbstractConfigBuilder> { - - protected CommonConfigBuilder() { - super(ConfigurationProvider.class); - } - -} diff --git a/core/src/main/old/builder/list/ConfigListBuilder.java b/core/src/main/old/builder/list/ConfigListBuilder.java deleted file mode 100644 index 67b5210..0000000 --- a/core/src/main/old/builder/list/ConfigListBuilder.java +++ /dev/null @@ -1,58 +0,0 @@ -package cc.carm.lib.configuration.builder.list; - -import cc.carm.lib.configuration.function.ConfigDataFunction; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; - - -public class ConfigListBuilder { - - protected final @NotNull Class valueClass; - - public ConfigListBuilder(@NotNull Class valueClass) { - this.valueClass = valueClass; - } - - public @NotNull SourceListBuilder from(@NotNull Class sourceClass, - @NotNull ConfigDataFunction sourceParser, - @NotNull ConfigDataFunction valueParser, - @NotNull ConfigDataFunction valueSerializer, - @NotNull ConfigDataFunction sourceSerializer) { - return new SourceListBuilder<>(sourceClass, sourceParser, this.valueClass, valueParser, valueSerializer, sourceSerializer); - } - - - public @NotNull SourceListBuilder from(Class sourceClass) { - return from(sourceClass, - ConfigDataFunction.required(), ConfigDataFunction.required(), - ConfigDataFunction.required(), ConfigDataFunction.required() - ); - } - - public @NotNull SourceListBuilder fromObject() { - return from( - Object.class, ConfigDataFunction.identity(), - ConfigDataFunction.castObject(valueClass), - ConfigDataFunction.toObject(), ConfigDataFunction.toObject() - ); - } - - public @NotNull SourceListBuilder fromString() { - return from( - String.class, ConfigDataFunction.castToString(), - ConfigDataFunction.castFromString(this.valueClass), - ConfigDataFunction.castToString(), ConfigDataFunction.toObject() - ); - } - - public @NotNull SourceListBuilder, V> fromMap() { - return from( - Map.class, obj -> (Map) obj, - ConfigDataFunction.required(), - ConfigDataFunction.required(), - ConfigDataFunction.toObject() - ); - } - -} diff --git a/core/src/main/old/builder/list/SourceListBuilder.java b/core/src/main/old/builder/list/SourceListBuilder.java deleted file mode 100644 index 4173a66..0000000 --- a/core/src/main/old/builder/list/SourceListBuilder.java +++ /dev/null @@ -1,80 +0,0 @@ -package cc.carm.lib.configuration.builder.list; - -import cc.carm.lib.configuration.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.value.standard.ConfiguredList; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -public class SourceListBuilder extends CommonConfigBuilder, SourceListBuilder> { - - protected final @NotNull Class sourceClass; - protected @NotNull ConfigDataFunction sourceParser; - - protected final @NotNull Class valueClass; - protected @NotNull ConfigDataFunction valueParser; - - protected @NotNull ConfigDataFunction valueSerializer; - protected @NotNull ConfigDataFunction sourceSerializer; - - public SourceListBuilder(@NotNull Class sourceClass, @NotNull ConfigDataFunction sourceParser, - @NotNull Class valueClass, @NotNull ConfigDataFunction valueParser, - @NotNull ConfigDataFunction valueSerializer, - @NotNull ConfigDataFunction sourceSerializer) { - this.sourceClass = sourceClass; - this.sourceParser = sourceParser; - this.sourceSerializer = sourceSerializer; - this.valueClass = valueClass; - this.valueParser = valueParser; - this.valueSerializer = valueSerializer; - } - - @SafeVarargs - public final @NotNull SourceListBuilder defaults(@NotNull V... values) { - return defaults(new ArrayList<>(Arrays.asList(values))); - } - - public final @NotNull SourceListBuilder defaults(@NotNull Collection values) { - return defaults(new ArrayList<>(values)); - } - - public @NotNull SourceListBuilder parseSource(ConfigDataFunction sourceParser) { - this.sourceParser = sourceParser; - return this; - } - - public @NotNull SourceListBuilder parseValue(ConfigDataFunction valueParser) { - this.valueParser = valueParser; - return this; - } - - public @NotNull SourceListBuilder serializeValue(ConfigDataFunction serializer) { - this.valueSerializer = serializer; - return this; - } - - public @NotNull SourceListBuilder serializeSource(ConfigDataFunction serializer) { - this.sourceSerializer = serializer; - return this; - } - - @Override - protected @NotNull SourceListBuilder getThis() { - return this; - } - - @Override - public @NotNull ConfiguredList build() { - return new ConfiguredList<>( - buildManifest(), this.valueClass, - this.sourceParser.andThen(this.valueParser), - this.valueSerializer.andThen(sourceSerializer) - ); - } - - -} diff --git a/core/src/main/old/builder/map/ConfigMapBuilder.java b/core/src/main/old/builder/map/ConfigMapBuilder.java deleted file mode 100644 index 635dd5d..0000000 --- a/core/src/main/old/builder/map/ConfigMapBuilder.java +++ /dev/null @@ -1,68 +0,0 @@ -package cc.carm.lib.configuration.builder.map; - -import cc.carm.lib.configuration.function.ConfigDataFunction; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; -import java.util.function.Supplier; - -public class ConfigMapBuilder, K, V> { - - protected final @NotNull Supplier supplier; - - protected final @NotNull Class keyClass; - protected final @NotNull Class valueClass; - - public ConfigMapBuilder(@NotNull Supplier supplier, @NotNull Class keyClass, @NotNull Class valueClass) { - this.supplier = supplier; - this.keyClass = keyClass; - this.valueClass = valueClass; - } - - public > ConfigMapBuilder supplier(@NotNull Supplier supplier) { - return new ConfigMapBuilder<>(supplier, keyClass, valueClass); - } - - public SourceMapBuilder from(@NotNull Class sourceClass, - @NotNull ConfigDataFunction valueParser, - @NotNull ConfigDataFunction valueSerializer) { - return new SourceMapBuilder<>(supplier, - keyClass, ConfigDataFunction.castFromString(this.keyClass), // #String -> key - sourceClass, ConfigDataFunction.castObject(sourceClass), // #Object -> source - valueClass, valueParser, // source -> value - ConfigDataFunction.castToString(), // key -> #String - valueSerializer/*value -> source*/, - ConfigDataFunction.toObject()/* source -> #Object */ - ); - } - - public SourceMapBuilder from(@NotNull Class sourceClass) { - return from(sourceClass, ConfigDataFunction.required(), ConfigDataFunction.required()); - } - - public SourceMapBuilder fromString(@NotNull ConfigDataFunction valueParser) { - return from(String.class, valueParser, ConfigDataFunction.castToString()); - } - - public SourceMapBuilder fromString() { - return fromString(ConfigDataFunction.castFromString(this.valueClass)); - } - - public SectionMapBuilder fromSection() { - return new SectionMapBuilder<>( - supplier, - keyClass, ConfigDataFunction.castFromString(keyClass), - valueClass, ConfigDataFunction.required(), - ConfigDataFunction.castToString(), ConfigDataFunction.required()); - } - - public SourceMapBuilder fromObject(@NotNull ConfigDataFunction valueParser) { - return from(Object.class, valueParser, ConfigDataFunction.toObject()); - } - - public SourceMapBuilder fromObject() { - return fromObject(ConfigDataFunction.required()); - } - - -} diff --git a/core/src/main/old/builder/map/ConfigMapCreator.java b/core/src/main/old/builder/map/ConfigMapCreator.java deleted file mode 100644 index 24a8312..0000000 --- a/core/src/main/old/builder/map/ConfigMapCreator.java +++ /dev/null @@ -1,38 +0,0 @@ -package cc.carm.lib.configuration.builder.map; - -import org.jetbrains.annotations.NotNull; - -import java.util.*; -import java.util.function.Supplier; - -public class ConfigMapCreator { - - protected final @NotNull Class keyClass; - protected final @NotNull Class valueClass; - - public ConfigMapCreator(@NotNull Class keyClass, @NotNull Class valueClass) { - this.keyClass = keyClass; - this.valueClass = valueClass; - } - - public > @NotNull ConfigMapBuilder asMap(Supplier mapSuppler) { - return new ConfigMapBuilder<>(mapSuppler, keyClass, valueClass); - } - - public @NotNull ConfigMapBuilder, K, V> asHashMap() { - return asMap(HashMap::new); - } - - public @NotNull ConfigMapBuilder, K, V> asLinkedMap() { - return asMap(LinkedHashMap::new); - } - - public @NotNull ConfigMapBuilder, K, V> asTreeMap() { - return asMap(TreeMap::new); - } - - public @NotNull ConfigMapBuilder, K, V> asTreeMap(@NotNull Comparator comparator) { - return asMap(() -> new TreeMap<>(comparator)); - } - -} diff --git a/core/src/main/old/builder/map/SectionMapBuilder.java b/core/src/main/old/builder/map/SectionMapBuilder.java deleted file mode 100644 index c5a6267..0000000 --- a/core/src/main/old/builder/map/SectionMapBuilder.java +++ /dev/null @@ -1,98 +0,0 @@ -package cc.carm.lib.configuration.builder.map; - -import cc.carm.lib.configuration.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.value.ValueManifest; -import cc.carm.lib.configuration.value.standard.ConfiguredSectionMap; -import org.jetbrains.annotations.NotNull; - -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class SectionMapBuilder, K, V> extends CommonConfigBuilder> { - - protected final @NotNull Supplier supplier; - - protected final @NotNull Class keyClass; - protected @NotNull ConfigDataFunction keyParser; - - protected final @NotNull Class valueClass; - protected @NotNull ConfigDataFunction, V> valueParser; - - protected @NotNull ConfigDataFunction keySerializer; - protected @NotNull ConfigDataFunction> valueSerializer; - - public SectionMapBuilder(@NotNull Supplier supplier, - @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, - @NotNull Class valueClass, @NotNull ConfigDataFunction, V> valueParser, - @NotNull ConfigDataFunction keySerializer, - @NotNull ConfigDataFunction> valueSerializer) { - this.supplier = supplier; - this.keyClass = keyClass; - this.keyParser = keyParser; - this.valueClass = valueClass; - this.valueParser = valueParser; - this.keySerializer = keySerializer; - this.valueSerializer = valueSerializer; - } - - public > SectionMapBuilder supplier(@NotNull Supplier supplier) { - return new SectionMapBuilder<>(supplier, - keyClass, keyParser, valueClass, valueParser, keySerializer, valueSerializer - ); - } - - public @NotNull SectionMapBuilder defaults(@NotNull Consumer factory) { - M map = supplier.get(); - factory.accept(map); - return defaults(map); - } - - public @NotNull SectionMapBuilder parseKey(@NotNull ConfigDataFunction parser) { - this.keyParser = parser; - return this; - } - - public @NotNull SectionMapBuilder parseValue(@NotNull ConfigDataFunction, V> parser) { - this.valueParser = parser; - return this; - } - - public @NotNull SectionMapBuilder serializeKey(@NotNull ConfigDataFunction serializer) { - this.keySerializer = serializer; - return this; - } - - public @NotNull SectionMapBuilder serializeValue(@NotNull ConfigDataFunction> serializer) { - this.valueSerializer = serializer; - return this; - } - - public @NotNull SectionMapBuilder serializeValue(@NotNull BiConsumer> serializer) { - return serializeValue(v -> { - Map map = new LinkedHashMap<>(); - serializer.accept(v, map); - return map; - }); - } - - - @Override - protected @NotNull SectionMapBuilder getThis() { - return this; - } - - @Override - public @NotNull ConfiguredSectionMap build() { - return new ConfiguredSectionMap<>( - new ValueManifest<>(provider, path, headerComments, inlineComment, defaultValue), - this.supplier, this.keyClass, this.keyParser, - this.valueClass, this.valueParser, - this.keySerializer, this.valueSerializer - ); - } - -} diff --git a/core/src/main/old/builder/map/SourceMapBuilder.java b/core/src/main/old/builder/map/SourceMapBuilder.java deleted file mode 100644 index 4699edd..0000000 --- a/core/src/main/old/builder/map/SourceMapBuilder.java +++ /dev/null @@ -1,107 +0,0 @@ -package cc.carm.lib.configuration.builder.map; - -import cc.carm.lib.configuration.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.value.ValueManifest; -import cc.carm.lib.configuration.value.standard.ConfiguredMap; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; -import java.util.function.Consumer; -import java.util.function.Supplier; - -public class SourceMapBuilder, S, K, V> extends CommonConfigBuilder> { - - protected final @NotNull Supplier supplier; - - protected final @NotNull Class keyClass; - protected @NotNull ConfigDataFunction keyParser; - - protected final @NotNull Class sourceClass; - protected @NotNull ConfigDataFunction sourceParser; - - protected final @NotNull Class valueClass; - protected @NotNull ConfigDataFunction valueParser; - - protected @NotNull ConfigDataFunction keySerializer; - protected @NotNull ConfigDataFunction valueSerializer; - protected @NotNull ConfigDataFunction sourceSerializer; - - public SourceMapBuilder(@NotNull Supplier supplier, - @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, - @NotNull Class sourceClass, @NotNull ConfigDataFunction sourceParser, - @NotNull Class valueClass, @NotNull ConfigDataFunction valueParser, - @NotNull ConfigDataFunction keySerializer, - @NotNull ConfigDataFunction valueSerializer, - @NotNull ConfigDataFunction sourceSerializer) { - this.supplier = supplier; - this.keyClass = keyClass; - this.keyParser = keyParser; - this.valueClass = valueClass; - this.valueParser = valueParser; - this.sourceClass = sourceClass; - this.sourceParser = sourceParser; - this.keySerializer = keySerializer; - this.valueSerializer = valueSerializer; - this.sourceSerializer = sourceSerializer; - } - - public > SourceMapBuilder supplier(@NotNull Supplier supplier) { - return new SourceMapBuilder<>(supplier, - keyClass, keyParser, sourceClass, sourceParser, valueClass, valueParser, - keySerializer, valueSerializer, sourceSerializer - ); - } - - public @NotNull SourceMapBuilder defaults(@NotNull Consumer factory) { - M map = supplier.get(); - factory.accept(map); - return defaults(map); - } - - public @NotNull SourceMapBuilder parseKey(@NotNull ConfigDataFunction parser) { - this.keyParser = parser; - return this; - } - - public @NotNull SourceMapBuilder parseSource(@NotNull ConfigDataFunction parser) { - this.sourceParser = parser; - return this; - } - - public @NotNull SourceMapBuilder parseValue(@NotNull ConfigDataFunction parser) { - this.valueParser = parser; - return this; - } - - public @NotNull SourceMapBuilder serializeKey(@NotNull ConfigDataFunction serializer) { - this.keySerializer = serializer; - return this; - } - - public @NotNull SourceMapBuilder serializeValue(@NotNull ConfigDataFunction serializer) { - this.valueSerializer = serializer; - return this; - } - - public @NotNull SourceMapBuilder serializeSource(@NotNull ConfigDataFunction serializer) { - this.sourceSerializer = serializer; - return this; - } - - @Override - protected @NotNull SourceMapBuilder getThis() { - return this; - } - - @Override - public @NotNull ConfiguredMap build() { - return new ConfiguredMap<>( - new ValueManifest<>(provider, path, headerComments, inlineComment, defaultValue), - this.supplier, this.keyClass, this.keyParser, - this.valueClass, this.sourceParser.andThen(this.valueParser), - this.keySerializer, this.valueSerializer.andThen(this.sourceSerializer) - ); - } - -} diff --git a/core/src/main/old/builder/value/ConfigValueBuilder.java b/core/src/main/old/builder/value/ConfigValueBuilder.java deleted file mode 100644 index b4db9ce..0000000 --- a/core/src/main/old/builder/value/ConfigValueBuilder.java +++ /dev/null @@ -1,63 +0,0 @@ -package cc.carm.lib.configuration.builder.value; - -import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.function.ConfigValueParser; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; - -public class ConfigValueBuilder { - - protected final @NotNull Class valueClass; - - public ConfigValueBuilder(@NotNull Class valueClass) { - this.valueClass = valueClass; - } - - public @NotNull SectionValueBuilder fromSection() { - return fromSection(ConfigValueParser.required(), ConfigDataFunction.required()); - } - - public @NotNull SectionValueBuilder fromSection(@NotNull ConfigValueParser, V> valueParser, - @NotNull ConfigDataFunction> valueSerializer) { - return new SectionValueBuilder<>(this.valueClass, valueParser, valueSerializer); - } - - public @NotNull SourceValueBuilder from(Class sourceClass) { - return from( - sourceClass, ConfigDataFunction.required(), ConfigValueParser.required(), - ConfigDataFunction.required(), ConfigDataFunction.required() - ); - } - - public @NotNull SourceValueBuilder from(@NotNull Class sourceClass, - @NotNull ConfigDataFunction sourceParser, - @NotNull ConfigValueParser valueParser, - @NotNull ConfigDataFunction valueSerializer, - @NotNull ConfigDataFunction sourceSerializer) { - return new SourceValueBuilder<>( - sourceClass, sourceParser, this.valueClass, valueParser, - valueSerializer, sourceSerializer - ); - } - - public @NotNull SourceValueBuilder fromObject() { - return from( - Object.class, ConfigDataFunction.identity(), - ConfigValueParser.castObject(valueClass), - s -> { - if (s instanceof Enum) return ((Enum) s).name(); - else return s; - }, ConfigDataFunction.toObject() - ); - } - - public @NotNull SourceValueBuilder fromString() { - return from( - String.class, ConfigDataFunction.castToString(), - ConfigValueParser.parseString(this.valueClass), - ConfigDataFunction.castToString(), ConfigDataFunction.toObject() - ); - } - -} diff --git a/core/src/main/old/builder/value/SectionValueBuilder.java b/core/src/main/old/builder/value/SectionValueBuilder.java deleted file mode 100644 index 4670fc8..0000000 --- a/core/src/main/old/builder/value/SectionValueBuilder.java +++ /dev/null @@ -1,52 +0,0 @@ -package cc.carm.lib.configuration.builder.value; - -import cc.carm.lib.configuration.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.function.ConfigValueParser; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; - -public class SectionValueBuilder - extends CommonConfigBuilder> { - - - protected final @NotNull Class valueClass; - - protected @NotNull ConfigValueParser, V> parser; - protected @NotNull ConfigDataFunction> serializer; - - public SectionValueBuilder(@NotNull Class valueClass, - @NotNull ConfigValueParser, V> parser, - @NotNull ConfigDataFunction> serializer) { - this.valueClass = valueClass; - this.parser = parser; - this.serializer = serializer; - } - - - @Override - protected @NotNull SectionValueBuilder getThis() { - return this; - } - - public @NotNull SectionValueBuilder parseValue(ConfigDataFunction, V> valueParser) { - return parseValue((section, path) -> valueParser.parse(section)); - } - - public @NotNull SectionValueBuilder parseValue(ConfigValueParser, V> valueParser) { - this.parser = valueParser; - return this; - } - - public @NotNull SectionValueBuilder serializeValue(ConfigDataFunction> serializer) { - this.serializer = serializer; - return this; - } - - @Override - public @NotNull ConfiguredSection build() { - return new ConfiguredSection<>(buildManifest(), this.valueClass, this.parser, this.serializer); - } - -} diff --git a/core/src/main/old/builder/value/SourceValueBuilder.java b/core/src/main/old/builder/value/SourceValueBuilder.java deleted file mode 100644 index 22c2c9a..0000000 --- a/core/src/main/old/builder/value/SourceValueBuilder.java +++ /dev/null @@ -1,70 +0,0 @@ -package cc.carm.lib.configuration.builder.value; - -import cc.carm.lib.configuration.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.function.ConfigValueParser; -import cc.carm.lib.configuration.value.standard.ConfiguredValue; -import org.jetbrains.annotations.NotNull; - -public class SourceValueBuilder extends CommonConfigBuilder> { - - protected final @NotNull Class sourceClass; - protected @NotNull ConfigDataFunction sourceParser; - - protected final @NotNull Class valueClass; - protected @NotNull ConfigValueParser valueParser; - - protected @NotNull ConfigDataFunction sourceSerializer; - protected @NotNull ConfigDataFunction valueSerializer; - - public SourceValueBuilder(@NotNull Class sourceClass, @NotNull ConfigDataFunction sourceParser, - @NotNull Class valueClass, @NotNull ConfigValueParser valueParser, - @NotNull ConfigDataFunction valueSerializer, - @NotNull ConfigDataFunction sourceSerializer) { - this.sourceClass = sourceClass; - this.sourceParser = sourceParser; - this.valueClass = valueClass; - this.valueParser = valueParser; - this.sourceSerializer = sourceSerializer; - this.valueSerializer = valueSerializer; - } - - @Override - protected @NotNull SourceValueBuilder getThis() { - return this; - } - - public @NotNull SourceValueBuilder parseSource(@NotNull ConfigDataFunction sourceParser) { - this.sourceParser = sourceParser; - return this; - } - - public @NotNull SourceValueBuilder parseValue(ConfigDataFunction valueParser) { - return parseValue((section, path) -> valueParser.parse(section)); - } - - public @NotNull SourceValueBuilder parseValue(@NotNull ConfigValueParser valueParser) { - this.valueParser = valueParser; - return this; - } - - public @NotNull SourceValueBuilder serializeValue(@NotNull ConfigDataFunction serializer) { - this.valueSerializer = serializer; - return this; - } - - public @NotNull SourceValueBuilder serializeSource(@NotNull ConfigDataFunction serializer) { - this.sourceSerializer = serializer; - return this; - } - - @Override - public @NotNull ConfiguredValue build() { - return new ConfiguredValue<>( - buildManifest(), this.valueClass, - this.valueParser.compose(this.sourceParser), - this.valueSerializer.andThen(sourceSerializer) - ); - } - -} From 45ca8b02d405c9678382ba659ba5153483aba707 Mon Sep 17 00:00:00 2001 From: Carm Date: Sun, 9 Feb 2025 03:49:37 +0800 Subject: [PATCH 10/17] feat!(core): Finished the design of core module --- .../adapter/ValueAdapterRegistry.java | 10 +- ...iveAdapters.java => PrimitiveAdapter.java} | 72 ++++--- .../configuration/annotation/ConfigPath.java | 2 - .../builder/AbstractConfigBuilder.java | 34 +++- .../builder/impl/AbstractSectionBuilder.java | 20 +- .../builder/impl/AbstractSourceBuilder.java | 20 +- .../builder/list/ConfigListBuilder.java | 6 +- .../builder/list/SectionListBuilder.java | 6 +- .../builder/list/SourceListBuilder.java | 4 +- .../builder/value/ConfigValueBuilder.java | 14 +- .../builder/value/SectionValueBuilder.java | 6 +- .../builder/value/SourceValueBuilder.java | 4 +- ...figDataFunction.java => DataFunction.java} | 34 ++-- ...figValueHandler.java => ValueHandler.java} | 16 +- .../lib/configuration/meta/PathMetadata.java | 58 ------ .../source/ConfigurationFactory.java | 16 +- .../source/ConfigurationProvider.java | 130 ++----------- .../loader/ConfigInitializeHandler.java | 32 ++++ .../loader/ConfigurationInitializer.java | 177 ++++++++++++++++++ .../source/loader/ConfigurationLoader.java | 133 ------------- .../source/loader/PathGenerator.java | 82 +++++++- .../source/loader/StandardPathGenerator.java | 86 --------- .../source/meta/ConfigurationMetaHolder.java | 124 ++++++++++++ .../source/meta/ConfigurationMetadata.java | 57 ++++++ .../option/ConfigurationOptionHolder.java | 10 +- ...ationOptions.java => StandardOptions.java} | 2 +- .../source/section/ConfigurationSection.java | 40 ++-- .../lib/configuration/value/ConfigValue.java | 16 +- .../configuration/value/ValueManifest.java | 54 ++++-- core/src/test/java/AdaptTest.java | 15 +- core/src/test/java/NameTest.java | 1 - .../java/cc/carm/test/config/LoaderTest.java | 11 +- .../commentable/CommentableMetaTypes.java | 23 ++- .../commentable/ConfigurationComments.java | 48 ----- .../configuration/source/FileProvider.java | 8 +- 35 files changed, 758 insertions(+), 613 deletions(-) rename core/src/main/java/cc/carm/lib/configuration/adapter/strandard/{PrimitiveAdapters.java => PrimitiveAdapter.java} (52%) rename core/src/main/java/cc/carm/lib/configuration/function/{ConfigDataFunction.java => DataFunction.java} (77%) rename core/src/main/java/cc/carm/lib/configuration/function/{ConfigValueHandler.java => ValueHandler.java} (70%) delete mode 100644 core/src/main/java/cc/carm/lib/configuration/meta/PathMetadata.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigInitializeHandler.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationInitializer.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationLoader.java delete mode 100644 core/src/main/java/cc/carm/lib/configuration/source/loader/StandardPathGenerator.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/meta/ConfigurationMetaHolder.java create mode 100644 core/src/main/java/cc/carm/lib/configuration/source/meta/ConfigurationMetadata.java rename core/src/main/java/cc/carm/lib/configuration/source/option/{ConfigurationOptions.java => StandardOptions.java} (96%) delete mode 100644 features/commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java 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 2864261..d03eba4 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 @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.adapter; -import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.source.ConfigurationProvider; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -15,14 +15,14 @@ public class ValueAdapterRegistry { protected final Set> adapters = new HashSet<>(); public void register(@NotNull Class from, @NotNull Class to, - @Nullable ConfigDataFunction parser, - @Nullable ConfigDataFunction serializer) { + @Nullable DataFunction parser, + @Nullable DataFunction serializer) { register(ValueType.of(from), ValueType.of(to), parser, serializer); } public void register(@NotNull ValueType from, @NotNull ValueType to, - @Nullable ConfigDataFunction parser, - @Nullable ConfigDataFunction serializer) { + @Nullable DataFunction parser, + @Nullable DataFunction serializer) { ValueAdapter fromAdapter = adapterOf(from); if (fromAdapter == null) throw new IllegalArgumentException("No adapter for type " + from); register(to, diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapter.java similarity index 52% rename from core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java rename to core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapter.java index 1017820..ecd3dd5 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapters.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/strandard/PrimitiveAdapter.java @@ -3,17 +3,27 @@ package cc.carm.lib.configuration.adapter.strandard; import cc.carm.lib.configuration.adapter.ValueAdapter; import cc.carm.lib.configuration.adapter.ValueParser; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.DataFunction; import org.jetbrains.annotations.NotNull; -public class PrimitiveAdapters extends ValueAdapter { +import java.util.Arrays; - public static final PrimitiveAdapters[] ADAPTERS = new PrimitiveAdapters[]{ +public class PrimitiveAdapter extends ValueAdapter { + + public static final PrimitiveAdapter[] ADAPTERS = new PrimitiveAdapter[]{ ofString(), ofBoolean(), ofBooleanType(), ofCharacter(), ofCharacterType(), ofInteger(), ofIntegerType(), ofLong(), ofLongType(), ofDouble(), ofDoubleType(), ofFloat(), ofFloatType(), ofShort(), ofShortType(), ofByte(), ofByteType() }; + public static final String[] TRUE_VALUES = new String[]{ + "true", "yes", "on", "1", "enabled", "enable", "active" + }; + + public static final String[] FALSE_VALUES = new String[]{ + "false", "no", "off", "0", "disabled", "disable", "inactive" + }; + @SuppressWarnings({"unchecked", "rawtypes"}) public static ValueAdapter> ofEnum() { ValueAdapter> adapter = new ValueAdapter<>(new ValueType>() { @@ -23,86 +33,92 @@ public class PrimitiveAdapters extends ValueAdapter { return adapter; } - public static PrimitiveAdapters ofString() { + public static PrimitiveAdapter ofString() { return of(String.class, o -> o instanceof String ? (String) o : o.toString()); } - public static PrimitiveAdapters ofBoolean() { - return of(Boolean.class, o -> o instanceof Boolean ? (Boolean) o : Boolean.parseBoolean(o.toString())); + public static PrimitiveAdapter ofBoolean() { + return of(Boolean.class, data -> { + if (data instanceof Boolean) return (Boolean) data; + String v = data.toString().trim(); + if (Arrays.stream(TRUE_VALUES).anyMatch(v::equalsIgnoreCase)) return true; + else if (Arrays.stream(FALSE_VALUES).anyMatch(v::equalsIgnoreCase)) return false; + else throw new IllegalArgumentException("Cannot parse boolean from " + data); + }); } - public static PrimitiveAdapters ofBooleanType() { + public static PrimitiveAdapter ofBooleanType() { return of(boolean.class, o -> o instanceof Boolean ? (Boolean) o : Boolean.parseBoolean(o.toString())); } - public static PrimitiveAdapters ofCharacter() { + public static PrimitiveAdapter ofCharacter() { return of(Character.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0)); } - public static PrimitiveAdapters ofCharacterType() { + public static PrimitiveAdapter ofCharacterType() { return of(char.class, o -> o instanceof Character ? (Character) o : o.toString().charAt(0)); } - public static PrimitiveAdapters ofInteger() { + public static PrimitiveAdapter ofInteger() { return ofNumber(Integer.class, Number::intValue, Integer::parseInt); } - public static PrimitiveAdapters ofIntegerType() { + public static PrimitiveAdapter ofIntegerType() { return ofNumber(int.class, Number::intValue, Integer::parseInt); } - public static PrimitiveAdapters ofLong() { + public static PrimitiveAdapter ofLong() { return ofNumber(Long.class, Number::longValue, Long::parseLong); } - public static PrimitiveAdapters ofLongType() { + public static PrimitiveAdapter ofLongType() { return ofNumber(long.class, Number::longValue, Long::parseLong); } - public static PrimitiveAdapters ofDouble() { + public static PrimitiveAdapter ofDouble() { return ofNumber(Double.class, Number::doubleValue, Double::parseDouble); } - public static PrimitiveAdapters ofDoubleType() { + public static PrimitiveAdapter ofDoubleType() { return ofNumber(double.class, Number::doubleValue, Double::parseDouble); } - public static PrimitiveAdapters ofFloat() { + public static PrimitiveAdapter ofFloat() { return ofNumber(Float.class, Number::floatValue, Float::parseFloat); } - public static PrimitiveAdapters ofFloatType() { + public static PrimitiveAdapter ofFloatType() { return ofNumber(float.class, Number::floatValue, Float::parseFloat); } - public static PrimitiveAdapters ofShort() { + public static PrimitiveAdapter ofShort() { return ofNumber(Short.class, Number::shortValue, Short::parseShort); } - public static PrimitiveAdapters ofShortType() { + public static PrimitiveAdapter ofShortType() { return ofNumber(short.class, Number::shortValue, Short::parseShort); } - public static PrimitiveAdapters ofByte() { + public static PrimitiveAdapter ofByte() { return ofNumber(Byte.class, Number::byteValue, Byte::parseByte); } - public static PrimitiveAdapters ofByteType() { + public static PrimitiveAdapter ofByteType() { return ofNumber(byte.class, Number::byteValue, Byte::parseByte); } - public static PrimitiveAdapters of(@NotNull Class clazz, - @NotNull ConfigDataFunction function) { - return new PrimitiveAdapters<>(clazz, (p, type, data) -> function.handle(data)); + public static PrimitiveAdapter of(@NotNull Class clazz, + @NotNull DataFunction function) { + return new PrimitiveAdapter<>(clazz, (p, type, data) -> function.handle(data)); } - public static PrimitiveAdapters ofNumber(@NotNull Class numberClass, - @NotNull ConfigDataFunction castFunction, - @NotNull ConfigDataFunction parseFunction) { + public static PrimitiveAdapter ofNumber(@NotNull Class numberClass, + @NotNull DataFunction castFunction, + @NotNull DataFunction parseFunction) { return of(numberClass, o -> o instanceof Number ? castFunction.handle((Number) o) : parseFunction.handle(o.toString())); } - protected PrimitiveAdapters(@NotNull Class valueType, @NotNull ValueParser deserializer) { + protected PrimitiveAdapter(@NotNull Class valueType, @NotNull ValueParser deserializer) { super(ValueType.of(valueType), (provider, type, value) -> value, deserializer); } diff --git a/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java index 9d21c85..e8810f8 100644 --- a/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java +++ b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java @@ -1,7 +1,5 @@ package cc.carm.lib.configuration.annotation; -import cc.carm.lib.configuration.source.loader.PathGenerator; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java index 1d466de..cf59996 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java @@ -2,11 +2,15 @@ package cc.carm.lib.configuration.builder; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; +import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.ValueManifest; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Supplier; public abstract class AbstractConfigBuilder< @@ -21,6 +25,8 @@ public abstract class AbstractConfigBuilder< protected @Nullable String path; protected @NotNull Supplier defaultValueSupplier = () -> null; + protected @NotNull BiConsumer, String> initializer = (provider, path) -> { + }; protected AbstractConfigBuilder(Class providerClass, ValueType type) { this.providerClass = providerClass; @@ -35,7 +41,7 @@ public abstract class AbstractConfigBuilder< public abstract @NotNull RESULT build(); - public @NotNull SELF from(@Nullable PROVIDER provider) { + public @NotNull SELF provider(@Nullable PROVIDER provider) { this.provider = provider; return self(); } @@ -45,6 +51,19 @@ public abstract class AbstractConfigBuilder< return self(); } + public @NotNull SELF initializer(@NotNull BiConsumer, String> initializer) { + this.initializer = initializer; + return self(); + } + + public @NotNull SELF append(@NotNull BiConsumer, String> initializer) { + return initializer(initializer.andThen(initializer)); + } + + public @NotNull SELF append(@NotNull Consumer> initializer) { + return append((provider, path) -> initializer.accept(provider)); + } + public @NotNull SELF defaults(@Nullable TYPE defaultValue) { return defaults(() -> defaultValue); } @@ -54,8 +73,19 @@ public abstract class AbstractConfigBuilder< return self(); } + public @NotNull SELF meta(@NotNull Consumer<@NotNull ConfigurationMetaHolder> metaConsumer) { + return append((provider, path) -> metaConsumer.accept(provider.metadata(path))); + } + + public @NotNull SELF meta(@NotNull ConfigurationMetadata type, @Nullable M value) { + return meta(holder -> holder.set(type, value)); + } + protected @NotNull ValueManifest buildManifest() { - return new ValueManifest<>(type(), this.provider, this.path, this.defaultValueSupplier); + return new ValueManifest<>( + type(), this.defaultValueSupplier, this.initializer, + this.provider, this.path + ); } } 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 91879d3..e647a1e 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 @@ -3,8 +3,8 @@ package cc.carm.lib.configuration.builder.impl; import cc.carm.lib.configuration.adapter.ValueAdapter; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.function.ConfigValueHandler; +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.value.ConfigValue; import org.jetbrains.annotations.NotNull; @@ -21,32 +21,32 @@ public abstract class AbstractSectionBuilder< protected final @NotNull ValueType paramType; - protected @NotNull ConfigValueHandler parser; - protected @NotNull ConfigValueHandler> serializer; + protected @NotNull ValueHandler parser; + protected @NotNull ValueHandler> serializer; public AbstractSectionBuilder(@NotNull ValueType type, @NotNull ValueType paramType, - @NotNull ConfigValueHandler parser, - @NotNull ConfigValueHandler> serializer) { + @NotNull ValueHandler parser, + @NotNull ValueHandler> serializer) { super(type); this.paramType = paramType; this.parser = parser; this.serializer = serializer; } - public @NotNull SELF parse(ConfigDataFunction valueParser) { + public @NotNull SELF parse(DataFunction valueParser) { return parse((p, section) -> valueParser.handle(section)); } - public @NotNull SELF parse(ConfigValueHandler valueParser) { + public @NotNull SELF parse(ValueHandler valueParser) { this.parser = valueParser; return self(); } - public @NotNull SELF serialize(ConfigDataFunction> serializer) { + public @NotNull SELF serialize(DataFunction> serializer) { return serialize((p, value) -> serializer.handle(value)); } - public @NotNull SELF serialize(ConfigValueHandler> serializer) { + public @NotNull SELF serialize(ValueHandler> serializer) { this.serializer = serializer; return self(); } 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 a9830d3..2ec78b0 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 @@ -3,8 +3,8 @@ package cc.carm.lib.configuration.builder.impl; import cc.carm.lib.configuration.adapter.ValueAdapter; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.builder.CommonConfigBuilder; -import cc.carm.lib.configuration.function.ConfigDataFunction; -import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.function.DataFunction; +import cc.carm.lib.configuration.function.ValueHandler; import cc.carm.lib.configuration.value.ConfigValue; import org.jetbrains.annotations.NotNull; @@ -15,13 +15,13 @@ public abstract class AbstractSourceBuilder< protected final @NotNull ValueType sourceType; protected final @NotNull ValueType paramType; - protected @NotNull ConfigValueHandler valueParser; - protected @NotNull ConfigValueHandler valueSerializer; + protected @NotNull ValueHandler valueParser; + protected @NotNull ValueHandler valueSerializer; public AbstractSourceBuilder(@NotNull ValueType type, @NotNull ValueType sourceType, @NotNull ValueType paramType, - @NotNull ConfigValueHandler parser, - @NotNull ConfigValueHandler serializer) { + @NotNull ValueHandler parser, + @NotNull ValueHandler serializer) { super(type); this.sourceType = sourceType; this.paramType = paramType; @@ -29,21 +29,21 @@ public abstract class AbstractSourceBuilder< this.valueSerializer = serializer; } - public @NotNull SELF parse(ConfigDataFunction parser) { + public @NotNull SELF parse(DataFunction parser) { return parse((p, source) -> parser.handle(source)); } - public @NotNull SELF parse(@NotNull ConfigValueHandler parser) { + public @NotNull SELF parse(@NotNull ValueHandler parser) { this.valueParser = parser; return self(); } - public @NotNull SELF serialize(@NotNull ConfigValueHandler serializer) { + public @NotNull SELF serialize(@NotNull ValueHandler serializer) { this.valueSerializer = serializer; return self(); } - public @NotNull SELF serialize(@NotNull ConfigDataFunction serializer) { + public @NotNull SELF serialize(@NotNull DataFunction serializer) { return serialize((p, value) -> serializer.handle(value)); } 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 cd7e8f1..e78082c 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 @@ -1,7 +1,7 @@ package cc.carm.lib.configuration.builder.list; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.function.ValueHandler; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -19,7 +19,7 @@ public class ConfigListBuilder { } public @NotNull SourceListBuilder from(@NotNull ValueType sourceType) { - return new SourceListBuilder<>(sourceType, type, ConfigValueHandler.required(), ConfigValueHandler.required(), ArrayList::new); + return new SourceListBuilder<>(sourceType, type, ValueHandler.required(), ValueHandler.required(), ArrayList::new); } public @NotNull SourceListBuilder fromString() { @@ -27,7 +27,7 @@ public class ConfigListBuilder { } public @NotNull SectionListBuilder fromSection() { - return new SectionListBuilder<>(type, ConfigValueHandler.required(), ConfigValueHandler.required(), ArrayList::new); + return new SectionListBuilder<>(type, ValueHandler.required(), ValueHandler.required(), ArrayList::new); } 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 d808a01..929cfe9 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 @@ -2,7 +2,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.ConfigValueHandler; +import cc.carm.lib.configuration.function.ValueHandler; import cc.carm.lib.configuration.source.section.ConfigurationSection; 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 ConfigValueHandler parser, - @NotNull ConfigValueHandler> 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/list/SourceListBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/list/SourceListBuilder.java index bb73610..655114c 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/list/SourceListBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/list/SourceListBuilder.java @@ -2,7 +2,7 @@ package cc.carm.lib.configuration.builder.list; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.builder.impl.AbstractSourceBuilder; -import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.function.ValueHandler; import cc.carm.lib.configuration.value.standard.ConfiguredList; import org.jetbrains.annotations.NotNull; @@ -18,7 +18,7 @@ public class SourceListBuilder protected @NotNull Supplier> constructor; public SourceListBuilder(@NotNull ValueType sourceType, @NotNull ValueType paramType, - @NotNull ConfigValueHandler parser, @NotNull ConfigValueHandler serializer, + @NotNull ValueHandler parser, @NotNull ValueHandler serializer, @NotNull Supplier> constructor) { super(new ValueType>() { }, sourceType, 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 b9447d0..c3ee264 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 @@ -1,7 +1,7 @@ package cc.carm.lib.configuration.builder.value; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.function.ValueHandler; import cc.carm.lib.configuration.source.section.ConfigurationSection; import org.jetbrains.annotations.NotNull; @@ -20,12 +20,12 @@ public class ConfigValueBuilder { } public @NotNull SourceValueBuilder from(@NotNull ValueType sourceType) { - return from(sourceType, ConfigValueHandler.required(), ConfigValueHandler.required()); + return from(sourceType, ValueHandler.required(), ValueHandler.required()); } public @NotNull SourceValueBuilder from(@NotNull ValueType sourceType, - @NotNull ConfigValueHandler valueParser, - @NotNull ConfigValueHandler valueSerializer) { + @NotNull ValueHandler valueParser, + @NotNull ValueHandler valueSerializer) { return new SourceValueBuilder<>(sourceType, this.type, valueParser, valueSerializer); } @@ -34,12 +34,12 @@ public class ConfigValueBuilder { } public @NotNull SectionValueBuilder fromSection() { - return fromSection(ConfigValueHandler.required(), ConfigValueHandler.required()); + return fromSection(ValueHandler.required(), ValueHandler.required()); } public @NotNull SectionValueBuilder fromSection( - @NotNull ConfigValueHandler valueParser, - @NotNull ConfigValueHandler> 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 5d6577a..52019ee 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 @@ -2,7 +2,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.ConfigValueHandler; +import cc.carm.lib.configuration.function.ValueHandler; import cc.carm.lib.configuration.source.section.ConfigurationSection; 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 ConfigValueHandler parser, - @NotNull ConfigValueHandler> serializer) { + @NotNull ValueHandler parser, + @NotNull ValueHandler> serializer) { super(type, type, parser, serializer); } diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java index ee0e943..96b01b0 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/value/SourceValueBuilder.java @@ -2,7 +2,7 @@ package cc.carm.lib.configuration.builder.value; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.builder.impl.AbstractSourceBuilder; -import cc.carm.lib.configuration.function.ConfigValueHandler; +import cc.carm.lib.configuration.function.ValueHandler; import cc.carm.lib.configuration.value.standard.ConfiguredValue; import org.jetbrains.annotations.NotNull; @@ -10,7 +10,7 @@ public class SourceValueBuilder extends AbstractSourceBuilder sourceType, @NotNull ValueType valueType, - @NotNull ConfigValueHandler parser, @NotNull ConfigValueHandler serializer) { + @NotNull ValueHandler parser, @NotNull ValueHandler serializer) { super(valueType, sourceType, valueType, parser, serializer); } diff --git a/core/src/main/java/cc/carm/lib/configuration/function/ConfigDataFunction.java b/core/src/main/java/cc/carm/lib/configuration/function/DataFunction.java similarity index 77% rename from core/src/main/java/cc/carm/lib/configuration/function/ConfigDataFunction.java rename to core/src/main/java/cc/carm/lib/configuration/function/DataFunction.java index 7571bcf..75a4708 100644 --- a/core/src/main/java/cc/carm/lib/configuration/function/ConfigDataFunction.java +++ b/core/src/main/java/cc/carm/lib/configuration/function/DataFunction.java @@ -7,39 +7,39 @@ import org.jetbrains.annotations.NotNull; import java.util.Objects; @FunctionalInterface -public interface ConfigDataFunction { +public interface DataFunction { @NotNull R handle(@NotNull T data) throws Exception; - default @NotNull ConfigDataFunction andThen(@NotNull ConfigDataFunction after) { + default @NotNull DataFunction andThen(@NotNull DataFunction after) { Objects.requireNonNull(after); return data -> after.handle(handle(data)); } @Contract(pure = true) - static @NotNull ConfigDataFunction identity() { + static @NotNull DataFunction identity() { return input -> input; } @Contract(pure = true) - static @NotNull ConfigDataFunction identity(Class type) { + static @NotNull DataFunction identity(Class type) { return input -> input; } @Contract(pure = true) - static @NotNull ConfigDataFunction required() { + static @NotNull DataFunction required() { return input -> { throw new IllegalArgumentException("Please specify the value parser."); }; } @Contract(pure = true) - static @NotNull ConfigDataFunction toObject() { + static @NotNull DataFunction toObject() { return input -> input; } @Contract(pure = true) - static @NotNull ConfigDataFunction castObject(Class valueClass) { + static @NotNull DataFunction castObject(Class valueClass) { return input -> { if (valueClass.isInstance(input)) return valueClass.cast(input); else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName()); @@ -47,7 +47,7 @@ public interface ConfigDataFunction { } @Contract(pure = true) - static @NotNull ConfigDataFunction castFromString(Class valueClass) { + static @NotNull DataFunction castFromString(Class valueClass) { return input -> { if (valueClass.isInstance(input)) return valueClass.cast(input); else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName()); @@ -55,7 +55,7 @@ public interface ConfigDataFunction { } @Contract(pure = true) - static @NotNull ConfigDataFunction castToString() { + static @NotNull DataFunction castToString() { return input -> { if (input instanceof String) return (String) input; else if (input instanceof Enum) return ((Enum) input).name(); @@ -64,7 +64,7 @@ public interface ConfigDataFunction { } @Contract(pure = true) - static @NotNull ConfigDataFunction parseString(Class valueClass) { + static @NotNull DataFunction parseString(Class valueClass) { return input -> { if (valueClass.isInstance(input)) return valueClass.cast(input); else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName()); @@ -72,7 +72,7 @@ public interface ConfigDataFunction { } @Contract(pure = true) - static @NotNull ConfigDataFunction intValue() { + static @NotNull DataFunction intValue() { return input -> { if (input instanceof Integer) { return (Integer) input; @@ -83,7 +83,7 @@ public interface ConfigDataFunction { } @Contract(pure = true) - static @NotNull ConfigDataFunction shortValue() { + static @NotNull DataFunction shortValue() { return input -> { if (input instanceof Short) { return (Short) input; @@ -94,7 +94,7 @@ public interface ConfigDataFunction { } @Contract(pure = true) - static @NotNull ConfigDataFunction doubleValue() { + static @NotNull DataFunction doubleValue() { return input -> { if (input instanceof Double) { return (Double) input; @@ -105,7 +105,7 @@ public interface ConfigDataFunction { } @Contract(pure = true) - static @NotNull ConfigDataFunction byteValue() { + static @NotNull DataFunction byteValue() { return input -> { if (input instanceof Byte) { return (Byte) input; @@ -116,7 +116,7 @@ public interface ConfigDataFunction { } @Contract(pure = true) - static @NotNull ConfigDataFunction floatValue() { + static @NotNull DataFunction floatValue() { return input -> { if (input instanceof Float) { return (Float) input; @@ -127,7 +127,7 @@ public interface ConfigDataFunction { } @Contract(pure = true) - static @NotNull ConfigDataFunction longValue() { + static @NotNull DataFunction longValue() { return input -> { if (input instanceof Long) { return (Long) input; @@ -138,7 +138,7 @@ public interface ConfigDataFunction { } @Contract(pure = true) - static @NotNull ConfigDataFunction booleanValue() { + static @NotNull DataFunction booleanValue() { return input -> { if (input instanceof Boolean) { return (Boolean) input; diff --git a/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueHandler.java b/core/src/main/java/cc/carm/lib/configuration/function/ValueHandler.java similarity index 70% rename from core/src/main/java/cc/carm/lib/configuration/function/ConfigValueHandler.java rename to core/src/main/java/cc/carm/lib/configuration/function/ValueHandler.java index 165f471..9f24b8d 100644 --- a/core/src/main/java/cc/carm/lib/configuration/function/ConfigValueHandler.java +++ b/core/src/main/java/cc/carm/lib/configuration/function/ValueHandler.java @@ -10,11 +10,11 @@ import org.jetbrains.annotations.Nullable; import java.util.Objects; @FunctionalInterface -public interface ConfigValueHandler { +public interface ValueHandler { @Nullable R handle(@NotNull ConfigurationProvider provider, @NotNull T data) throws Exception; - default ConfigValueHandler andThen(@NotNull ConfigValueHandler after) { + default ValueHandler andThen(@NotNull ValueHandler after) { Objects.requireNonNull(after); return ((provider, data) -> { R result = handle(provider, data); @@ -23,7 +23,7 @@ public interface ConfigValueHandler { }); } - default ConfigValueHandler compose(@NotNull ConfigValueHandler before) { + default ValueHandler compose(@NotNull ValueHandler before) { Objects.requireNonNull(before); return ((provider, data) -> { T result = before.handle(provider, data); @@ -32,7 +32,7 @@ public interface ConfigValueHandler { }); } - default ConfigValueHandler compose(@NotNull ConfigDataFunction before) { + default ValueHandler compose(@NotNull DataFunction before) { Objects.requireNonNull(before); return ((provider, data) -> { T result = before.handle(data); @@ -41,23 +41,23 @@ public interface ConfigValueHandler { } @Contract(pure = true) - static @NotNull ConfigValueHandler identity() { + static @NotNull ValueHandler identity() { return (provider, input) -> input; } @Contract(pure = true) - static @NotNull ConfigValueHandler toObject() { + static @NotNull ValueHandler toObject() { return ConfigurationProvider::serialize; } @Contract(pure = true) - static @NotNull ConfigValueHandler fromObject(ValueType type) { + static @NotNull ValueHandler fromObject(ValueType type) { return (provider, input) -> provider.deserialize(type, input); } @Contract(pure = true) - static @NotNull ConfigValueHandler required() { + static @NotNull ValueHandler required() { return (provider, input) -> { throw new IllegalArgumentException("Please specify the value parser."); }; diff --git a/core/src/main/java/cc/carm/lib/configuration/meta/PathMetadata.java b/core/src/main/java/cc/carm/lib/configuration/meta/PathMetadata.java deleted file mode 100644 index a2df1b1..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/meta/PathMetadata.java +++ /dev/null @@ -1,58 +0,0 @@ -package cc.carm.lib.configuration.meta; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.function.Function; -import java.util.function.Supplier; - -public class PathMetadata { - - public static PathMetadata of() { - return of(() -> null); - } - - public static PathMetadata of(T defaults) { - return of(() -> defaults); - } - - public static PathMetadata of(@NotNull Supplier<@Nullable T> defaults) { - return of(v -> defaults.get()); - } - - public static PathMetadata of(@NotNull Function defaults) { - return new PathMetadata<>(defaults); - } - - protected Function defaultFunction; - - public PathMetadata(@NotNull Function defaults) { - this.defaultFunction = defaults; - } - - public boolean isDefault(String path, @NotNull T value) { - return value.equals(defaults(path)); - } - - public boolean hasDefaults(String path) { - return defaults(path) != null; - } - - public T getDefault(String path, @Nullable T suppliedValue) { - T defaults = defaults(path); - return defaults == null ? suppliedValue : defaults; - } - - public @Nullable T defaults(String path) { - return defaultFunction.apply(path); - } - - public void setDefaults(Function defaultFunction) { - this.defaultFunction = defaultFunction; - } - - public void setDefaults(T value) { - setDefaults((v) -> value); - } - -} 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 3046267..23d734e 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,7 +1,7 @@ package cc.carm.lib.configuration.source; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; -import cc.carm.lib.configuration.source.loader.ConfigurationLoader; +import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.loader.PathGenerator; import cc.carm.lib.configuration.source.option.ConfigurationOption; import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; @@ -13,8 +13,8 @@ import java.util.function.Function; public abstract class ConfigurationFactory, PROVIDER extends ConfigurationProvider, SELF> { - protected Function loaderFunction = PROVIDER -> new ConfigurationLoader(); - protected Consumer loaderConsumer = loader -> { + protected Function loaderFunction = PROVIDER -> new ConfigurationInitializer(); + protected Consumer loaderConsumer = loader -> { }; protected ValueAdapterRegistry adapters = new ValueAdapterRegistry(); @@ -22,23 +22,23 @@ public abstract class ConfigurationFactory loaderFunction) { + public SELF loader(Function loaderFunction) { this.loaderFunction = loaderFunction; return self(); } - public SELF loader(ConfigurationLoader loader) { + public SELF loader(ConfigurationInitializer loader) { return loader(PROVIDER -> loader); } - public SELF loader(Consumer loaderConsumer) { + public SELF loader(Consumer loaderConsumer) { this.loaderConsumer = this.loaderConsumer.andThen(loaderConsumer); return self(); } - public SELF pathGenerator(PathGenerator pathGenerator) { + public SELF pathGenerator(PathGenerator generator) { return loader(loader -> { - loader.setPathGenerator(pathGenerator); + loader.pathGenerator(generator); }); } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java index 68f7097..9749984 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java @@ -3,9 +3,8 @@ package cc.carm.lib.configuration.source; import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.meta.PathMetadata; -import cc.carm.lib.configuration.source.loader.ConfigurationLoader; -import cc.carm.lib.configuration.source.option.ConfigurationOption; +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.value.ValueManifest; @@ -18,20 +17,22 @@ import java.util.Map; public class ConfigurationProvider> { protected final @NotNull S source; - protected final @NotNull ConfigurationLoader loader; protected final @NotNull ValueAdapterRegistry adapters; protected final @NotNull ConfigurationOptionHolder options; - protected final @NotNull Map, Object>> pathMetadata; + protected final @NotNull Map metadata; - public ConfigurationProvider(@NotNull S source, @NotNull ConfigurationLoader loader, + protected final @NotNull ConfigurationInitializer initializer; + + public ConfigurationProvider(@NotNull S source, @NotNull ValueAdapterRegistry adapters, @NotNull ConfigurationOptionHolder options, - @NotNull Map, Object>> pathMetadata) { + @NotNull Map metadata, + @NotNull ConfigurationInitializer initializer) { this.source = source; - this.loader = loader; + this.initializer = initializer; this.adapters = adapters; this.options = options; - this.pathMetadata = pathMetadata; + this.metadata = metadata; } public @NotNull S source() { @@ -50,112 +51,21 @@ public class ConfigurationProvider> { return options; } - public @NotNull T option(@NotNull ConfigurationOption option) { - return options.get(option); + public @NotNull Map metadata() { + return this.metadata; } - public void option(@NotNull ConfigurationOption option, @NotNull T value) { - options.set(option, value); + public @NotNull ConfigurationMetaHolder metadata(@Nullable String path) { + return metadata().computeIfAbsent(path, k -> new ConfigurationMetaHolder()); } + public ValueAdapterRegistry adapters() { return this.adapters; } - public ConfigurationLoader loader() { - return loader; - } - - public @NotNull Map, Object>> pathMetadata() { - return pathMetadata; - } - - public @NotNull Map, Object> metadata(@NotNull String path) { - return pathMetadata().computeIfAbsent(path, k -> new java.util.HashMap<>()); - } - - /** - * Get the value of option. - * - * @param type {@link PathMetadata} - * @param defaultValue Default value if the value of option is not set. - * @param Value type - * @return Value of option - */ - @SuppressWarnings("unchecked") - @Contract("_,_, !null -> !null") - public @Nullable V meta(@NotNull String path, - @NotNull PathMetadata type, @Nullable V defaultValue) { - return (V) metadata(path).getOrDefault(type, type.getDefault(path, defaultValue)); - } - - /** - * Get the value of option. - * - * @param type {@link PathMetadata} - * @param Value type - * @return Value of option - */ - public @Nullable V meta(@NotNull String path, @NotNull PathMetadata type) { - return meta(path, type, null); - } - - public boolean hasMeta(@NotNull String path, @NotNull PathMetadata type) { - return metadata(path).containsKey(type) || type.hasDefaults(path); - } - - /** - * Set the value of meta, if the value is null, the meta will be removed. - *
Will only be changed in current holder. - * - * @param type {@link PathMetadata} - * @param value Value of meta - * @param Value type - * @return Previous value of meta - */ - @SuppressWarnings("unchecked") - public @Nullable V setMeta(@NotNull String path, @NotNull PathMetadata type, @Nullable V value) { - if (value == null || type.isDefault(path, value)) { - return (V) metadata(path).remove(type); - } else { - return (V) metadata(path).put(type, value); - } - } - - /** - * Set the value of meta, if the value is null, the meta will not be changed. - *
Will only be changed in current holder. - * - * @param type {@link PathMetadata} - * @param value Value of meta - * @param Value type - */ - public void setMetaIfAbsent(@NotNull String path, @NotNull PathMetadata type, @Nullable V value) { - if (value == null || type.isDefault(path, value)) { - metadata(path).remove(type); - } else { - metadata(path).putIfAbsent(type, value); - } - } - - /** - * Set the value of meta, if the value is null, the meta will not be changed. - *
Will only be changed in current holder. - * - * @param type {@link PathMetadata} - * @param value Value of meta - * @param Value type - */ - @SuppressWarnings("unchecked") - public @Nullable V setMetaIfPresent(@NotNull String path, @NotNull PathMetadata type, @Nullable V value) { - Object exists = metadata(path).get(type); - if (exists == null) return null; - - if (value == null || type.isDefault(path, value)) { - return (V) metadata(path).remove(type); - } else { - return (V) metadata(path).put(type, value); - } + public ConfigurationInitializer initializer() { + return initializer; } @Contract("_,null -> null") @@ -167,7 +77,7 @@ public class ConfigurationProvider> { public T deserialize(@NotNull ValueType type, @Nullable Object source) throws Exception { return adapters().deserialize(this, type, source); } - + @Contract("null -> null") public Object serialize(@Nullable T value) throws Exception { return adapters().serialize(this, value); @@ -175,7 +85,7 @@ public class ConfigurationProvider> { public void load(Class configClass) { try { - loader.load(this, configClass); + initializer.initialize(this, configClass); } catch (Exception e) { e.printStackTrace(); } @@ -183,7 +93,7 @@ public class ConfigurationProvider> { public void load(@NotNull Configuration config) { try { - loader.load(this, config); + initializer.initialize(this, config); } catch (Exception e) { e.printStackTrace(); } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigInitializeHandler.java b/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigInitializeHandler.java new file mode 100644 index 0000000..2ffe1b8 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigInitializeHandler.java @@ -0,0 +1,32 @@ +package cc.carm.lib.configuration.source.loader; + +import cc.carm.lib.configuration.source.ConfigurationProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@FunctionalInterface +public interface ConfigInitializeHandler { + + static ConfigInitializeHandler start() { + return (provider, path, value) -> { + }; + } + + void whenInitialize(@NotNull ConfigurationProvider provider, @Nullable String path, @NotNull T value) throws Exception; + + default ConfigInitializeHandler andThen(ConfigInitializeHandler after) { + return (provider, path, value) -> { + whenInitialize(provider, path, value); + after.whenInitialize(provider, path, value); + }; + } + + default ConfigInitializeHandler compose(ConfigInitializeHandler before) { + return (provider, path, value) -> { + before.whenInitialize(provider, path, value); + whenInitialize(provider, path, value); + }; + } + + +} 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 new file mode 100644 index 0000000..2463752 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationInitializer.java @@ -0,0 +1,177 @@ +package cc.carm.lib.configuration.source.loader; + +import cc.carm.lib.configuration.Configuration; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; +import cc.carm.lib.configuration.source.option.StandardOptions; +import cc.carm.lib.configuration.value.ConfigValue; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.function.Function; + +/** + * Configuration initializer, + * used to initialize {@link ConfigValue}s from {@link Configuration} classes. + */ +public class ConfigurationInitializer { + + protected @NotNull PathGenerator pathGenerator; + protected @NotNull ConfigInitializeHandler fieldInitializer; + protected @NotNull ConfigInitializeHandler> classInitializer; + + public ConfigurationInitializer() { + this(PathGenerator.of(), ConfigInitializeHandler.start(), ConfigInitializeHandler.start()); + } + + public ConfigurationInitializer(@NotNull PathGenerator pathGenerator, + @NotNull ConfigInitializeHandler fieldInitializer, + @NotNull ConfigInitializeHandler> classInitializer) { + this.pathGenerator = pathGenerator; + this.fieldInitializer = fieldInitializer; + this.classInitializer = classInitializer; + } + + public void pathGenerator(@NotNull PathGenerator pathGenerator) { + this.pathGenerator = pathGenerator; + } + + public @NotNull PathGenerator pathGenerator() { + return pathGenerator; + } + + public ConfigInitializeHandler fieldInitializer() { + return fieldInitializer; + } + + public void fieldInitializer(@NotNull ConfigInitializeHandler fieldInitializer) { + this.fieldInitializer = fieldInitializer; + } + + public ConfigInitializeHandler> classInitializer() { + return classInitializer; + } + + public void classInitializer(@NotNull ConfigInitializeHandler> classInitializer) { + this.classInitializer = classInitializer; + } + + public void appendFieldInitializer(@NotNull ConfigInitializeHandler fieldInitializer) { + this.fieldInitializer = this.fieldInitializer.andThen(fieldInitializer); + } + + public void appendClassInitializer(@NotNull ConfigInitializeHandler> classInitializer) { + this.classInitializer = this.classInitializer.andThen(classInitializer); + } + + public void registerAnnotation(@NotNull Class annotation, + @NotNull ConfigurationMetadata metadata, + @NotNull Function extractor) { + appendFieldInitializer((provider, path, field) -> { + A data = field.getAnnotation(annotation); + if (data == null) return; + provider.metadata(path).setIfAbsent(metadata, extractor.apply(data)); + }); + appendClassInitializer((provider, path, clazz) -> { + A data = clazz.getAnnotation(annotation); + if (data == null) return; + provider.metadata(path).setIfAbsent(metadata, extractor.apply(data)); + }); + } + + + public @Nullable String getFieldPath(ConfigurationProvider provider, @Nullable String parentPath, @NotNull Field field) { + return pathGenerator.getFieldPath(provider, parentPath, field); + } + + public @Nullable String getClassPath(ConfigurationProvider provider, @Nullable String parentPath, + @NotNull Class clazz, @Nullable Field clazzField) { + return pathGenerator.getClassPath(provider, parentPath, clazz, clazzField); + } + + public void initialize(ConfigurationProvider provider, @NotNull Configuration config) throws Exception { + initializeInstance(provider, config, null, null); + if (provider.options().get(StandardOptions.SET_DEFAULTS)) provider.save(); + } + + public void initialize(ConfigurationProvider provider, @NotNull Class clazz) throws Exception { + initializeStaticClass(provider, clazz, null, null); + if (provider.options().get(StandardOptions.SET_DEFAULTS)) provider.save(); + } + + + // 针对实例类的初始化方法 + protected void initializeInstance(@NotNull ConfigurationProvider provider, + @NotNull Configuration root, @Nullable String parentPath, @Nullable Field configField) { + String path = getClassPath(provider, parentPath, root.getClass(), configField); + try { + this.classInitializer.whenInitialize(provider, path, root.getClass()); + } catch (Exception e) { + e.printStackTrace(); + } + Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(provider, root, field, path)); + } + + // 针对静态类的初始化方法 + @SuppressWarnings("unchecked") + protected void initializeStaticClass(@NotNull ConfigurationProvider provider, + @NotNull Class clazz, @Nullable String parentPath, @Nullable Field configField) { + if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类 + + String path = getClassPath(provider, parentPath, clazz, configField); + + try { + this.classInitializer.whenInitialize(provider, path, (Class) clazz); + } catch (Exception e) { + e.printStackTrace(); + } + + for (Field field : clazz.getDeclaredFields()) { + initializeField(provider, clazz, field, path); + } + + if (provider.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); + } + } + } + + protected void initializeField(@NotNull ConfigurationProvider provider, + @NotNull Object source, @NotNull Field field, @Nullable String parent) { + try { + field.setAccessible(true); + Object object = field.get(source); +// + if (object instanceof ConfigValue) { + // 目标是 ConfigValue 实例,进行具体的初始化注入 + ConfigValue value = (ConfigValue) object; + String path = getFieldPath(provider, parent, field); + if (path == null) return; + value.initialize(provider, path); + try { + this.fieldInitializer.whenInitialize(provider, path, field); + } catch (Exception e) { + e.printStackTrace(); + } + } else if (source instanceof Configuration && object instanceof Configuration) { + // 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。 + initializeInstance(provider, (Configuration) object, parent, field); + } else if (source instanceof Class && object instanceof Class) { + // 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。 + initializeStaticClass(provider, (Class) object, parent, field); + } + + // 以上判断实现以下规范: + // - 实例类中仅加载 ConfigValue实例 与 Configuration实例 + // - 静态类中仅加载 静态ConfigValue实例 与 静态Configuration类 + + } catch (IllegalAccessException ignored) { + } + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationLoader.java b/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationLoader.java deleted file mode 100644 index 7c4052f..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigurationLoader.java +++ /dev/null @@ -1,133 +0,0 @@ -package cc.carm.lib.configuration.source.loader; - -import cc.carm.lib.configuration.Configuration; -import cc.carm.lib.configuration.source.ConfigurationProvider; -import cc.carm.lib.configuration.source.option.ConfigurationOptions; -import cc.carm.lib.configuration.value.ConfigValue; -import cc.carm.lib.configuration.value.ValueManifest; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.lang.reflect.Field; -import java.util.Arrays; - -/** - * Configuration loader, - * used to load configuration values from {@link Configuration} classes. - */ -public class ConfigurationLoader { - - public static final Field PATH_FIELD; - public static final Field PROVIDER_FIELD; - - static { - try { - PATH_FIELD = ValueManifest.class.getDeclaredField("path"); - PATH_FIELD.setAccessible(true); - PROVIDER_FIELD = ValueManifest.class.getDeclaredField("provider"); - PROVIDER_FIELD.setAccessible(true); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } - } - - protected PathGenerator pathGenerator; - - public ConfigurationLoader() { - this(StandardPathGenerator.of()); - } - - public ConfigurationLoader(PathGenerator pathGenerator) { - this.pathGenerator = pathGenerator; - } - - public void setPathGenerator(PathGenerator pathGenerator) { - this.pathGenerator = pathGenerator; - } - - public PathGenerator getPathGenerator() { - return pathGenerator; - } - - public @Nullable String getFieldPath(ConfigurationProvider provider, @Nullable String parentPath, @NotNull Field field) { - return pathGenerator.getFieldPath(provider, parentPath, field); - } - - public @Nullable String getClassPath(ConfigurationProvider provider, @Nullable String parentPath, - @NotNull Class clazz, @Nullable Field clazzField) { - return pathGenerator.getClassPath(provider, parentPath, clazz, clazzField); - } - - public void load(ConfigurationProvider provider, @NotNull Configuration config) throws Exception { - initializeInstance(provider, config, null, null); - if (provider.option(ConfigurationOptions.SET_DEFAULTS)) provider.save(); - } - - public void load(ConfigurationProvider provider, @NotNull Class clazz) throws Exception { - initializeStaticClass(provider, clazz, null, null); - if (provider.option(ConfigurationOptions.SET_DEFAULTS)) provider.save(); - } - - - // 针对实例类的初始化方法 - private void initializeInstance(@NotNull ConfigurationProvider provider, - @NotNull Configuration root, @Nullable String parentPath, @Nullable Field configField) { - String path = getClassPath(provider, parentPath, root.getClass(), configField); - Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(provider, root, field, path)); - } - - // 针对静态类的初始化方法 - private void initializeStaticClass(@NotNull ConfigurationProvider provider, - @NotNull Class clazz, @Nullable String parentPath, @Nullable Field configField) { - if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类 - String path = getClassPath(provider, parentPath, clazz, configField); - - for (Field field : clazz.getDeclaredFields()) { - initializeField(provider, clazz, field, path); - } - - if (!provider.option(ConfigurationOptions.LOAD_SUB_CLASSES)) return; - Class[] classes = clazz.getDeclaredClasses(); - for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。 - initializeStaticClass(provider, classes[i], path, null); - } - } - - private void initializeField(@NotNull ConfigurationProvider provider, - @NotNull Object source, @NotNull Field field, @Nullable String parent) { - try { - field.setAccessible(true); - Object object = field.get(source); -// - if (object instanceof ConfigValue) { - // 目标是 ConfigValue 实例,进行具体的初始化注入 - ConfigValue value = (ConfigValue) object; - String path = getFieldPath(provider, parent, field); - if (path == null) return; - insertIfAbsent(value, PATH_FIELD, path); - insertIfAbsent(value, PROVIDER_FIELD, provider); - } else if (source instanceof Configuration && object instanceof Configuration) { - // 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。 - initializeInstance(provider, (Configuration) object, parent, field); - } else if (source instanceof Class && object instanceof Class) { - // 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。 - initializeStaticClass(provider, (Class) object, parent, field); - } - - // 以上判断实现以下规范: - // - 实例类中仅加载 ConfigValue实例 与 Configuration实例 - // - 静态类中仅加载 静态ConfigValue实例 与 静态Configuration类 - - } catch (IllegalAccessException ignored) { - } - } - - private void insertIfAbsent(@NotNull ValueManifest value, @NotNull Field field, @NotNull Object obj) { - try { - if (field.get(obj) == null) field.set(obj, value); - } catch (IllegalAccessException ignored) { - } - } - -} 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 f7d508e..0f2dd10 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 @@ -1,27 +1,96 @@ package cc.carm.lib.configuration.source.loader; +import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.option.StandardOptions; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; +import java.util.function.UnaryOperator; -public interface PathGenerator { +public class PathGenerator { - @Nullable String getFieldPath(@NotNull ConfigurationProvider provider, - @Nullable String parentPath, @NotNull Field field); + public static PathGenerator of() { + return of(PathGenerator::covertPathName); + } - @Nullable String getClassPath(@NotNull ConfigurationProvider provider, - @Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField); + public static PathGenerator of(UnaryOperator pathConverter) { + return new PathGenerator(pathConverter); + } + + protected UnaryOperator pathConverter; + + public PathGenerator(UnaryOperator pathConverter) { + this.pathConverter = pathConverter; + } + + public @NotNull UnaryOperator getPathConverter() { + return pathConverter; + } + + public void setPathConverter(UnaryOperator pathConverter) { + this.pathConverter = pathConverter; + } + + public String covertPath(String name) { + return pathConverter.apply(name); + } + + public @Nullable String getFieldPath(@NotNull ConfigurationProvider provider, + @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())); + } + + public @Nullable String getClassPath(@NotNull ConfigurationProvider provider, + @Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField) { + // For standard path generator, we generate path following by: + // 1. Check if the class has a ConfigPath annotation, if so, use the root and value as the path. + // 2. If the class defined as a field, check if the field has a ConfigPath annotation, + // and use filed information. + ConfigPath clazzPath = clazz.getAnnotation(ConfigPath.class); + + if (clazzPath != null) return link(provider, parentPath, clazzPath.root(), clazzPath.value()); + if (clazzField == null) { + return link(provider, 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); + } + + protected String select(String path, String defaultValue) { + if (path == null || path.isEmpty()) return defaultValue; + else return isBlank(path) ? null : path; + } + + protected @Nullable String link(@NotNull ConfigurationProvider provider, + @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); + } + + public static boolean isBlank(String path) { + return path == null || path.replace(" ", "").isEmpty(); + } + + public static char pathSeparator(ConfigurationProvider provider) { + return provider.options().get(StandardOptions.PATH_SEPARATOR); + } /** * Get the configuration name of the specified element. * Use the naming convention of all lowercase and "-" links. + *

+ * e.g. "SOME_NAME" -> "some-name" * * @param name source name * @return the final path */ - static String covertPathName(String name) { + public static String covertPathName(String name) { return name // Replace all uppercase letters with dashes .replaceAll("[A-Z]", "-$0") @@ -40,4 +109,5 @@ public interface PathGenerator { .toLowerCase(); } + } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/loader/StandardPathGenerator.java b/core/src/main/java/cc/carm/lib/configuration/source/loader/StandardPathGenerator.java deleted file mode 100644 index 2612e0a..0000000 --- a/core/src/main/java/cc/carm/lib/configuration/source/loader/StandardPathGenerator.java +++ /dev/null @@ -1,86 +0,0 @@ -package cc.carm.lib.configuration.source.loader; - -import cc.carm.lib.configuration.annotation.ConfigPath; -import cc.carm.lib.configuration.source.ConfigurationProvider; -import cc.carm.lib.configuration.source.option.ConfigurationOptions; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Field; -import java.util.function.UnaryOperator; - -public class StandardPathGenerator implements PathGenerator { - - public static StandardPathGenerator of() { - return of(PathGenerator::covertPathName); - } - - public static StandardPathGenerator of(UnaryOperator pathConverter) { - return new StandardPathGenerator(pathConverter); - } - - protected UnaryOperator pathConverter; - - public StandardPathGenerator(UnaryOperator pathConverter) { - this.pathConverter = pathConverter; - } - - public @NotNull UnaryOperator getPathConverter() { - return pathConverter; - } - - public void setPathConverter(UnaryOperator pathConverter) { - this.pathConverter = pathConverter; - } - - public String covertPath(String name) { - return pathConverter.apply(name); - } - - public char pathSeparator(ConfigurationProvider provider) { - return provider.option(ConfigurationOptions.PATH_SEPARATOR); - } - - @Override - public @Nullable String getFieldPath(@NotNull ConfigurationProvider provider, - @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())); - } - - @Override - public @Nullable String getClassPath(@NotNull ConfigurationProvider provider, - @Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField) { - // For standard path generator, we generate path following by: - // 1. Check if the class has a ConfigPath annotation, if so, use the root and value as the path. - // 2. If the class defined as a field, check if the field has a ConfigPath annotation, - // and use filed information. - ConfigPath clazzPath = clazz.getAnnotation(ConfigPath.class); - - if (clazzPath != null) return link(provider, parentPath, clazzPath.root(), clazzPath.value()); - if (clazzField == null) { - return link(provider, 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); - } - - protected String select(String path, String defaultValue) { - if (path == null || path.isEmpty()) return defaultValue; - else return isBlank(path) ? null : path; - } - - protected boolean isBlank(String path) { - return path == null || path.replace(" ", "").isEmpty(); - } - - protected @Nullable String link(@NotNull ConfigurationProvider provider, @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); - } - - -} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/meta/ConfigurationMetaHolder.java b/core/src/main/java/cc/carm/lib/configuration/source/meta/ConfigurationMetaHolder.java new file mode 100644 index 0000000..fce23be --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/meta/ConfigurationMetaHolder.java @@ -0,0 +1,124 @@ +package cc.carm.lib.configuration.source.meta; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +public class ConfigurationMetaHolder { + + protected final @NotNull Map, Object> values; + + public ConfigurationMetaHolder() { + this(new ConcurrentHashMap<>()); + } + + public ConfigurationMetaHolder(@NotNull Map, Object> values) { + this.values = values; + } + + public @NotNull Map, Object> values() { + return values; + } + + /** + * Get the value of option. + * + * @param type {@link ConfigurationMetadata} + * @param defaultValue Default value if the value of option is not set. + * @param Value type + * @return Value of option + */ + @SuppressWarnings("unchecked") + @Contract("_,!null -> !null") + public @Nullable V get(@NotNull ConfigurationMetadata type, @Nullable V defaultValue) { + return (V) values().getOrDefault(type, type.defaultOrSupply(defaultValue)); + } + + /** + * Get the value of option. + * + * @param type {@link ConfigurationMetadata} + * @param defaultValue Default value if the value of option is not set. + * @param Value type + * @return Value of option + */ + @SuppressWarnings("unchecked") + @Contract("_,!null -> !null") + public @Nullable V get(@NotNull ConfigurationMetadata type, Supplier<@Nullable V> defaultValue) { + return (V) values().getOrDefault(type, type.defaultOrSupply(defaultValue)); + } + + /** + * Get the value of option. + * + * @param type {@link ConfigurationMetadata} + * @param Value type + * @return Value of option + */ + public @Nullable V get(@NotNull ConfigurationMetadata type) { + return get(type, (V) null); + } + + public boolean contains(@NotNull ConfigurationMetadata type) { + return values().containsKey(type) || type.hasDefaults(); + } + + /** + * Set the value of meta, if the value is null, the meta will be removed. + *
Will only be changed in current holder. + * + * @param type {@link ConfigurationMetadata} + * @param value Value of meta + * @param Value type + * @return Previous value of meta + */ + @SuppressWarnings("unchecked") + public @Nullable V set(@NotNull ConfigurationMetadata type, @Nullable V value) { + if (value == null || type.isDefault(value)) { + return (V) values().remove(type); + } else { + return (V) values().put(type, value); + } + } + + /** + * Set the value of meta, if the value is null, the meta will not be changed. + *
Will only be changed in current holder. + * + * @param type {@link ConfigurationMetadata} + * @param value Value of meta + * @param Value type + */ + public void setIfAbsent(@NotNull ConfigurationMetadata type, @Nullable V value) { + if (value == null || type.isDefault(value)) { + values().remove(type); + } else { + values().putIfAbsent(type, value); + } + } + + /** + * Set the value of meta, if the value is null, the meta will not be changed. + *
Will only be changed in current holder. + * + * @param type {@link ConfigurationMetadata} + * @param value Value of meta + * @param Value type + */ + @SuppressWarnings("unchecked") + public @Nullable V setIfPresent(@NotNull ConfigurationMetadata type, @Nullable V value) { + Object exists = values().get(type); + if (exists == null) return null; + + if (value == null || type.isDefault(value)) { + return (V) values().remove(type); + } else { + return (V) values().put(type, value); + } + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/meta/ConfigurationMetadata.java b/core/src/main/java/cc/carm/lib/configuration/source/meta/ConfigurationMetadata.java new file mode 100644 index 0000000..ff28804 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/source/meta/ConfigurationMetadata.java @@ -0,0 +1,57 @@ +package cc.carm.lib.configuration.source.meta; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +public class ConfigurationMetadata { + + public static ConfigurationMetadata of() { + return of(() -> null); + } + + public static ConfigurationMetadata of(T defaults) { + return of(() -> defaults); + } + + public static ConfigurationMetadata of(@NotNull Supplier<@Nullable T> defaults) { + return new ConfigurationMetadata<>(defaults); + } + + protected Supplier<@Nullable T> defaultsSupplier; + + public ConfigurationMetadata(@NotNull Supplier<@Nullable T> defaults) { + this.defaultsSupplier = defaults; + } + + public boolean isDefault(@NotNull T value) { + return value.equals(defaults()); + } + + public boolean hasDefaults() { + return defaults() != null; + } + + public T defaultOrSupply(@Nullable T suppliedValue) { + return defaultOrSupply(() -> suppliedValue); + } + + public T defaultOrSupply(Supplier<@Nullable T> suppliedValue) { + T defaults = defaults(); + return defaults == null ? suppliedValue.get() : defaults; + } + + public @Nullable T defaults() { + return defaultsSupplier.get(); + } + + public void setDefaults(Supplier defaultFunction) { + this.defaultsSupplier = defaultFunction; + } + + public void setDefaults(T value) { + setDefaults(() -> value); + } + +} diff --git a/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptionHolder.java b/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptionHolder.java index abacb5d..00f5c5b 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptionHolder.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptionHolder.java @@ -9,7 +9,7 @@ import java.util.concurrent.ConcurrentHashMap; public class ConfigurationOptionHolder { - public static @NotNull ConfigurationOptionHolder of(@NotNull Map, V> options) { + public static @NotNull ConfigurationOptionHolder of(@NotNull Map, Object> options) { return new ConfigurationOptionHolder(new ConcurrentHashMap<>(options)); } @@ -23,7 +23,7 @@ public class ConfigurationOptionHolder { this.options = options; } - public @NotNull Map, Object> options() { + public @NotNull Map, Object> values() { return options; } @@ -36,7 +36,7 @@ public class ConfigurationOptionHolder { */ @SuppressWarnings("unchecked") public @NotNull V get(@NotNull ConfigurationOption type) { - return Optional.ofNullable(options().get(type)).map(v -> (V) v).orElseGet(type::defaults); + return Optional.ofNullable(values().get(type)).map(v -> (V) v).orElseGet(type::defaults); } /** @@ -50,9 +50,9 @@ public class ConfigurationOptionHolder { @SuppressWarnings("unchecked") public @Nullable V set(@NotNull ConfigurationOption type, @Nullable V value) { if (value == null) { - return (V) options().remove(type); + return (V) values().remove(type); } else { - return (V) options().put(type, value); + return (V) values().put(type, value); } } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptions.java b/core/src/main/java/cc/carm/lib/configuration/source/option/StandardOptions.java similarity index 96% rename from core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptions.java rename to core/src/main/java/cc/carm/lib/configuration/source/option/StandardOptions.java index 377a273..a14c641 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/option/ConfigurationOptions.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/option/StandardOptions.java @@ -4,7 +4,7 @@ import cc.carm.lib.configuration.Configuration; import static cc.carm.lib.configuration.source.option.ConfigurationOption.of; -public interface ConfigurationOptions { +public interface StandardOptions { /** * The configuration path separator. 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/ConfigurationSection.java index 088c1d8..05a1afa 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/ConfigurationSection.java @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.source.section; -import cc.carm.lib.configuration.function.ConfigDataFunction; +import cc.carm.lib.configuration.function.DataFunction; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,18 +41,18 @@ public interface ConfigurationSection { return get(path, null, clazz); } - default @Nullable T get(@NotNull String path, @NotNull ConfigDataFunction parser) { + default @Nullable T get(@NotNull String path, @NotNull DataFunction parser) { return get(path, null, parser); } @Contract("_,!null,_->!null") default @Nullable T get(@NotNull String path, @Nullable T defaultValue, @NotNull Class clazz) { - return get(path, defaultValue, ConfigDataFunction.castObject(clazz)); + return get(path, defaultValue, DataFunction.castObject(clazz)); } @Contract("_,!null,_->!null") default @Nullable T get(@NotNull String path, @Nullable T defaultValue, - @NotNull ConfigDataFunction parser) { + @NotNull DataFunction parser) { Object value = get(path); if (value != null) { try { @@ -75,7 +75,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) { - return get(path, def, ConfigDataFunction.booleanValue()); + return get(path, def, DataFunction.booleanValue()); } default @Nullable Boolean isByte(@NotNull String path) { @@ -88,7 +88,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) { - return get(path, def, ConfigDataFunction.byteValue()); + return get(path, def, DataFunction.byteValue()); } default boolean isShort(@NotNull String path) { @@ -101,7 +101,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Short getShort(@NotNull String path, @Nullable Short def) { - return get(path, def, ConfigDataFunction.shortValue()); + return get(path, def, DataFunction.shortValue()); } @@ -115,7 +115,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) { - return get(path, def, ConfigDataFunction.intValue()); + return get(path, def, DataFunction.intValue()); } @@ -129,7 +129,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Long getLong(@NotNull String path, @Nullable Long def) { - return get(path, def, ConfigDataFunction.longValue()); + return get(path, def, DataFunction.longValue()); } @@ -143,7 +143,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) { - return get(path, def, ConfigDataFunction.floatValue()); + return get(path, def, DataFunction.floatValue()); } @@ -157,7 +157,7 @@ public interface ConfigurationSection { @Contract("_, !null -> !null") default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) { - return get(path, def, ConfigDataFunction.doubleValue()); + return get(path, def, DataFunction.doubleValue()); } @@ -188,47 +188,47 @@ public interface ConfigurationSection { return get(path, def, String.class); } - default @NotNull List getList(@NotNull String path, @NotNull ConfigDataFunction parser) { + default @NotNull List getList(@NotNull String path, @NotNull DataFunction parser) { return parseList(getList(path), parser); } @Unmodifiable default @NotNull List getStringList(@NotNull String path) { - return getList(path, ConfigDataFunction.castToString()); + return getList(path, DataFunction.castToString()); } @Unmodifiable default @NotNull List getIntegerList(@NotNull String path) { - return getList(path, ConfigDataFunction.intValue()); + return getList(path, DataFunction.intValue()); } @Unmodifiable default @NotNull List getLongList(@NotNull String path) { - return getList(path, ConfigDataFunction.longValue()); + return getList(path, DataFunction.longValue()); } @Unmodifiable default @NotNull List getDoubleList(@NotNull String path) { - return getList(path, ConfigDataFunction.doubleValue()); + return getList(path, DataFunction.doubleValue()); } @Unmodifiable default @NotNull List getFloatList(@NotNull String path) { - return getList(path, ConfigDataFunction.floatValue()); + return getList(path, DataFunction.floatValue()); } @Unmodifiable default @NotNull List getByteList(@NotNull String path) { - return getList(path, ConfigDataFunction.byteValue()); + return getList(path, DataFunction.byteValue()); } @Unmodifiable default @NotNull List getCharList(@NotNull String path) { - return getList(path, ConfigDataFunction.castObject(Character.class)); + return getList(path, DataFunction.castObject(Character.class)); } @Unmodifiable - static @NotNull List parseList(@Nullable List list, ConfigDataFunction parser) { + static @NotNull List parseList(@Nullable List list, DataFunction parser) { if (list == null) return Collections.emptyList(); List values = new ArrayList<>(); for (Object o : list) { diff --git a/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java index c198c18..05459b2 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java @@ -10,7 +10,7 @@ import java.util.Optional; public abstract class ConfigValue extends ValueManifest { protected ConfigValue(@NotNull ValueManifest manifest) { - super(manifest.type, manifest.provider, manifest.path, manifest.defaultSupplier); + super(manifest); } /** @@ -37,7 +37,7 @@ public abstract class ConfigValue extends ValueManifest { * @throws NullPointerException 对应数据为空时抛出 */ public @NotNull T getNotNull() { - return Objects.requireNonNull(getOrDefault(), "Value(" + path() + ") [" + type() + "] is null."); + return Objects.requireNonNull(getOrDefault(), "Value(" + type() + ") @[" + path() + "] is null."); } public @NotNull Optional<@Nullable T> optional() { @@ -80,4 +80,16 @@ public abstract class ConfigValue extends ValueManifest { return Objects.equals(defaults(), get()); } + /** + * Try to save the configuration. + *
To save multiple modifications, + * it is recommended to call {@link ConfigurationProvider#save()} + * after all modifications are completed instead of this. + * + * @throws Exception + */ + public void save() throws Exception { + provider().save(); + } + } 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 f508cd7..6ccdd01 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 @@ -2,41 +2,65 @@ package cc.carm.lib.configuration.value; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.section.ConfigurationSource; -import cc.carm.lib.configuration.meta.PathMetadata; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Map; +import java.util.function.BiConsumer; import java.util.function.Supplier; public class ValueManifest { protected final @NotNull ValueType type; + protected final @NotNull BiConsumer<@NotNull ConfigurationProvider, @NotNull String> initializer; + protected @Nullable ConfigurationProvider provider; protected @Nullable String path; // Section path protected @NotNull Supplier<@Nullable T> defaultSupplier; - public ValueManifest(ValueType type) { - this(type, null, null, () -> null); + + public ValueManifest(@NotNull ValueType type) { + this(type, () -> null, EMPTY_INITIALIZER, null, null); } public ValueManifest(@NotNull T defaultValue) { - this(ValueType.of(defaultValue), null, null, () -> defaultValue); + this(ValueType.of(defaultValue), () -> defaultValue); } public ValueManifest(@NotNull ValueType type, @NotNull Supplier<@Nullable T> defaultSupplier) { - this(type, null, null, defaultSupplier); + this(type, defaultSupplier, EMPTY_INITIALIZER, null, null); } - public ValueManifest(@NotNull ValueType type, - @Nullable ConfigurationProvider provider, @Nullable String path, - @NotNull Supplier<@Nullable T> defaultSupplier) { + public ValueManifest(@NotNull ValueType type, @NotNull Supplier<@Nullable T> defaultSupplier, + @NotNull BiConsumer<@NotNull ConfigurationProvider, @NotNull String> initializer) { + this(type, defaultSupplier, initializer, null, null); + } + + public ValueManifest(@NotNull ValueType type, @NotNull Supplier<@Nullable T> defaultSupplier, + @NotNull BiConsumer<@NotNull ConfigurationProvider, @NotNull String> initializer, + @Nullable ConfigurationProvider provider, @Nullable String path) { this.type = type; + this.initializer = initializer; + this.defaultSupplier = defaultSupplier; this.provider = provider; this.path = path; - this.defaultSupplier = defaultSupplier; + initialize(); + } + + protected ValueManifest(@NotNull ValueManifest manifest) { + this(manifest.type, manifest.defaultSupplier, manifest.initializer, manifest.provider, manifest.path); + } + + public void initialize(@NotNull ConfigurationProvider provider, @NotNull String path) { + this.provider = provider; + this.path = path; + initialize(); + } + + protected void initialize() { + if (provider != null && path != null) this.initializer.accept(provider, path); } public @NotNull ValueType type() { @@ -81,6 +105,10 @@ public class ValueManifest { return provider().source(); } + public ConfigurationMetaHolder metadata() { + return provider().metadata(path()); + } + protected Object getData() { return config().get(path()); } @@ -89,8 +117,8 @@ public class ValueManifest { config().set(path(), value); } - public Map, Object> metadata() { - return provider().metadata(path()); - } + + private static final @NotNull BiConsumer<@NotNull ConfigurationProvider, @NotNull String> EMPTY_INITIALIZER = (provider, path) -> { + }; } diff --git a/core/src/test/java/AdaptTest.java b/core/src/test/java/AdaptTest.java index e1ede3a..99dbace 100644 --- a/core/src/test/java/AdaptTest.java +++ b/core/src/test/java/AdaptTest.java @@ -1,17 +1,14 @@ import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapters; +import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter; import cc.carm.lib.configuration.source.ConfigurationProvider; -import cc.carm.lib.configuration.source.loader.ConfigurationLoader; +import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; -import cc.carm.lib.configuration.value.standard.ConfiguredValue; import cc.carm.test.config.TestSource; import org.junit.Test; import java.time.Duration; -import java.time.LocalDate; import java.time.LocalTime; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class AdaptTest { @@ -20,8 +17,8 @@ public class AdaptTest { public void test() throws Exception { ValueAdapterRegistry registry = new ValueAdapterRegistry(); - registry.register(PrimitiveAdapters.ADAPTERS); - registry.register(PrimitiveAdapters.ofEnum()); + registry.register(PrimitiveAdapter.ADAPTERS); + registry.register(PrimitiveAdapter.ofEnum()); registry.register(ValueType.of(Long.class), ValueType.of(Duration.class), Duration::ofMillis, Duration::toMillis); @@ -32,8 +29,8 @@ public class AdaptTest { ); ConfigurationProvider provider = new ConfigurationProvider<>( - new TestSource(), new ConfigurationLoader(), - registry, new ConfigurationOptionHolder(), new ConcurrentHashMap<>() + new TestSource(), registry, new ConfigurationOptionHolder(), + new ConcurrentHashMap<>(), new ConfigurationInitializer() ); LocalTime v = registry.deserialize(provider, LocalTime.class, 600000L); diff --git a/core/src/test/java/NameTest.java b/core/src/test/java/NameTest.java index 604057c..9b4cce8 100644 --- a/core/src/test/java/NameTest.java +++ b/core/src/test/java/NameTest.java @@ -1,4 +1,3 @@ -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 7210546..b42e961 100644 --- a/core/src/test/java/cc/carm/test/config/LoaderTest.java +++ b/core/src/test/java/cc/carm/test/config/LoaderTest.java @@ -4,7 +4,7 @@ import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.source.ConfigurationProvider; -import cc.carm.lib.configuration.source.loader.ConfigurationLoader; +import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; import org.junit.Test; @@ -14,10 +14,13 @@ public class LoaderTest { @Test public void test() throws Exception { - ConfigurationProvider provider = new ConfigurationProvider<>(new TestSource(), new ConfigurationLoader(), new ValueAdapterRegistry(), new ConfigurationOptionHolder(), new ConcurrentHashMap<>()); + ConfigurationProvider provider = new ConfigurationProvider<>( + new TestSource(), new ValueAdapterRegistry(), new ConfigurationOptionHolder(), + new ConcurrentHashMap<>(), new ConfigurationInitializer() + ); - ConfigurationLoader loader = new ConfigurationLoader(); - loader.load(provider, ROOT.class); + ConfigurationInitializer loader = new ConfigurationInitializer(); + loader.initialize(provider, ROOT.class); } interface ROOT extends Configuration { diff --git a/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java b/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java index 866abcb..b18433e 100644 --- a/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java +++ b/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java @@ -2,8 +2,12 @@ package cc.carm.lib.configuration.commentable; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.annotation.InlineComment; -import cc.carm.lib.configuration.meta.PathMetadata; +import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; +import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; +import org.jetbrains.annotations.NotNull; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -12,11 +16,24 @@ public interface CommentableMetaTypes { /** * Configuration's {@link HeaderComment} */ - PathMetadata> HEADER_COMMENTS = PathMetadata.of(Collections.emptyList()); + ConfigurationMetadata> HEADER_COMMENTS = ConfigurationMetadata.of(Collections.emptyList()); /** * Configuration's {@link InlineComment} */ - PathMetadata INLINE_COMMENT_VALUE = PathMetadata.of(); + ConfigurationMetadata INLINE_COMMENT = ConfigurationMetadata.of(); + + + static void register(@NotNull ConfigurationProvider provider) { + register(provider.initializer()); + } + + static void register(@NotNull ConfigurationInitializer initializer) { + initializer.registerAnnotation( + HeaderComment.class, HEADER_COMMENTS, + a -> Arrays.asList(a.value()) + ); + initializer.registerAnnotation(InlineComment.class, INLINE_COMMENT, InlineComment::value); + } } diff --git a/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java b/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java deleted file mode 100644 index c7b9ba0..0000000 --- a/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/ConfigurationComments.java +++ /dev/null @@ -1,48 +0,0 @@ -package cc.carm.lib.configuration.commentable; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.Unmodifiable; - -import java.util.*; - -public class ConfigurationComments { - - protected final @NotNull Map> headerComments = new HashMap<>(); - protected final @NotNull Map inlineComments = new HashMap<>(); - - protected @NotNull Map> getHeaderComments() { - return headerComments; - } - - protected @NotNull Map getInlineComments() { - return inlineComments; - } - - public void setHeaderComments(@Nullable String path, @Nullable List comments) { - if (comments == null) { - getHeaderComments().remove(path); - } else { - getHeaderComments().put(path, comments); - } - } - - public void setInlineComment(@NotNull String path, @Nullable String comment) { - if (comment == null) { - getInlineComments().remove(path); - } else { - getInlineComments().put(path, comment); - } - } - - @Nullable - @Unmodifiable - public List getHeaderComment(@Nullable String path) { - return Optional.ofNullable(getHeaderComments().get(path)).map(Collections::unmodifiableList).orElse(null); - } - - public @Nullable String getInlineComment(@NotNull String path) { - return getInlineComments().get(path); - } - -} diff --git a/features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java b/features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java index f10b3da..67cc8a8 100644 --- a/features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java +++ b/features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java @@ -1,8 +1,8 @@ package cc.carm.lib.configuration.source; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; -import cc.carm.lib.configuration.meta.PathMetadata; -import cc.carm.lib.configuration.source.loader.ConfigurationLoader; +import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; +import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; import cc.carm.lib.configuration.source.section.ConfigurationSource; import org.jetbrains.annotations.NotNull; @@ -11,9 +11,9 @@ import java.util.Map; public abstract class FileProvider> extends ConfigurationProvider { - public FileProvider(@NotNull S source, @NotNull ConfigurationLoader loader, + public FileProvider(@NotNull S source, @NotNull ConfigurationInitializer loader, @NotNull ValueAdapterRegistry adapters, @NotNull ConfigurationOptionHolder options, - @NotNull Map, Object>> pathMetadata) { + @NotNull Map, Object>> pathMetadata) { super(source, loader, adapters, options, pathMetadata); } From 209309192353fa85c23c14da0b0deafe9704a043 Mon Sep 17 00:00:00 2001 From: Carm Date: Mon, 10 Feb 2025 03:16:48 +0800 Subject: [PATCH 11/17] feat!(core): Update files sources --- .../configuration/adapter/ValueAdapter.java | 6 +- .../adapter/ValueAdapterRegistry.java | 8 +- .../configuration/adapter/ValueParser.java | 4 +- .../adapter/ValueSerializer.java | 4 +- .../builder/AbstractConfigBuilder.java | 12 +- .../builder/CommonConfigBuilder.java | 6 +- .../configuration/function/ValueHandler.java | 6 +- .../source/ConfigurationFactory.java | 2 +- ...Provider.java => ConfigurationHolder.java} | 20 +-- .../loader/ConfigInitializeHandler.java | 4 +- .../loader/ConfigurationInitializer.java | 16 +-- .../source/loader/PathGenerator.java | 10 +- .../source/option/StandardOptions.java | 3 +- .../source/section/ConfigurationSource.java | 22 +++- .../lib/configuration/value/ConfigValue.java | 12 +- .../configuration/value/ValueManifest.java | 36 +++--- .../value/impl/CachedConfigValue.java | 6 +- .../value/standard/ConfiguredList.java | 6 +- .../value/standard/ConfiguredMap.java | 10 +- .../value/standard/ConfiguredValue.java | 6 +- core/src/test/java/AdaptTest.java | 4 +- .../java/cc/carm/test/config/LoaderTest.java | 4 +- .../commentable/CommentableMetaTypes.java | 4 +- .../option/FileConfigOptions.java | 10 +- .../source/FileConfigProvider.java | 87 ------------- .../source/FileConfigSource.java | 121 +++++++++++++++++- .../configuration/source/FileProvider.java | 21 --- .../json/JSONConfigProvider.java | 8 +- .../configuration/json/JSONConfigSource.java | 109 ++++++++++++++++ .../json/JSONConfigurationSection.java | 53 ++++++++ 30 files changed, 402 insertions(+), 218 deletions(-) rename core/src/main/java/cc/carm/lib/configuration/source/{ConfigurationProvider.java => ConfigurationHolder.java} (83%) delete mode 100644 features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigProvider.java delete mode 100644 features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java create mode 100644 providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigSource.java create mode 100644 providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigurationSection.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 9785e04..190bbcd 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 @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.adapter; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -53,13 +53,13 @@ public class ValueAdapter } @Override - public Object serialize(@NotNull ConfigurationProvider provider, @NotNull ValueType type, @NotNull TYPE value) throws Exception { + 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); } @Override - public TYPE parse(@NotNull ConfigurationProvider provider, @NotNull ValueType type, @NotNull Object value) throws Exception { + 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); } 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 d03eba4..1cf7861 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 @@ -1,7 +1,7 @@ package cc.carm.lib.configuration.adapter; import cc.carm.lib.configuration.function.DataFunction; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -100,12 +100,12 @@ public class ValueAdapterRegistry { } @Contract("_,_,null -> null") - public T deserialize(@NotNull ConfigurationProvider provider, @NotNull Class type, @Nullable Object source) throws Exception { + public T deserialize(@NotNull ConfigurationHolder holder, @NotNull Class type, @Nullable Object source) throws Exception { return deserialize(provider, ValueType.of(type), source); } @Contract("_,_,null -> null") - public T deserialize(@NotNull ConfigurationProvider provider, @NotNull ValueType type, @Nullable Object source) throws Exception { + public T deserialize(@NotNull ConfigurationHolder holder, @NotNull ValueType type, @Nullable Object source) throws Exception { if (source == null) return null; // Null check if (type.isInstance(source)) return type.cast(source); // Not required to deserialize ValueAdapter adapter = adapterOf(type); @@ -114,7 +114,7 @@ public class ValueAdapterRegistry { } @Contract("_,null -> null") - public Object serialize(@NotNull ConfigurationProvider provider, @Nullable T value) throws Exception { + public Object serialize(@NotNull ConfigurationHolder holder, @Nullable T value) throws Exception { if (value == null) return null; // Null check ValueType type = ValueType.of(value); ValueAdapter adapter = adapterOf(type); diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java index d375456..e5162b4 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueParser.java @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.adapter; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import org.jetbrains.annotations.NotNull; /** @@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull; public interface ValueParser { TYPE parse( - @NotNull ConfigurationProvider provider, + @NotNull ConfigurationHolder holder, @NotNull ValueType type, @NotNull Object data ) throws Exception; diff --git a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java index 44db8a9..37e74e0 100644 --- a/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java +++ b/core/src/main/java/cc/carm/lib/configuration/adapter/ValueSerializer.java @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.adapter; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import org.jetbrains.annotations.NotNull; /** @@ -12,7 +12,7 @@ import org.jetbrains.annotations.NotNull; public interface ValueSerializer { Object serialize( - @NotNull ConfigurationProvider provider, + @NotNull ConfigurationHolder holder, @NotNull ValueType type, @NotNull TYPE value ) throws Exception; diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java index cf59996..d2ebac1 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java @@ -1,7 +1,7 @@ package cc.carm.lib.configuration.builder; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.value.ConfigValue; @@ -14,7 +14,7 @@ import java.util.function.Consumer; import java.util.function.Supplier; public abstract class AbstractConfigBuilder< - TYPE, RESULT extends ConfigValue, PROVIDER extends ConfigurationProvider, + TYPE, RESULT extends ConfigValue, PROVIDER extends ConfigurationHolder, SELF extends AbstractConfigBuilder > { @@ -25,7 +25,7 @@ public abstract class AbstractConfigBuilder< protected @Nullable String path; protected @NotNull Supplier defaultValueSupplier = () -> null; - protected @NotNull BiConsumer, String> initializer = (provider, path) -> { + protected @NotNull BiConsumer, String> initializer = (provider, path) -> { }; protected AbstractConfigBuilder(Class providerClass, ValueType type) { @@ -51,16 +51,16 @@ public abstract class AbstractConfigBuilder< return self(); } - public @NotNull SELF initializer(@NotNull BiConsumer, String> initializer) { + public @NotNull SELF initializer(@NotNull BiConsumer, String> initializer) { this.initializer = initializer; return self(); } - public @NotNull SELF append(@NotNull BiConsumer, String> initializer) { + public @NotNull SELF append(@NotNull BiConsumer, String> initializer) { return initializer(initializer.andThen(initializer)); } - public @NotNull SELF append(@NotNull Consumer> initializer) { + public @NotNull SELF append(@NotNull Consumer> initializer) { return append((provider, path) -> initializer.accept(provider)); } diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java index 1d52039..03dff8d 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/CommonConfigBuilder.java @@ -1,14 +1,14 @@ package cc.carm.lib.configuration.builder; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.value.ConfigValue; public abstract class CommonConfigBuilder, SELF extends CommonConfigBuilder> - extends AbstractConfigBuilder, SELF> { + extends AbstractConfigBuilder, SELF> { protected CommonConfigBuilder(ValueType type) { - super(ConfigurationProvider.class, type); + super(ConfigurationHolder.class, type); } } 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 9f24b8d..6dac39b 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 @@ -2,7 +2,7 @@ package cc.carm.lib.configuration.function; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,7 +12,7 @@ import java.util.Objects; @FunctionalInterface public interface ValueHandler { - @Nullable R handle(@NotNull ConfigurationProvider provider, @NotNull T data) throws Exception; + @Nullable R handle(@NotNull ConfigurationHolder holder, @NotNull T data) throws Exception; default ValueHandler andThen(@NotNull ValueHandler after) { Objects.requireNonNull(after); @@ -47,7 +47,7 @@ public interface ValueHandler { @Contract(pure = true) static @NotNull ValueHandler toObject() { - return ConfigurationProvider::serialize; + return ConfigurationHolder::serialize; } @Contract(pure = true) 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 23d734e..33ad652 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 @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; import java.util.function.Consumer; import java.util.function.Function; -public abstract class ConfigurationFactory, PROVIDER extends ConfigurationProvider, SELF> { +public abstract class ConfigurationFactory, PROVIDER extends ConfigurationHolder, SELF> { protected Function loaderFunction = PROVIDER -> new ConfigurationInitializer(); protected Consumer loaderConsumer = loader -> { diff --git a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationHolder.java similarity index 83% rename from core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java rename to core/src/main/java/cc/carm/lib/configuration/source/ConfigurationHolder.java index 9749984..441456e 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationProvider.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/ConfigurationHolder.java @@ -13,22 +13,22 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Map; +import java.util.Objects; -public class ConfigurationProvider> { +public class ConfigurationHolder> { - protected final @NotNull S source; protected final @NotNull ValueAdapterRegistry adapters; protected final @NotNull ConfigurationOptionHolder options; protected final @NotNull Map metadata; protected final @NotNull ConfigurationInitializer initializer; - public ConfigurationProvider(@NotNull S source, - @NotNull ValueAdapterRegistry adapters, - @NotNull ConfigurationOptionHolder options, - @NotNull Map metadata, - @NotNull ConfigurationInitializer initializer) { - this.source = source; + protected @Nullable S source; + + public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters, + @NotNull ConfigurationOptionHolder options, + @NotNull Map metadata, + @NotNull ConfigurationInitializer initializer) { this.initializer = initializer; this.adapters = adapters; this.options = options; @@ -36,7 +36,7 @@ public class ConfigurationProvider> { } public @NotNull S source() { - return source; + return Objects.requireNonNull(source, "Source is not initialized"); } public void reload() throws Exception { @@ -100,7 +100,7 @@ public class ConfigurationProvider> { } public void load(@NotNull ValueManifest value) { - value.provider(this); + value.holder(this); } } diff --git a/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigInitializeHandler.java b/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigInitializeHandler.java index 2ffe1b8..1b1ba35 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigInitializeHandler.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/loader/ConfigInitializeHandler.java @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.source.loader; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,7 +12,7 @@ public interface ConfigInitializeHandler { }; } - void whenInitialize(@NotNull ConfigurationProvider provider, @Nullable String path, @NotNull T value) throws Exception; + void whenInitialize(@NotNull ConfigurationHolder holder, @Nullable String path, @NotNull T value) throws Exception; default ConfigInitializeHandler andThen(ConfigInitializeHandler after) { return (provider, path, value) -> { 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 2463752..38c52f4 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 @@ -1,7 +1,7 @@ package cc.carm.lib.configuration.source.loader; import cc.carm.lib.configuration.Configuration; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.option.StandardOptions; import cc.carm.lib.configuration.value.ConfigValue; @@ -83,28 +83,28 @@ public class ConfigurationInitializer { } - public @Nullable String getFieldPath(ConfigurationProvider provider, @Nullable String parentPath, @NotNull Field field) { + public @Nullable String getFieldPath(ConfigurationHolder holder, @Nullable String parentPath, @NotNull Field field) { return pathGenerator.getFieldPath(provider, parentPath, field); } - public @Nullable String getClassPath(ConfigurationProvider provider, @Nullable String parentPath, + public @Nullable String getClassPath(ConfigurationHolder holder, @Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField) { return pathGenerator.getClassPath(provider, parentPath, clazz, clazzField); } - public void initialize(ConfigurationProvider provider, @NotNull Configuration config) throws Exception { + public void initialize(ConfigurationHolder holder, @NotNull Configuration config) throws Exception { initializeInstance(provider, config, null, null); if (provider.options().get(StandardOptions.SET_DEFAULTS)) provider.save(); } - public void initialize(ConfigurationProvider provider, @NotNull Class clazz) throws Exception { + public void initialize(ConfigurationHolder holder, @NotNull Class clazz) throws Exception { initializeStaticClass(provider, clazz, null, null); if (provider.options().get(StandardOptions.SET_DEFAULTS)) provider.save(); } // 针对实例类的初始化方法 - protected void initializeInstance(@NotNull ConfigurationProvider provider, + protected void initializeInstance(@NotNull ConfigurationHolder holder, @NotNull Configuration root, @Nullable String parentPath, @Nullable Field configField) { String path = getClassPath(provider, parentPath, root.getClass(), configField); try { @@ -117,7 +117,7 @@ public class ConfigurationInitializer { // 针对静态类的初始化方法 @SuppressWarnings("unchecked") - protected void initializeStaticClass(@NotNull ConfigurationProvider provider, + protected void initializeStaticClass(@NotNull ConfigurationHolder holder, @NotNull Class clazz, @Nullable String parentPath, @Nullable Field configField) { if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类 @@ -141,7 +141,7 @@ public class ConfigurationInitializer { } } - protected void initializeField(@NotNull ConfigurationProvider provider, + protected void initializeField(@NotNull ConfigurationHolder holder, @NotNull Object source, @NotNull Field field, @Nullable String parent) { try { field.setAccessible(true); 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 0f2dd10..7eb552f 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 @@ -1,7 +1,7 @@ package cc.carm.lib.configuration.source.loader; import cc.carm.lib.configuration.annotation.ConfigPath; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.option.StandardOptions; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -37,14 +37,14 @@ public class PathGenerator { return pathConverter.apply(name); } - public @Nullable String getFieldPath(@NotNull ConfigurationProvider provider, + 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())); } - public @Nullable String getClassPath(@NotNull ConfigurationProvider provider, + public @Nullable String getClassPath(@NotNull ConfigurationHolder holder, @Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField) { // For standard path generator, we generate path following by: // 1. Check if the class has a ConfigPath annotation, if so, use the root and value as the path. @@ -67,7 +67,7 @@ public class PathGenerator { else return isBlank(path) ? null : path; } - protected @Nullable String link(@NotNull ConfigurationProvider provider, + 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); @@ -77,7 +77,7 @@ public class PathGenerator { return path == null || path.replace(" ", "").isEmpty(); } - public static char pathSeparator(ConfigurationProvider provider) { + public static char pathSeparator(ConfigurationHolder holder) { return provider.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 a14c641..ad6221e 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 @@ -1,6 +1,7 @@ package cc.carm.lib.configuration.source.option; import cc.carm.lib.configuration.Configuration; +import cc.carm.lib.configuration.source.ConfigurationHolder; import static cc.carm.lib.configuration.source.option.ConfigurationOption.of; @@ -26,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 cc.carm.lib.configuration.source.ConfigurationProvider#load(Configuration)}. + * {@link ConfigurationHolder#load(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 index fd27553..734746c 100644 --- 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 @@ -1,19 +1,27 @@ 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 long updateMillis; + protected final @NotNull ConfigurationHolder holder; + protected long lastUpdateMillis; - protected ConfigurationSource(long updateMillis) { - this.updateMillis = updateMillis; + 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.updateMillis = System.currentTimeMillis(); + this.lastUpdateMillis = System.currentTimeMillis(); } protected abstract SELF self(); @@ -27,12 +35,12 @@ public abstract class ConfigurationSource parsedTime; + return getLastUpdateMillis() > parsedTime; } } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java index 05459b2..70557d6 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/ConfigValue.java @@ -1,6 +1,6 @@ package cc.carm.lib.configuration.value; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -46,7 +46,7 @@ public abstract class ConfigValue extends ValueManifest { /** * 设定该配置的值。 - *
设定后,不会自动保存配置文件;若需要保存,请调用 {@link ConfigurationProvider#save()} 方法。 + *
设定后,不会自动保存配置文件;若需要保存,请调用 {@link ConfigurationHolder#save()} 方法。 * * @param value 配置的值 */ @@ -54,7 +54,7 @@ public abstract class ConfigValue extends ValueManifest { /** * 初始化该配置的默认值。 - *
设定后,不会自动保存配置文件;若需要保存,请调用 {@link ConfigurationProvider#save()} 方法。 + *
设定后,不会自动保存配置文件;若需要保存,请调用 {@link ConfigurationHolder#save()} 方法。 */ public void setDefault() { setDefault(false); @@ -62,7 +62,7 @@ public abstract class ConfigValue extends ValueManifest { /** * 将该配置的值设置为默认值。 - *
设定后,不会自动保存配置文件;若需要保存,请调用 {@link ConfigurationProvider#save()} 方法。 + *
设定后,不会自动保存配置文件;若需要保存,请调用 {@link ConfigurationHolder#save()} 方法。 * * @param override 是否覆盖已设定的值 */ @@ -83,13 +83,13 @@ public abstract class ConfigValue extends ValueManifest { /** * Try to save the configuration. *
To save multiple modifications, - * it is recommended to call {@link ConfigurationProvider#save()} + * it is recommended to call {@link ConfigurationHolder#save()} * after all modifications are completed instead of this. * * @throws Exception */ public void save() throws Exception { - provider().save(); + holder().save(); } } 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 6ccdd01..d9a6530 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 @@ -1,7 +1,7 @@ package cc.carm.lib.configuration.value; import cc.carm.lib.configuration.adapter.ValueType; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.section.ConfigurationSource; import org.jetbrains.annotations.NotNull; @@ -13,9 +13,9 @@ import java.util.function.Supplier; public class ValueManifest { protected final @NotNull ValueType type; - protected final @NotNull BiConsumer<@NotNull ConfigurationProvider, @NotNull String> initializer; + protected final @NotNull BiConsumer<@NotNull ConfigurationHolder, @NotNull String> initializer; - protected @Nullable ConfigurationProvider provider; + protected @Nullable ConfigurationHolder holder; protected @Nullable String path; // Section path protected @NotNull Supplier<@Nullable T> defaultSupplier; @@ -34,41 +34,41 @@ public class ValueManifest { } public ValueManifest(@NotNull ValueType type, @NotNull Supplier<@Nullable T> defaultSupplier, - @NotNull BiConsumer<@NotNull ConfigurationProvider, @NotNull String> initializer) { + @NotNull BiConsumer<@NotNull ConfigurationHolder, @NotNull String> initializer) { this(type, defaultSupplier, initializer, null, null); } public ValueManifest(@NotNull ValueType type, @NotNull Supplier<@Nullable T> defaultSupplier, - @NotNull BiConsumer<@NotNull ConfigurationProvider, @NotNull String> initializer, - @Nullable ConfigurationProvider provider, @Nullable String path) { + @NotNull BiConsumer<@NotNull ConfigurationHolder, @NotNull String> initializer, + @Nullable ConfigurationHolder holder, @Nullable String path) { this.type = type; this.initializer = initializer; this.defaultSupplier = defaultSupplier; - this.provider = provider; + this.holder = holder; this.path = path; initialize(); } protected ValueManifest(@NotNull ValueManifest manifest) { - this(manifest.type, manifest.defaultSupplier, manifest.initializer, manifest.provider, manifest.path); + this(manifest.type, manifest.defaultSupplier, manifest.initializer, manifest.holder, manifest.path); } - public void initialize(@NotNull ConfigurationProvider provider, @NotNull String path) { - this.provider = provider; + public void initialize(@NotNull ConfigurationHolder holder, @NotNull String path) { + this.holder = holder; this.path = path; initialize(); } protected void initialize() { - if (provider != null && path != null) this.initializer.accept(provider, path); + if (holder != null && path != null) this.initializer.accept(holder, path); } public @NotNull ValueType type() { return this.type; } - public void provider(@NotNull ConfigurationProvider provider) { - this.provider = provider; + public void holder(@NotNull ConfigurationHolder holder) { + this.holder = holder; } public void path(@NotNull String path) { @@ -96,17 +96,17 @@ public class ValueManifest { else throw new IllegalStateException("No section path provided."); } - public @NotNull ConfigurationProvider provider() { - if (this.provider != null) return this.provider; + public @NotNull ConfigurationHolder holder() { + if (this.holder != null) return this.holder; throw new IllegalStateException("Value does not have a provider."); } public @NotNull ConfigurationSource config() { - return provider().source(); + return holder().source(); } public ConfigurationMetaHolder metadata() { - return provider().metadata(path()); + return holder().metadata(path()); } protected Object getData() { @@ -118,7 +118,7 @@ public class ValueManifest { } - private static final @NotNull BiConsumer<@NotNull ConfigurationProvider, @NotNull String> EMPTY_INITIALIZER = (provider, path) -> { + private static final @NotNull BiConsumer<@NotNull ConfigurationHolder, @NotNull String> EMPTY_INITIALIZER = (provider, path) -> { }; } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java index 7f52e43..802a00a 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/impl/CachedConfigValue.java @@ -28,7 +28,7 @@ public abstract class CachedConfigValue extends ConfigValue { return cachedValue; } - public boolean isExpired() { + public boolean cacheExpired() { return this.parsedTime <= 0 || config().isExpired(this.parsedTime); } @@ -63,7 +63,7 @@ public abstract class CachedConfigValue extends ConfigValue { */ protected @Nullable ValueParser parserFor(@NotNull ValueAdapter adapter) { if (adapter.parser() != null) return adapter.parser(); - ValueAdapter registered = provider().adapters().adapterOf(adapter.type()); + ValueAdapter registered = holder().adapters().adapterOf(adapter.type()); if (registered == null) return null; return registered.parser(); } @@ -73,7 +73,7 @@ public abstract class CachedConfigValue extends ConfigValue { */ protected @Nullable ValueSerializer serializerFor(@NotNull ValueAdapter adapter) { if (adapter.serializer() != null) return adapter.serializer(); - ValueAdapter registered = provider().adapters().adapterOf(adapter.type()); + ValueAdapter registered = holder().adapters().adapterOf(adapter.type()); if (registered == null) return null; return registered.serializer(); } diff --git a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java index 1c2e02a..5cebea2 100644 --- a/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java +++ b/core/src/main/java/cc/carm/lib/configuration/value/standard/ConfiguredList.java @@ -67,7 +67,7 @@ public class ConfiguredList extends CachedConfigValue> implements Lis @Override public @NotNull List get() { - if (!isExpired()) return getCachedOrDefault(createList()); + if (!cacheExpired()) return getCachedOrDefault(createList()); // Data that is outdated and needs to be parsed again. List list = createList(); List data = config().contains(path()) ? config().getList(path()) : null; @@ -79,7 +79,7 @@ public class ConfiguredList extends CachedConfigValue> implements Lis for (Object dataVal : data) { if (dataVal == null) continue; try { - list.add(parser.parse(provider(), paramType(), dataVal)); + list.add(parser.parse(holder(), paramType(), dataVal)); } catch (Exception e) { e.printStackTrace(); } @@ -101,7 +101,7 @@ public class ConfiguredList extends CachedConfigValue> implements Lis for (V val : value) { if (val == null) continue; try { - data.add(serializer.serialize(provider(), paramType(), val)); + data.add(serializer.serialize(holder(), paramType(), val)); } catch (Exception ex) { ex.printStackTrace(); } 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 4eb4a1d..f01a390 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 @@ -54,7 +54,7 @@ public class ConfiguredMap extends CachedConfigValue> implements @Override public @NotNull Map get() { - if (!isExpired()) return getCachedOrDefault(createMap()); + if (!cacheExpired()) return getCachedOrDefault(createMap()); // If the value is expired, we need to update it Map map = createMap(); @@ -72,8 +72,8 @@ public class ConfiguredMap extends CachedConfigValue> implements Object dataVal = section.get(dataKey); if (dataVal == null) continue; try { - K key = keyParser.parse(provider(), keyType(), dataKey); - V value = valueParser.parse(provider(), valueType(), dataVal); + K key = keyParser.parse(holder(), keyType(), dataKey); + V value = valueParser.parse(holder(), valueType(), dataVal); map.put(key, value); } catch (Exception e) { e.printStackTrace(); @@ -109,8 +109,8 @@ public class ConfiguredMap extends CachedConfigValue> implements for (Map.Entry entry : value.entrySet()) { try { data.put( - keySerializer.serialize(provider(), keyType(), entry.getKey()), - valueSerializer.serialize(provider(), valueType(), entry.getValue()) + keySerializer.serialize(holder(), keyType(), entry.getKey()), + valueSerializer.serialize(holder(), valueType(), entry.getValue()) ); } catch (Exception e) { e.printStackTrace(); 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 8df3683..6565daf 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 @@ -89,7 +89,7 @@ public class ConfiguredValue extends CachedConfigValue { @Override public V get() { - if (!isExpired()) return getCachedOrDefault(); + if (!cacheExpired()) return getCachedOrDefault(); // Data that is outdated and needs to be parsed again. Object data = getData(); @@ -100,7 +100,7 @@ public class ConfiguredValue extends CachedConfigValue { try { // If there are no errors, update the cache and return. - return updateCache(parser.parse(provider(), type(), data)); + return updateCache(parser.parse(holder(), type(), data)); } catch (Exception e) { // There was a parsing error, prompted and returned the default value. e.printStackTrace(); @@ -127,7 +127,7 @@ public class ConfiguredValue extends CachedConfigValue { if (serializer == null) return; // No serializer, do nothing. try { - setData(serializer.serialize(provider(), type(), value)); + setData(serializer.serialize(holder(), type(), value)); } catch (Exception e) { e.printStackTrace(); } diff --git a/core/src/test/java/AdaptTest.java b/core/src/test/java/AdaptTest.java index 99dbace..11b9039 100644 --- a/core/src/test/java/AdaptTest.java +++ b/core/src/test/java/AdaptTest.java @@ -1,7 +1,7 @@ import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; import cc.carm.lib.configuration.adapter.ValueType; import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter; -import cc.carm.lib.configuration.source.ConfigurationProvider; +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; @@ -28,7 +28,7 @@ public class AdaptTest { data -> Duration.between(LocalTime.now(), data) ); - ConfigurationProvider provider = new ConfigurationProvider<>( + ConfigurationHolder provider = new ConfigurationHolder<>( new TestSource(), registry, new ConfigurationOptionHolder(), new ConcurrentHashMap<>(), new ConfigurationInitializer() ); 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 b42e961..5d0393e 100644 --- a/core/src/test/java/cc/carm/test/config/LoaderTest.java +++ b/core/src/test/java/cc/carm/test/config/LoaderTest.java @@ -3,7 +3,7 @@ package cc.carm.test.config; import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; import cc.carm.lib.configuration.annotation.ConfigPath; import cc.carm.lib.configuration.Configuration; -import cc.carm.lib.configuration.source.ConfigurationProvider; +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.junit.Test; @@ -14,7 +14,7 @@ public class LoaderTest { @Test public void test() throws Exception { - ConfigurationProvider provider = new ConfigurationProvider<>( + ConfigurationHolder provider = new ConfigurationHolder<>( new TestSource(), new ValueAdapterRegistry(), new ConfigurationOptionHolder(), new ConcurrentHashMap<>(), new ConfigurationInitializer() ); diff --git a/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java b/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java index b18433e..d328e6d 100644 --- a/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java +++ b/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java @@ -2,7 +2,7 @@ package cc.carm.lib.configuration.commentable; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.annotation.InlineComment; -import cc.carm.lib.configuration.source.ConfigurationProvider; +import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import org.jetbrains.annotations.NotNull; @@ -24,7 +24,7 @@ public interface CommentableMetaTypes { ConfigurationMetadata INLINE_COMMENT = ConfigurationMetadata.of(); - static void register(@NotNull ConfigurationProvider provider) { + static void register(@NotNull ConfigurationHolder provider) { register(provider.initializer()); } diff --git a/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java b/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java index 30741e7..ee950a6 100644 --- a/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java +++ b/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java @@ -2,8 +2,16 @@ package cc.carm.lib.configuration.option; import cc.carm.lib.configuration.source.option.ConfigurationOption; -public class FileConfigOptions { +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +public interface FileConfigOptions { + + /** + * The charset of the file. + */ + ConfigurationOption CHARSET = ConfigurationOption.of(StandardCharsets.UTF_8); + /** * Whether to copy files from resource if exists. */ diff --git a/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigProvider.java b/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigProvider.java deleted file mode 100644 index 41bdea1..0000000 --- a/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigProvider.java +++ /dev/null @@ -1,87 +0,0 @@ -//package cc.carm.lib.configuration.core.source.impl; -// -//import org.jetbrains.annotations.NotNull; -//import org.jetbrains.annotations.Nullable; -// -//import java.io.File; -//import java.io.IOException; -//import java.io.InputStream; -//import java.io.OutputStream; -//import java.net.URL; -//import java.net.URLConnection; -//import java.nio.file.Files; -//import java.util.Objects; -// -//public abstract class FileConfigProvider> extends ConfigurationProvider { -// -// protected final @NotNull File file; -// -// protected FileConfigProvider(@NotNull File file) { -// this.file = file; -// } -// -// public @NotNull File getFile() { -// return file; -// } -// -// public void initializeFile(@Nullable String sourcePath) throws IOException { -// if (this.file.exists()) return; -// -// File parent = this.file.getParentFile(); -// if (parent != null && !parent.exists() && !parent.mkdirs()) { -// throw new IOException("Failed to create directory " + file.getParentFile().getAbsolutePath()); -// } -// -// if (!this.file.createNewFile()) { -// throw new IOException("Failed to create file " + file.getAbsolutePath()); -// } -// -// if (sourcePath != null) { -// try { -// saveResource(sourcePath, true); -// } catch (IllegalArgumentException ignored) { -// } -// } -// } -// -// public void saveResource(@NotNull String resourcePath, boolean replace) -// throws IOException, IllegalArgumentException { -// Objects.requireNonNull(resourcePath, "ResourcePath cannot be null"); -// if (resourcePath.isEmpty()) throw new IllegalArgumentException("ResourcePath cannot be empty"); -// -// resourcePath = resourcePath.replace('\\', '/'); -// -// URL url = this.getClass().getClassLoader().getResource(resourcePath); -// if (url == null) throw new IllegalArgumentException("The resource '" + resourcePath + "' not exists"); -// -// File outDir = file.getParentFile(); -// -// if (!outDir.exists() && !outDir.mkdirs()) throw new IOException("Failed to create directory " + outDir); -// if (!file.exists() || replace) { -// try (OutputStream out = Files.newOutputStream(file.toPath())) { -// URLConnection connection = url.openConnection(); -// connection.setUseCaches(false); -// try (InputStream in = connection.getInputStream()) { -// byte[] buf = new byte[1024]; -// int len; -// while ((len = in.read(buf)) > 0) { -// out.write(buf, 0, len); -// } -// } -// } -// } -// } -// -// @Nullable -// public InputStream getResource(@NotNull String filename) { -// try { -// URL url = this.getClass().getClassLoader().getResource(filename); -// if (url == null) return null; -// URLConnection connection = url.openConnection(); -// connection.setUseCaches(false); -// return connection.getInputStream(); -// } catch (IOException ex) { -// return null; -// } -// } -//} 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 c189461..0c28dee 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 @@ -1,6 +1,125 @@ package cc.carm.lib.configuration.source; -public class FileConfigSource { +import cc.carm.lib.configuration.function.DataFunction; +import cc.carm.lib.configuration.option.FileConfigOptions; +import cc.carm.lib.configuration.source.section.ConfigurationSource; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.Objects; +import java.util.function.Consumer; + +public abstract class FileConfigSource, ORIGINAL> + extends ConfigurationSource { + + protected final @NotNull File file; + protected final @Nullable String resourcePath; + + protected FileConfigSource(@NotNull ConfigurationHolder holder, long lastUpdateMillis, + @NotNull File file, @Nullable String resourcePath) { + super(holder, lastUpdateMillis); + this.file = file; + this.resourcePath = resourcePath; + } + + public Charset charset() { + return holder().options().get(FileConfigOptions.CHARSET); + } + + public boolean copyDefaults() { + return holder().options().get(FileConfigOptions.COPY_DEFAULTS); + } + + + public void initializeFile() throws IOException { + if (this.file.exists()) return; + + File parent = this.file.getParentFile(); + if (parent != null && !parent.exists() && !parent.mkdirs()) { + throw new IOException("Failed to create directory " + file.getParentFile().getAbsolutePath()); + } + + if (!this.file.createNewFile()) { + throw new IOException("Failed to create file " + file.getAbsolutePath()); + } + + if (resourcePath != null && copyDefaults()) { + try { + saveResource(resourcePath, false); + } catch (IllegalArgumentException ignored) { + } + } + } + + protected R fileInputStream(@NotNull DataFunction loader) { + try (FileInputStream is = new FileInputStream(file)) { + return loader.handle(is); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + protected R fileReader(@NotNull DataFunction loader) { + return fileInputStream(is -> loader.handle(new InputStreamReader(is, charset()))); + } + + protected void fileOutputStream(@NotNull Consumer stream) { + try (FileOutputStream os = new FileOutputStream(file)) { + stream.accept(os); + } catch (Exception e) { + e.printStackTrace(); + } + } + + protected void fileWriter(@NotNull Consumer writer) { + fileOutputStream(os -> writer.accept(new OutputStreamWriter(os, charset()))); + } + + protected void saveResource(@NotNull String resourcePath, boolean replace) + throws IOException, IllegalArgumentException { + Objects.requireNonNull(resourcePath, "ResourcePath cannot be null"); + if (resourcePath.isEmpty()) throw new IllegalArgumentException("ResourcePath cannot be empty"); + + resourcePath = resourcePath.replace('\\', '/'); + + URL url = this.getClass().getClassLoader().getResource(resourcePath); + if (url == null) throw new IllegalArgumentException("The resource '" + resourcePath + "' not exists"); + + File outDir = file.getParentFile(); + + if (!outDir.exists() && !outDir.mkdirs()) throw new IOException("Failed to create directory " + outDir); + if (!file.exists() || replace) { + try (OutputStream out = Files.newOutputStream(file.toPath())) { + URLConnection connection = url.openConnection(); + connection.setUseCaches(false); + try (InputStream in = connection.getInputStream()) { + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + } + } + } + } + + @Nullable + protected InputStream getResource(@NotNull String filename) { + try { + URL url = this.getClass().getClassLoader().getResource(filename); + if (url == null) return null; + URLConnection connection = url.openConnection(); + connection.setUseCaches(false); + return connection.getInputStream(); + } catch (IOException ex) { + return null; + } + } } diff --git a/features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java b/features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java deleted file mode 100644 index 67cc8a8..0000000 --- a/features/file/src/main/java/cc/carm/lib/configuration/source/FileProvider.java +++ /dev/null @@ -1,21 +0,0 @@ -package cc.carm.lib.configuration.source; - -import cc.carm.lib.configuration.adapter.ValueAdapterRegistry; -import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; -import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; -import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; -import cc.carm.lib.configuration.source.section.ConfigurationSource; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; - -public abstract class FileProvider> extends ConfigurationProvider { - - public FileProvider(@NotNull S source, @NotNull ConfigurationInitializer loader, - @NotNull ValueAdapterRegistry adapters, @NotNull ConfigurationOptionHolder options, - @NotNull Map, Object>> pathMetadata) { - super(source, loader, adapters, options, pathMetadata); - } - - -} 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 index 74865ee..976f712 100644 --- 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 @@ -1,7 +1,6 @@ package cc.carm.lib.configuration.json; import cc.carm.lib.configuration.source.comment.ConfigurationComments; -import cc.carm.lib.configuration.core.source.impl.FileConfigProvider; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonSerializer; @@ -20,12 +19,7 @@ import java.util.LinkedHashMap; */ public class JSONConfigProvider extends FileConfigProvider { - protected final Gson gson = new GsonBuilder() - .serializeNulls().disableHtmlEscaping().setPrettyPrinting() - .registerTypeAdapter( - JSONConfigWrapper.class, - (JsonSerializer) (src, typeOfSrc, context) -> context.serialize(src.data) - ).create(); + protected JSONConfigWrapper configuration; protected ConfigInitializer 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 new file mode 100644 index 0000000..59499c6 --- /dev/null +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigSource.java @@ -0,0 +1,109 @@ +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/JSONConfigurationSection.java b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigurationSection.java new file mode 100644 index 0000000..bda7daf --- /dev/null +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigurationSection.java @@ -0,0 +1,53 @@ +package cc.carm.lib.configuration.json; + +import cc.carm.lib.configuration.source.section.ConfigurationSection; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class JSONConfigurationSection implements ConfigurationSection { + + + @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; + } +} From c68d2371eebda3b26e8746b9121e9263d284ec33 Mon Sep 17 00:00:00 2001 From: Carm Date: Wed, 12 Feb 2025 02:35:59 +0800 Subject: [PATCH 12/17] feat(comment): Support regex inline comments --- .../annotation/InlineComment.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/features/commentable/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java b/features/commentable/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java index d042da4..763f896 100644 --- a/features/commentable/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java +++ b/features/commentable/src/main/java/cc/carm/lib/configuration/annotation/InlineComment.java @@ -31,4 +31,23 @@ public @interface InlineComment { @NotNull String value() default ""; + /** + * If the regex is not empty, the comment will be added to + * all sub paths if the regex matches the value. + * If the regex is empty, the comment will be added to the current path. + *

e.g. "^foo\\.*\\.bar" will be set like + *

+     *     foo:
+     *       some:
+     *         lover: "bar" <- not matched so no comments
+     *         bar: "foobar" # Comment Contents
+     *       other:
+     *         bar: "foobar" # Comment Contents
+     * 
+ * + * @return The path regexes of this comment + */ + @NotNull + String[] regex() default {}; + } From 05ff61a9d9b5d4d8337e73e28841515c1b235d3e Mon Sep 17 00:00:00 2001 From: Carm Date: Wed, 12 Feb 2025 04:25:29 +0800 Subject: [PATCH 13/17] 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); } From 79f59bafe60efc565fb22cf61536dd60fdc4c235 Mon Sep 17 00:00:00 2001 From: Carm Date: Thu, 13 Feb 2025 01:30:10 +0800 Subject: [PATCH 14/17] feat(json): Finished json version's provider --- .../configuration/annotation/ConfigPath.java | 2 +- .../builder/AbstractConfigBuilder.java | 2 +- .../loader/ConfigurationInitializer.java | 22 +++++++----- .../source/loader/PathGenerator.java | 23 ++++++------ .../demo/tests/ConfigurationTest.java | 36 +++++++++---------- .../demo/tests/conf/DemoConfiguration.java | 19 +++++----- ...Configuration.java => InstanceConfig.java} | 2 +- .../demo/tests/conf/OtherConfiguration.java | 4 --- ...Configuration.java => RegistryConfig.java} | 15 ++++---- ...AbstractModel.java => AbstractRecord.java} | 4 +-- .../model/{TestModel.java => UserRecord.java} | 20 ++++++----- .../source/FileConfigSource.java | 23 ++++++++---- pom.xml | 2 +- .../lib/configuration/json/JSONSection.java | 10 ++++++ .../src/test/java/config/JSONConfigTest.java | 11 +++++- .../gson/src/test/resources/example.json | 3 ++ .../src/test/java/config/DemoConfigTest.java | 8 ++--- .../src/test/java/config/model/AnyModel.java | 4 +-- .../src/test/java/config/model/SomeModel.java | 4 +-- .../config/source/ModelConfiguration.java | 6 ++-- 20 files changed, 125 insertions(+), 95 deletions(-) rename demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/{TestInnerConfiguration.java => InstanceConfig.java} (86%) delete mode 100644 demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/OtherConfiguration.java rename demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/{TestConfiguration.java => RegistryConfig.java} (59%) rename demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/{AbstractModel.java => AbstractRecord.java} (73%) rename demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/{TestModel.java => UserRecord.java} (65%) create mode 100644 providers/gson/src/test/resources/example.json diff --git a/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java index e8810f8..e84c4ac 100644 --- a/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java +++ b/core/src/main/java/cc/carm/lib/configuration/annotation/ConfigPath.java @@ -14,7 +14,7 @@ public @interface ConfigPath { /** * The path value of the current configuration. - * If not set,will generate the path by {@link PathGenerator}. + * If not set,will generate the path by {@link cc.carm.lib.configuration.source.loader.PathGenerator}. * * @return The path value of the current configuration */ diff --git a/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java b/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java index d2ebac1..a44d2cb 100644 --- a/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/builder/AbstractConfigBuilder.java @@ -41,7 +41,7 @@ public abstract class AbstractConfigBuilder< public abstract @NotNull RESULT build(); - public @NotNull SELF provider(@Nullable PROVIDER provider) { + public @NotNull SELF holder(@Nullable PROVIDER provider) { this.provider = provider; return self(); } 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 5ba01bb..a6f7f42 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 @@ -83,29 +83,31 @@ public class ConfigurationInitializer { } - public @Nullable String getFieldPath(ConfigurationHolder holder, @Nullable String parentPath, @NotNull Field field) { + public @Nullable String getFieldPath(@NotNull ConfigurationHolder holder, @Nullable String parentPath, @NotNull Field field) { return pathGenerator.getFieldPath(holder, parentPath, field); } - public @Nullable String getClassPath(ConfigurationHolder holder, @Nullable String parentPath, + public @Nullable String getClassPath(@NotNull ConfigurationHolder holder, @Nullable String parentPath, @NotNull Class clazz, @Nullable Field clazzField) { return pathGenerator.getClassPath(holder, parentPath, clazz, clazzField); } - public void initialize(ConfigurationHolder holder, @NotNull Configuration config) throws Exception { + public void initialize(@NotNull ConfigurationHolder holder, + @NotNull Configuration config) throws Exception { initializeInstance(holder, config, null, null); if (holder.options().get(StandardOptions.SET_DEFAULTS)) holder.save(); } - public void initialize(ConfigurationHolder holder, @NotNull Class clazz) throws Exception { + public void initialize(@NotNull ConfigurationHolder holder, + @NotNull Class clazz) throws Exception { 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) { + protected void initializeInstance(@NotNull ConfigurationHolder holder, @NotNull Configuration root, + @Nullable String parentPath, @Nullable Field configField) { String path = getClassPath(holder, parentPath, root.getClass(), configField); try { this.classInitializer.whenInitialize(holder, path, root.getClass()); @@ -118,8 +120,9 @@ public class ConfigurationInitializer { // 针对静态类的初始化方法 @SuppressWarnings("unchecked") protected void initializeStaticClass(@NotNull ConfigurationHolder holder, - @NotNull Class clazz, @Nullable String parentPath, @Nullable Field configField) { - if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类 + @NotNull Class clazz, + @Nullable String parentPath, @Nullable Field configField) { + if (!Configuration.class.isAssignableFrom(clazz)) return; // Only Configuration class can be initialized. String path = getClassPath(holder, parentPath, clazz, configField); @@ -158,6 +161,9 @@ public class ConfigurationInitializer { } catch (Exception e) { e.printStackTrace(); } + if (holder.options().get(StandardOptions.SET_DEFAULTS)) { + value.setDefault(); + } } else if (source instanceof Configuration && object instanceof Configuration) { // 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。 initializeInstance(holder, (Configuration) 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 4312fd4..fc2e260 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,9 @@ 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(holder, parentPath, false, field.getName()); // No annotation, use field name. - else return link(holder, parentPath, path.root(), select(path.value(), field.getName())); + if (path == null) + return link(holder, parentPath, false, covertPath(field.getName())); // No annotation, use field name. + else return link(holder, parentPath, path.root(), select(path.value(), covertPath(field.getName()))); } public @Nullable String getClassPath(@NotNull ConfigurationHolder holder, @@ -51,14 +52,14 @@ public class PathGenerator { // 2. If the class defined as a field, check if the field has a ConfigPath annotation, // and use filed information. ConfigPath clazzPath = clazz.getAnnotation(ConfigPath.class); - if (clazzPath != null) return link(holder, parentPath, clazzPath.root(), clazzPath.value()); + if (clazzField == null) { - return link(holder, parentPath, false, clazz.getSimpleName()); // No field, use class name. + return link(holder, parentPath, false, parentPath == null ? null : covertPath(clazz.getSimpleName())); // No field, use class name. } ConfigPath fieldPath = clazzField.getAnnotation(ConfigPath.class); - if (fieldPath == null) return link(holder, parentPath, false, clazzField.getName()); + if (fieldPath == null) return link(holder, parentPath, false, covertPath(clazzField.getName())); else return getFieldPath(holder, parentPath, clazzField); } @@ -70,7 +71,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(holder) + covertPath(path); + return root || parent == null ? path : parent + pathSeparator(holder) + path; } public static boolean isBlank(String path) { @@ -93,16 +94,16 @@ public class PathGenerator { public static String covertPathName(String name) { return name // Replace all uppercase letters with dashes - .replaceAll("[A-Z]", "-$0") + .replaceAll("[A-Z]", "=$0") // If the first letter is also capitalized, // it will also be converted and the first dash will need to be removed - .replaceAll("-(.*)", "$1") + .replaceAll("^=(.*)$", "$1") // Because the name may contain _, it needs to be treated a little differently - .replaceAll("_-([A-Z])", "_$1") + .replaceAll("_=([A-Z])", "_$1") // The content that is not named in all caps is then converted - .replaceAll("([a-z])-([A-Z])", "$1_$2") + .replaceAll("([a-z])=([A-Z])", "$1_$2") // Remove any extra horizontal lines - .replace("-", "") + .replaceAll("=", "") // Replace the underscore with a dash .replace("_", "-") // Finally, convert it to all lowercase 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 b8420a5..1f52303 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 @@ -1,8 +1,8 @@ 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.demo.tests.conf.RegistryConfig; +import cc.carm.lib.configuration.demo.tests.model.UserRecord; import cc.carm.lib.configuration.source.ConfigurationHolder; import org.jetbrains.annotations.TestOnly; @@ -16,7 +16,7 @@ public class ConfigurationTest { @TestOnly public static void testDemo(ConfigurationHolder holder) { try { - holder.initializer().initialize(holder, DemoConfiguration.class); + holder.initialize(DemoConfiguration.class); } catch (Exception e) { e.printStackTrace(); } @@ -30,27 +30,27 @@ public class ConfigurationTest { System.out.println("after: " + DemoConfiguration.TEST_NUMBER.get()); System.out.println("> Test Value:"); - System.out.println("before: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get()); - DemoConfiguration.Sub.UUID_CONFIG_VALUE.set(UUID.randomUUID()); - System.out.println("after: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get()); + System.out.println("before: " + DemoConfiguration.SUB.UUID_CONFIG_VALUE.get()); + DemoConfiguration.SUB.UUID_CONFIG_VALUE.set(UUID.randomUUID()); + System.out.println("after: " + DemoConfiguration.SUB.UUID_CONFIG_VALUE.get()); System.out.println("> Test List:"); System.out.println(" Before:"); - DemoConfiguration.Sub.That.OPERATORS.forEach(System.out::println); + DemoConfiguration.SUB.That.OPERATORS.forEach(System.out::println); List operators = IntStream.range(0, 5).mapToObj(i -> UUID.randomUUID()).collect(Collectors.toList()); - DemoConfiguration.Sub.That.OPERATORS.set(operators); + DemoConfiguration.SUB.That.OPERATORS.set(operators); System.out.println(" After:"); - DemoConfiguration.Sub.That.OPERATORS.forEach(System.out::println); + DemoConfiguration.SUB.That.OPERATORS.forEach(System.out::println); System.out.println("> Clear List:"); - System.out.println(" Before: size :" + DemoConfiguration.Sub.That.OPERATORS.size()); - DemoConfiguration.Sub.That.OPERATORS.modify(List::clear); - System.out.println(" After size :" + DemoConfiguration.Sub.That.OPERATORS.size()); + System.out.println(" Before: size :" + DemoConfiguration.SUB.That.OPERATORS.size()); + DemoConfiguration.SUB.That.OPERATORS.modify(List::clear); + System.out.println(" After size :" + DemoConfiguration.SUB.That.OPERATORS.size()); System.out.println("> Test Section:"); - System.out.println(DemoConfiguration.MODEL_TEST.get()); - DemoConfiguration.MODEL_TEST.set(TestModel.random()); + System.out.println(DemoConfiguration.USERS.get()); + DemoConfiguration.USERS.add(UserRecord.random()); // System.out.println("> Test Maps:"); // DemoConfiguration.USERS.forEach((k, v) -> System.out.println(k + ": " + v)); @@ -64,19 +64,19 @@ public class ConfigurationTest { public static void testInner(ConfigurationHolder provider) { - TestConfiguration TEST = new TestConfiguration(); + RegistryConfig TEST = new RegistryConfig(); provider.initialize(TEST); System.out.println("> Test Inner value before:"); - System.out.println(TEST.INNER.INNER_VALUE.getNotNull()); + System.out.println(TEST.INSTANCE.INNER_VALUE.getNotNull()); double after = Math.random() * 200D; System.out.println("> Test Inner value -> " + after); - TEST.INNER.INNER_VALUE.set(after); + TEST.INSTANCE.INNER_VALUE.set(after); System.out.println("> Test Inner value after:"); - System.out.println(TEST.INNER.INNER_VALUE.getNotNull()); + System.out.println(TEST.INSTANCE.INNER_VALUE.getNotNull()); } 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 2080ce8..8623ac8 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 @@ -4,7 +4,8 @@ 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.demo.DatabaseConfiguration; +import cc.carm.lib.configuration.demo.tests.model.UserRecord; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.standard.ConfiguredList; import cc.carm.lib.configuration.value.standard.ConfiguredValue; @@ -27,18 +28,14 @@ public interface DemoConfiguration extends Configuration { // 支持通过 Class 变量标注子配置,一并注册。 // 注意: 若对应类也有注解,则优先使用类的注解。 - @ConfigPath("other-class-config") //支持通过注解修改子配置的主路径,若不修改则以变量名自动生成。 - @HeaderComment({"", "Something..."}) // 支持给子路径直接打注释 - @InlineComment("InlineComments for class path") - Class OTHER = OtherConfiguration.class; + Class DATABASE = DatabaseConfiguration.class; - @ConfigPath("user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。 + @ConfigPath("registered_users") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。 @HeaderComment({"Section类型数据测试"}) // 通过注解给配置添加注释。 @InlineComment("Section数据也支持InlineComment注释") - ConfigValue MODEL_TEST = ConfiguredValue.builderOf(TestModel.class).fromSection() - .defaults(new TestModel("Carm", UUID.randomUUID())) - .parse((holder, section) -> TestModel.deserialize(section)) - .serialize(TestModel::serialize).build(); + ConfiguredList USERS = ConfiguredList.builderOf(UserRecord.class).fromSection() + .parse(UserRecord::deserialize).serialize(UserRecord::serialize) + .defaults(UserRecord.CARM).build(); // @HeaderComment({"[ID - UUID]对照表", "", "用于测试Map类型的解析与序列化保存"}) // ConfiguredMap USERS = ConfiguredMap.builderOf(Integer.class, UUID.class) @@ -52,7 +49,7 @@ public interface DemoConfiguration extends Configuration { * 支持内部类的直接注册。 * 注意,需要启用 {@link cc.carm.lib.configuration.source.option.StandardOptions#LOAD_SUB_CLASSES} */ - class Sub implements Configuration { + class SUB implements Configuration { @ConfigPath(value = "uuid-value", root = true) @InlineComment("This is an inline comment") 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/InstanceConfig.java similarity index 86% rename from demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/TestInnerConfiguration.java rename to demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/InstanceConfig.java index 7c93b94..c0d7a8b 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/InstanceConfig.java @@ -6,7 +6,7 @@ import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue; @HeaderComment("Inner Test") -public class TestInnerConfiguration implements Configuration { +public class InstanceConfig implements Configuration { public final ConfigValue INNER_VALUE = ConfiguredValue.of(1.0D); diff --git a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/OtherConfiguration.java b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/OtherConfiguration.java deleted file mode 100644 index cb0fd2c..0000000 --- a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/OtherConfiguration.java +++ /dev/null @@ -1,4 +0,0 @@ -package cc.carm.lib.configuration.demo.tests.conf; - -public class OtherConfiguration { -} 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/RegistryConfig.java similarity index 59% rename from demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/TestConfiguration.java rename to demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/RegistryConfig.java index 0252d51..36fceca 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/RegistryConfig.java @@ -4,24 +4,23 @@ 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.demo.tests.model.UserRecord; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue; import java.util.UUID; -public class TestConfiguration implements Configuration { +public class RegistryConfig implements Configuration { - public final TestInnerConfiguration INNER = new TestInnerConfiguration(); - - public final ConfigValue CLASS_VALUE = ConfiguredValue.of(1.0D); + @HeaderComment("Support for configurations as instances") + public final InstanceConfig INSTANCE = new InstanceConfig(); @ConfigPath("test.user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。 @HeaderComment({"Section类型数据测试"}) // 通过注解给配置添加注释。 @InlineComment("Section数据也支持InlineComment注释") - public final ConfigValue TEST_MODEL = ConfiguredValue.builderOf(TestModel.class).fromSection() - .defaults(new TestModel("Carm", UUID.randomUUID())) - .parse((holder, section) -> TestModel.deserialize(section)) + public final ConfigValue TEST_MODEL = ConfiguredValue.builderOf(UserRecord.class).fromSection() + .defaults(new UserRecord("Carm", UUID.randomUUID())) + .parse((holder, section) -> UserRecord.deserialize(section)) .serialize((holder, data) -> data.serialize()).build(); diff --git a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/AbstractModel.java b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/AbstractRecord.java similarity index 73% rename from demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/AbstractModel.java rename to demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/AbstractRecord.java index f12e411..d8e09ce 100644 --- a/demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/AbstractModel.java +++ b/demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/AbstractRecord.java @@ -2,11 +2,11 @@ package cc.carm.lib.configuration.demo.tests.model; import org.jetbrains.annotations.NotNull; -public abstract class AbstractModel { +public abstract class AbstractRecord { protected final @NotNull String name; - public AbstractModel(@NotNull String name) { + public AbstractRecord(@NotNull String name) { this.name = name; } 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/UserRecord.java similarity index 65% rename from demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/TestModel.java rename to demo/src/main/java/cc/carm/lib/configuration/demo/tests/model/UserRecord.java index 0c9ef93..f14240a 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/UserRecord.java @@ -7,20 +7,22 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; -public class TestModel extends AbstractModel { +public class UserRecord extends AbstractRecord { - public UUID uuid; + public static final UserRecord CARM = new UserRecord("Carm", UUID.fromString("f7b3b3b3-3b3b-3b3b-3b3b-3b3b3b3b3b3b")); - public TestModel(String name, UUID uuid) { + protected UUID uuid; + + public UserRecord(String name, UUID uuid) { super(name); this.uuid = uuid; } - public void setUuid(UUID uuid) { + public void uuid(UUID uuid) { this.uuid = uuid; } - public UUID getUuid() { + public UUID uuid() { return uuid; } @@ -33,16 +35,16 @@ public class TestModel extends AbstractModel { return map; } - public static TestModel deserialize(ConfigureSection section) { + public static UserRecord deserialize(ConfigureSection section) { String name = section.getString("name"); if (name == null) throw new NullPointerException("name is null"); String uuidString = section.getString("info.uuid"); if (uuidString == null) throw new NullPointerException("uuid is null"); - return new TestModel(name, UUID.fromString(uuidString)); + return new UserRecord(name, UUID.fromString(uuidString)); } - public static TestModel random() { - return new TestModel(UUID.randomUUID().toString().substring(0, 5), UUID.randomUUID()); + public static UserRecord random() { + return new UserRecord(UUID.randomUUID().toString().substring(0, 5), UUID.randomUUID()); } 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 5973156..8584eea 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 @@ -46,16 +46,17 @@ public abstract class FileConfigSource
R fileInputStream(@NotNull DataFunction loader) throws Exception { @@ -65,7 +66,11 @@ public abstract class FileConfigSource
R fileReader(@NotNull DataFunction loader) throws Exception { - return fileInputStream(is -> loader.handle(new InputStreamReader(is, charset()))); + try (InputStream is = Files.newInputStream(file.toPath())) { + try (Reader r = new InputStreamReader(is, charset())) { + return loader.handle(r); + } + } } protected void fileOutputStream(@NotNull Consumer stream) throws Exception { @@ -75,7 +80,11 @@ public abstract class FileConfigSource
writer) throws Exception { - fileOutputStream(os -> writer.accept(new OutputStreamWriter(os, charset()))); + try (OutputStream os = Files.newOutputStream(file.toPath())) { + try (Writer w = new OutputStreamWriter(os, charset())) { + writer.accept(w); + } + } } protected void saveResource(@NotNull String resourcePath, boolean replace) diff --git a/pom.xml b/pom.xml index ac2a2a5..fcbba7f 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ features/commentable features/file - + providers/yaml providers/gson diff --git a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSection.java b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSection.java index e60231b..1e707e4 100644 --- a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSection.java +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSection.java @@ -22,6 +22,16 @@ public class JSONSection implements ConfigureSection { if (entry.getValue() instanceof Map) { this.data.put(key, new JSONSection(source, (Map) entry.getValue())); + } else if (entry.getValue() instanceof List) { + List list = new ArrayList<>(); + for (Object obj : (List) entry.getValue()) { + if (obj instanceof Map) { + list.add(new JSONSection(source, (Map) obj)); + } else { + list.add(obj); + } + } + this.data.put(key, list); } else { this.data.put(key, entry.getValue()); } diff --git a/providers/gson/src/test/java/config/JSONConfigTest.java b/providers/gson/src/test/java/config/JSONConfigTest.java index 931f09d..a8f911e 100644 --- a/providers/gson/src/test/java/config/JSONConfigTest.java +++ b/providers/gson/src/test/java/config/JSONConfigTest.java @@ -3,7 +3,10 @@ package config; import cc.carm.lib.configuration.demo.tests.ConfigurationTest; import cc.carm.lib.configuration.json.JSONConfigFactory; import cc.carm.lib.configuration.source.ConfigurationHolder; +import cc.carm.lib.configuration.source.loader.PathGenerator; import cc.carm.lib.configuration.source.option.StandardOptions; +import cc.carm.lib.configuration.value.ConfigValue; +import cc.carm.lib.configuration.value.standard.ConfiguredValue; import org.junit.Test; import java.io.File; @@ -12,11 +15,17 @@ public class JSONConfigTest { protected final ConfigurationHolder holder = JSONConfigFactory .from(new File("target"), "config.json") - .option(StandardOptions.PATH_SEPARATOR, '-') + .resourcePath("example.json") .build(); @Test public void onTest() { + + ConfigValue EXAMPLE = ConfiguredValue.of(false); + EXAMPLE.initialize(this.holder, "example"); + + System.out.println("Example: " + EXAMPLE.get()); + ConfigurationTest.testDemo(this.holder); ConfigurationTest.testInner(this.holder); diff --git a/providers/gson/src/test/resources/example.json b/providers/gson/src/test/resources/example.json new file mode 100644 index 0000000..44954eb --- /dev/null +++ b/providers/gson/src/test/resources/example.json @@ -0,0 +1,3 @@ +{ + "example": "true" +} \ No newline at end of file diff --git a/providers/yaml/src/test/java/config/DemoConfigTest.java b/providers/yaml/src/test/java/config/DemoConfigTest.java index b7427cd..ee68d7b 100644 --- a/providers/yaml/src/test/java/config/DemoConfigTest.java +++ b/providers/yaml/src/test/java/config/DemoConfigTest.java @@ -2,7 +2,7 @@ package config; import cc.carm.lib.configuration.EasyConfiguration; import cc.carm.lib.configuration.demo.tests.ConfigurationTest; -import cc.carm.lib.configuration.demo.tests.model.AbstractModel; +import cc.carm.lib.configuration.demo.tests.model.AbstractRecord; import cc.carm.lib.configuration.yaml.YAMLConfigProvider; import config.model.AnyModel; import config.model.SomeModel; @@ -10,8 +10,6 @@ import config.source.ModelConfiguration; import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerialization; import org.junit.Test; -import java.io.IOException; - public class DemoConfigTest { static { @@ -37,10 +35,10 @@ public class DemoConfigTest { provider.initialize(ModelConfiguration.class); System.out.println("----------------------------------------------------"); - AbstractModel someModel = ModelConfiguration.SOME_MODEL.get(); + AbstractRecord someModel = ModelConfiguration.SOME_MODEL.get(); if (someModel != null) System.out.println(someModel.getName()); - AbstractModel anyModel = ModelConfiguration.ANY_MODEL.get(); + AbstractRecord anyModel = ModelConfiguration.ANY_MODEL.get(); if (anyModel != null) System.out.println(anyModel.getName()); ModelConfiguration.MODELS.forEach(System.out::println); diff --git a/providers/yaml/src/test/java/config/model/AnyModel.java b/providers/yaml/src/test/java/config/model/AnyModel.java index f123d09..4f619a8 100644 --- a/providers/yaml/src/test/java/config/model/AnyModel.java +++ b/providers/yaml/src/test/java/config/model/AnyModel.java @@ -1,6 +1,6 @@ package config.model; -import cc.carm.lib.configuration.demo.tests.model.AbstractModel; +import cc.carm.lib.configuration.demo.tests.model.AbstractRecord; import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; import org.bspfsystems.yamlconfiguration.serialization.SerializableAs; import org.jetbrains.annotations.NotNull; @@ -11,7 +11,7 @@ import java.util.Map; import java.util.UUID; @SerializableAs("AnyModel") -public class AnyModel extends AbstractModel implements ConfigurationSerializable { +public class AnyModel extends AbstractRecord implements ConfigurationSerializable { public final boolean bool; diff --git a/providers/yaml/src/test/java/config/model/SomeModel.java b/providers/yaml/src/test/java/config/model/SomeModel.java index 65fdf21..4308bfe 100644 --- a/providers/yaml/src/test/java/config/model/SomeModel.java +++ b/providers/yaml/src/test/java/config/model/SomeModel.java @@ -1,6 +1,6 @@ package config.model; -import cc.carm.lib.configuration.demo.tests.model.AbstractModel; +import cc.carm.lib.configuration.demo.tests.model.AbstractRecord; import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; import org.bspfsystems.yamlconfiguration.serialization.SerializableAs; import org.jetbrains.annotations.NotNull; @@ -11,7 +11,7 @@ import java.util.Map; import java.util.UUID; @SerializableAs("SomeModel") -public class SomeModel extends AbstractModel implements ConfigurationSerializable { +public class SomeModel extends AbstractRecord implements ConfigurationSerializable { public final int num; diff --git a/providers/yaml/src/test/java/config/source/ModelConfiguration.java b/providers/yaml/src/test/java/config/source/ModelConfiguration.java index 14dfdf9..8095fe8 100644 --- a/providers/yaml/src/test/java/config/source/ModelConfiguration.java +++ b/providers/yaml/src/test/java/config/source/ModelConfiguration.java @@ -7,7 +7,7 @@ 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.ConfiguredSectionMap; -import cc.carm.lib.configuration.demo.tests.model.AbstractModel; +import cc.carm.lib.configuration.demo.tests.model.AbstractRecord; import cc.carm.lib.configuration.yaml.value.ConfiguredSerializable; import config.model.AnyModel; import config.model.SomeModel; @@ -16,11 +16,11 @@ import config.model.SomeModel; @ConfigPath("model-test") public class ModelConfiguration implements Configuration { - public static final ConfigValue SOME_MODEL = ConfiguredSerializable.of( + public static final ConfigValue SOME_MODEL = ConfiguredSerializable.of( SomeModel.class, SomeModel.random() ); - public static final ConfigValue ANY_MODEL = ConfiguredSerializable.of( + public static final ConfigValue ANY_MODEL = ConfiguredSerializable.of( AnyModel.class, AnyModel.random() ); From 90407dcd0dcb8549809994c755099a2316c361f0 Mon Sep 17 00:00:00 2001 From: Carm Date: Thu, 13 Feb 2025 04:34:52 +0800 Subject: [PATCH 15/17] feat(json): Finished json version's provider --- .../source/section/ConfigureSection.java | 111 +++++++++++++++--- .../source/section/ConfigureSource.java | 7 +- .../annotation/FooterComment.java | 40 +++++++ .../commentable/CommentableMetaTypes.java | 10 ++ .../option/CommentableOptions.java | 12 +- .../source/{ => file}/FileConfigFactory.java | 4 +- .../source/{ => file}/FileConfigSource.java | 5 +- .../option/FileConfigOptions.java | 2 +- .../{ => source}/json/JSONConfigFactory.java | 4 +- .../{ => source}/json/JSONSection.java | 38 +++--- .../{ => source}/json/JSONSource.java | 10 +- .../src/test/java/config/JSONConfigTest.java | 4 +- providers/yaml/pom.xml | 17 ++- .../lib/configuration/EasyConfiguration.java | 36 ------ .../source/yaml/YAMLConfigFactory.java | 4 + .../source/yaml/YAMLSection.java | 76 ++++++++++++ .../configuration/source/yaml/YAMLSource.java | 4 + .../yaml/YAMLConfigProvider.java | 90 -------------- .../configuration/yaml/YAMLConfigSource.java | 4 - .../yaml/YAMLSectionWrapper.java | 88 -------------- .../lib/configuration/yaml/YAMLValue.java | 28 ----- .../yaml/builder/AbstractYAMLBuilder.java | 13 -- .../yaml/builder/YAMLConfigBuilder.java | 14 --- .../serializable/SerializableBuilder.java | 29 ----- .../yaml/value/ConfiguredSerializable.java | 49 -------- .../src/test/java/config/DemoConfigTest.java | 52 -------- .../src/test/java/config/model/AnyModel.java | 50 -------- .../src/test/java/config/model/SomeModel.java | 50 -------- .../config/source/ModelConfiguration.java | 43 ------- .../yaml/src/test/java/sample/Sample.java | 2 - 30 files changed, 289 insertions(+), 607 deletions(-) create mode 100644 features/commentable/src/main/java/cc/carm/lib/configuration/annotation/FooterComment.java rename features/file/src/main/java/cc/carm/lib/configuration/source/{ => file}/FileConfigFactory.java (85%) rename features/file/src/main/java/cc/carm/lib/configuration/source/{ => file}/FileConfigSource.java (96%) rename features/file/src/main/java/cc/carm/lib/configuration/{ => source}/option/FileConfigOptions.java (90%) rename providers/gson/src/main/java/cc/carm/lib/configuration/{ => source}/json/JSONConfigFactory.java (94%) rename providers/gson/src/main/java/cc/carm/lib/configuration/{ => source}/json/JSONSection.java (80%) rename providers/gson/src/main/java/cc/carm/lib/configuration/{ => source}/json/JSONSource.java (88%) delete mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java create mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLConfigFactory.java create mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLSection.java create mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLSource.java delete mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java delete mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigSource.java delete mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java delete mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java delete mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/AbstractYAMLBuilder.java delete mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/YAMLConfigBuilder.java delete mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java delete mode 100644 providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java delete mode 100644 providers/yaml/src/test/java/config/DemoConfigTest.java delete mode 100644 providers/yaml/src/test/java/config/model/AnyModel.java delete mode 100644 providers/yaml/src/test/java/config/model/SomeModel.java delete mode 100644 providers/yaml/src/test/java/config/source/ModelConfiguration.java diff --git a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java index 42e71a6..8da24a1 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java @@ -2,27 +2,31 @@ 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; -import org.jetbrains.annotations.Unmodifiable; +import org.jetbrains.annotations.*; import java.util.*; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; public interface ConfigureSection { @NotNull ConfigureSource source(); + @Nullable ConfigureSection parent(); + default char separator() { return source().holder().options().get(StandardOptions.PATH_SEPARATOR); } @NotNull + @UnmodifiableView default Set getKeys(boolean deep) { return getValues(deep).keySet(); } @NotNull + @UnmodifiableView Map getValues(boolean deep); void set(@NotNull String path, @Nullable Object value); @@ -195,56 +199,125 @@ public interface ConfigureSection { return get(path, def, String.class); } + /** + * Get a list of values from the section + *

+ * If the path does not exist, an empty list will be returned + *
Any changes please use {@link #set(String, Object)} after changes + * + * @param path The path to get the list from + * @param parser The function to parse the values + * @param The type of the values + * @return The list of values + */ default @NotNull List getList(@NotNull String path, @NotNull DataFunction parser) { - return parseList(getList(path), parser); + return getCollection(path, ArrayList::new, parser); } - @Unmodifiable + /** + * Get a list of strings from the section + *

Limitations see {@link #getList(String, DataFunction)} + * + * @param path The path to get the list from + * @return The list of strings + */ default @NotNull List getStringList(@NotNull String path) { return getList(path, DataFunction.castToString()); } - @Unmodifiable + /** + * Get a list of integer from the section + *

Limitations see {@link #getList(String, DataFunction)} + * + * @param path The path to get the list from + * @return The list of int values + */ default @NotNull List getIntegerList(@NotNull String path) { return getList(path, DataFunction.intValue()); } - @Unmodifiable + /** + * Get a list of long from the section + *

Limitations see {@link #getList(String, DataFunction)} + * + * @param path The path to get the list from + * @return The list of long values + */ default @NotNull List getLongList(@NotNull String path) { return getList(path, DataFunction.longValue()); } - @Unmodifiable + /** + * Get a list of double from the section + *

Limitations see {@link #getList(String, DataFunction)} + * + * @param path The path to get the list from + * @return The list of doubles + */ default @NotNull List getDoubleList(@NotNull String path) { return getList(path, DataFunction.doubleValue()); } - @Unmodifiable + /** + * Get a list of floats from the section + *

Limitations see {@link #getList(String, DataFunction)} + * + * @param path The path to get the list from + * @return The list of floats + */ default @NotNull List getFloatList(@NotNull String path) { return getList(path, DataFunction.floatValue()); } - @Unmodifiable + /** + * Get a list of bytes from the section + *

Limitations see {@link #getList(String, DataFunction)} + * + * @param path The path to get the list from + * @return The list of bytes + */ default @NotNull List getByteList(@NotNull String path) { return getList(path, DataFunction.byteValue()); } - @Unmodifiable + /** + * Get a list of char from the section + *

Limitations see {@link #getList(String, DataFunction)} + * + * @param path The path to get the list from + * @return The list of char + */ default @NotNull List getCharList(@NotNull String path) { return getList(path, DataFunction.castObject(Character.class)); } - @Unmodifiable - static @NotNull List parseList(@Nullable List list, DataFunction parser) { - if (list == null) return Collections.emptyList(); - List values = new ArrayList<>(); - for (Object o : list) { + default > @NotNull C getCollection(@NotNull String path, + @NotNull Supplier constructor, + @NotNull DataFunction parser) { + return parseCollection(getList(path), constructor, parser); + } + + default @NotNull Stream stream(@NotNull String path) { + List values = getList(path); + return values == null ? Stream.empty() : values.stream(); + } + + default @NotNull Stream stream(@NotNull String path, @NotNull Function parser) { + return stream(path).map(parser); + } + + static > @NotNull C parseCollection( + @Nullable List data, @NotNull Supplier constructor, + @NotNull DataFunction parser + ) { + C values = constructor.get(); + if (data == null) return values; + for (Object obj : data) { try { - values.add(parser.handle(o)); + values.add(parser.handle(obj)); } catch (Exception ignored) { } } return values; } - } 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 index b2e7e4c..f0c83c7 100644 --- 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 @@ -38,7 +38,7 @@ public abstract class ConfigureSource< public abstract @NotNull ORIGINAL original(); /** - * @return Configuration section + * @return The root {@link ConfigureSection} */ public abstract @NotNull SECTION section(); @@ -54,6 +54,11 @@ public abstract class ConfigureSource< return getLastUpdateMillis() > parsedTime; } + @Override + public @Nullable ConfigureSection parent() { + return null; // Source also represents the root section, so it has no parent + } + @Override public @NotNull Map getValues(boolean deep) { return section().getValues(deep); diff --git a/features/commentable/src/main/java/cc/carm/lib/configuration/annotation/FooterComment.java b/features/commentable/src/main/java/cc/carm/lib/configuration/annotation/FooterComment.java new file mode 100644 index 0000000..24971d6 --- /dev/null +++ b/features/commentable/src/main/java/cc/carm/lib/configuration/annotation/FooterComment.java @@ -0,0 +1,40 @@ +package cc.carm.lib.configuration.annotation; + +import org.jetbrains.annotations.NotNull; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Footer Comments. + * Add a comment to the bottom of the corresponding configuration for easy reading and viewing. + *

e.g. + *

+ * foo: "bar"
+ * # The first line of the comment
+ * # The second line of the comment
+ * 
+ */ +@Target({ElementType.TYPE, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface FooterComment { + + /** + * If the content of the note is 0, it will be treated as a blank line. + *

e.g. {"foo","","bar"} + * Will be set as + *

+     * foo: "bar"
+     * # foo
+     *
+     * # bar
+     * 
+ * + * @return The content of this comment + */ + @NotNull + String[] value() default ""; + +} diff --git a/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java b/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java index d328e6d..ce73428 100644 --- a/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java +++ b/features/commentable/src/main/java/cc/carm/lib/configuration/commentable/CommentableMetaTypes.java @@ -1,5 +1,6 @@ package cc.carm.lib.configuration.commentable; +import cc.carm.lib.configuration.annotation.FooterComment; import cc.carm.lib.configuration.annotation.HeaderComment; import cc.carm.lib.configuration.annotation.InlineComment; import cc.carm.lib.configuration.source.ConfigurationHolder; @@ -18,6 +19,11 @@ public interface CommentableMetaTypes { */ ConfigurationMetadata> HEADER_COMMENTS = ConfigurationMetadata.of(Collections.emptyList()); + /** + * Configuration's footer comments + */ + ConfigurationMetadata> FOOTER_COMMENTS = ConfigurationMetadata.of(Collections.emptyList()); + /** * Configuration's {@link InlineComment} */ @@ -33,6 +39,10 @@ public interface CommentableMetaTypes { HeaderComment.class, HEADER_COMMENTS, a -> Arrays.asList(a.value()) ); + initializer.registerAnnotation( + FooterComment.class, FOOTER_COMMENTS, + a -> Arrays.asList(a.value()) + ); initializer.registerAnnotation(InlineComment.class, INLINE_COMMENT, InlineComment::value); } diff --git a/features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java b/features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java index 1c8a413..09a89e4 100644 --- a/features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java +++ b/features/commentable/src/main/java/cc/carm/lib/configuration/option/CommentableOptions.java @@ -4,11 +4,11 @@ import cc.carm.lib.configuration.source.option.ConfigurationOption; public interface CommentableOptions { - /** - * Whether to keep modified comments in configuration, - * that means we only set comments for values that are not exists in configuration. - */ - ConfigurationOption KEEP_COMMENTS = ConfigurationOption.of(true); +// /** +// * Whether to keep modified comments in configuration, +// * that means we only set comments for values that are not exists in configuration. +// */ +// ConfigurationOption KEEP_COMMENTS = ConfigurationOption.of(true); /** * Whether to comment values name that are not exists in configuration and no default value offered. @@ -19,6 +19,6 @@ public interface CommentableOptions { * # foo: * */ - ConfigurationOption COMMENT_NO_DEFAULT = ConfigurationOption.of(true); + ConfigurationOption COMMENT_EMPTY_VALUE = ConfigurationOption.of(true); } 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/file/FileConfigFactory.java similarity index 85% rename from features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigFactory.java rename to features/file/src/main/java/cc/carm/lib/configuration/source/file/FileConfigFactory.java index 20a33f3..d112eb2 100644 --- a/features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigFactory.java +++ b/features/file/src/main/java/cc/carm/lib/configuration/source/file/FileConfigFactory.java @@ -1,5 +1,7 @@ -package cc.carm.lib.configuration.source; +package cc.carm.lib.configuration.source.file; +import cc.carm.lib.configuration.source.ConfigurationFactory; +import cc.carm.lib.configuration.source.ConfigurationHolder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; 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/file/FileConfigSource.java similarity index 96% rename from features/file/src/main/java/cc/carm/lib/configuration/source/FileConfigSource.java rename to features/file/src/main/java/cc/carm/lib/configuration/source/file/FileConfigSource.java index 8584eea..85b7013 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/file/FileConfigSource.java @@ -1,7 +1,8 @@ -package cc.carm.lib.configuration.source; +package cc.carm.lib.configuration.source.file; import cc.carm.lib.configuration.function.DataFunction; -import cc.carm.lib.configuration.option.FileConfigOptions; +import cc.carm.lib.configuration.source.ConfigurationHolder; +import cc.carm.lib.configuration.source.option.FileConfigOptions; import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.source.section.ConfigureSource; import org.jetbrains.annotations.NotNull; diff --git a/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java b/features/file/src/main/java/cc/carm/lib/configuration/source/option/FileConfigOptions.java similarity index 90% rename from features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java rename to features/file/src/main/java/cc/carm/lib/configuration/source/option/FileConfigOptions.java index ee950a6..2c46761 100644 --- a/features/file/src/main/java/cc/carm/lib/configuration/option/FileConfigOptions.java +++ b/features/file/src/main/java/cc/carm/lib/configuration/source/option/FileConfigOptions.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.option; +package cc.carm.lib.configuration.source.option; import cc.carm.lib.configuration.source.option.ConfigurationOption; 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/source/json/JSONConfigFactory.java similarity index 94% rename from providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigFactory.java rename to providers/gson/src/main/java/cc/carm/lib/configuration/source/json/JSONConfigFactory.java index 5758188..d7f5e39 100644 --- a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONConfigFactory.java +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/source/json/JSONConfigFactory.java @@ -1,7 +1,7 @@ -package cc.carm.lib.configuration.json; +package cc.carm.lib.configuration.source.json; import cc.carm.lib.configuration.source.ConfigurationHolder; -import cc.carm.lib.configuration.source.FileConfigFactory; +import cc.carm.lib.configuration.source.file.FileConfigFactory; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.jetbrains.annotations.NotNull; diff --git a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSection.java b/providers/gson/src/main/java/cc/carm/lib/configuration/source/json/JSONSection.java similarity index 80% rename from providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSection.java rename to providers/gson/src/main/java/cc/carm/lib/configuration/source/json/JSONSection.java index 1e707e4..3b93a2c 100644 --- a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSection.java +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/source/json/JSONSection.java @@ -1,4 +1,4 @@ -package cc.carm.lib.configuration.json; +package cc.carm.lib.configuration.source.json; import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.source.section.ConfigureSource; @@ -9,24 +9,26 @@ import java.util.*; public class JSONSection implements ConfigureSection { - protected final ConfigureSource source; - protected final Map data; + protected final @NotNull ConfigureSource source; + protected final @NotNull Map data; + protected final @Nullable JSONSection parent; public JSONSection(@NotNull ConfigureSource source, - @NotNull Map data) { + @NotNull Map data, @Nullable JSONSection parent) { this.source = source; + this.parent = parent; this.data = new LinkedHashMap<>(); 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 JSONSection(source, (Map) entry.getValue())); + this.data.put(key, new JSONSection(source, (Map) entry.getValue(), this)); } else if (entry.getValue() instanceof List) { List list = new ArrayList<>(); for (Object obj : (List) entry.getValue()) { if (obj instanceof Map) { - list.add(new JSONSection(source, (Map) obj)); + list.add(new JSONSection(source, (Map) obj, this)); } else { list.add(obj); } @@ -43,13 +45,12 @@ public class JSONSection implements ConfigureSection { return this.source; } - public Map data() { + public @NotNull Map data() { return this.data; } - @Override - public @NotNull Set getKeys(boolean deep) { - return getValues(deep).keySet(); + public @Nullable JSONSection parent() { + return this.parent; } @Override @@ -57,14 +58,14 @@ public class JSONSection implements ConfigureSection { if (deep) { Map values = new LinkedHashMap<>(); mapChildrenValues(values, this, null, true); - return values; - } else return new LinkedHashMap<>(this.data); + return Collections.unmodifiableMap(values); + } else return Collections.unmodifiableMap(data()); } @Override public void set(@NotNull String path, @Nullable Object value) { if (value instanceof Map) { - value = new JSONSection(source(), (Map) value); + value = new JSONSection(source(), (Map) value, this); } JSONSection section = getSectionFor(path); @@ -119,7 +120,7 @@ public class JSONSection implements ConfigureSection { String root = path.substring(0, index); Object section = this.data.get(root); if (section == null) { - section = new JSONSection(source(), new LinkedHashMap<>()); + section = new JSONSection(source(), new LinkedHashMap<>(), this); this.data.put(root, section); } @@ -132,6 +133,15 @@ public class JSONSection implements ConfigureSection { } + /** + * Map the values of the children of the section to the output map. + * + * @param output The map to map the values to + * @param section The section to map the values from + * @param parent The parent path + * @param deep If the mapping should be deep + * @author md_5, sk89q + */ protected void mapChildrenValues(@NotNull Map output, @NotNull JSONSection section, @Nullable String parent, boolean deep) { for (Map.Entry entry : section.data().entrySet()) { 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/source/json/JSONSource.java similarity index 88% rename from providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSource.java rename to providers/gson/src/main/java/cc/carm/lib/configuration/source/json/JSONSource.java index a6465b2..3354665 100644 --- a/providers/gson/src/main/java/cc/carm/lib/configuration/json/JSONSource.java +++ b/providers/gson/src/main/java/cc/carm/lib/configuration/source/json/JSONSource.java @@ -1,7 +1,7 @@ -package cc.carm.lib.configuration.json; +package cc.carm.lib.configuration.source.json; import cc.carm.lib.configuration.source.ConfigurationHolder; -import cc.carm.lib.configuration.source.FileConfigSource; +import cc.carm.lib.configuration.source.file.FileConfigSource; import cc.carm.lib.configuration.source.section.ConfigureSource; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -22,7 +22,7 @@ public class JSONSource extends FileConfigSource, JSONSou ).create(); protected final @NotNull Gson gson; - protected @Nullable JSONSection section; + protected @Nullable JSONSection rootSection; protected JSONSource(@NotNull ConfigurationHolder holder, long lastUpdateMillis, @NotNull File file, @Nullable String resourcePath) { @@ -62,7 +62,7 @@ public class JSONSource extends FileConfigSource, JSONSou @Override public @NotNull JSONSection section() { - return Objects.requireNonNull(this.section, "Section is not initialized"); + return Objects.requireNonNull(this.rootSection, "Section is not initialized"); } @Override @@ -74,7 +74,7 @@ public class JSONSource extends FileConfigSource, JSONSou 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.rootSection = new JSONSection(this, data, null); 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 a8f911e..07f98aa 100644 --- a/providers/gson/src/test/java/config/JSONConfigTest.java +++ b/providers/gson/src/test/java/config/JSONConfigTest.java @@ -1,10 +1,8 @@ package config; import cc.carm.lib.configuration.demo.tests.ConfigurationTest; -import cc.carm.lib.configuration.json.JSONConfigFactory; +import cc.carm.lib.configuration.source.json.JSONConfigFactory; import cc.carm.lib.configuration.source.ConfigurationHolder; -import cc.carm.lib.configuration.source.loader.PathGenerator; -import cc.carm.lib.configuration.source.option.StandardOptions; import cc.carm.lib.configuration.value.ConfigValue; import cc.carm.lib.configuration.value.standard.ConfiguredValue; import org.junit.Test; diff --git a/providers/yaml/pom.xml b/providers/yaml/pom.xml index 7be0584..88ea416 100644 --- a/providers/yaml/pom.xml +++ b/providers/yaml/pom.xml @@ -37,18 +37,25 @@ ${project.parent.groupId} - easyconfiguration-demo + easyconfiguration-feature-file ${project.parent.version} - test + compile - org.bspfsystems - yamlconfiguration - 2.0.1 + org.yaml + snakeyaml + 2.3 compile + + ${project.parent.groupId} + easyconfiguration-demo + ${project.parent.version} + test + + diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/EasyConfiguration.java deleted file mode 100644 index aa6aa78..0000000 --- a/providers/yaml/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.yaml.YAMLConfigProvider; - -import java.io.File; -import java.io.IOException; - -public class EasyConfiguration { - - private EasyConfiguration() { - } - - public static YAMLConfigProvider from(File file, String source) { - YAMLConfigProvider provider = new YAMLConfigProvider(file); - try { - provider.initializeFile(source); - provider.initializeConfig(); - } catch (IOException e) { - e.printStackTrace(); - } - return provider; - } - - public static YAMLConfigProvider from(File file) { - return from(file, file.getName()); - } - - public static YAMLConfigProvider from(String fileName) { - return from(fileName, fileName); - } - - public static YAMLConfigProvider from(String fileName, String source) { - return from(new File(fileName), source); - } - -} diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLConfigFactory.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLConfigFactory.java new file mode 100644 index 0000000..5458631 --- /dev/null +++ b/providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLConfigFactory.java @@ -0,0 +1,4 @@ +package cc.carm.lib.configuration.source.yaml; + +public class YAMLConfigFactory { +} diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLSection.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLSection.java new file mode 100644 index 0000000..d5cbc95 --- /dev/null +++ b/providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLSection.java @@ -0,0 +1,76 @@ +package cc.carm.lib.configuration.source.yaml; + +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 org.jetbrains.annotations.UnmodifiableView; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class YAMLSection implements ConfigureSection { + + protected final @NotNull ConfigureSource source; + protected final @NotNull Map data; + protected final @Nullable YAMLSection parent; + + public YAMLSection(@NotNull ConfigureSource source, + @NotNull Map data, @Nullable YAMLSection parent) { + this.source = source; + this.data = data; + this.parent = parent; + } + + + @Override + public @NotNull ConfigureSource source() { + return this.source; + } + + @Override + public @Nullable YAMLSection parent() { + return this.parent; + } + + @Override + public @NotNull @UnmodifiableView 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 YAMLSection getSection(@NotNull String path) { + return null; + } + + @Override + public @Nullable Object get(@NotNull String path) { + return null; + } +} diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLSource.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLSource.java new file mode 100644 index 0000000..d7af585 --- /dev/null +++ b/providers/yaml/src/main/java/cc/carm/lib/configuration/source/yaml/YAMLSource.java @@ -0,0 +1,4 @@ +package cc.carm.lib.configuration.source.yaml; + +public class YAMLSource { +} diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java deleted file mode 100644 index 9815444..0000000 --- a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java +++ /dev/null @@ -1,90 +0,0 @@ -package cc.carm.lib.configuration.yaml; - -import cc.carm.lib.configuration.source.comment.ConfigurationComments; -import cc.carm.lib.configuration.core.source.impl.FileConfigProvider; -import cc.carm.lib.yamlcommentupdater.CommentedYAML; -import cc.carm.lib.yamlcommentupdater.CommentedYAMLWriter; -import org.bspfsystems.yamlconfiguration.configuration.ConfigurationSection; -import org.bspfsystems.yamlconfiguration.file.FileConfiguration; -import org.bspfsystems.yamlconfiguration.file.YamlConfiguration; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.util.List; -import java.util.Set; - -public class YAMLConfigProvider extends FileConfigProvider implements CommentedYAML { - - protected final @NotNull ConfigurationComments comments = new ConfigurationComments(); - protected YamlConfiguration configuration; - protected ConfigInitializer initializer; - - public YAMLConfigProvider(@NotNull File file) { - super(file); - } - - public void initializeConfig() { - ConfigurationOptions - this.configuration = YamlConfiguration.loadConfiguration(file); - this.initializer = new ConfigInitializer<>(this); - } - - @Override - public @NotNull YAMLSectionWrapper getConfiguration() { - return YAMLSectionWrapper.of(configuration); - } - - @Override - protected void onReload() throws Exception { - configuration.load(getFile()); - } - - @Override - public @NotNull ConfigurationComments getComments() { - return this.comments; - } - - @Override - public void save() throws Exception { - try { - CommentedYAMLWriter.writeWithComments(this, this.file); - } catch (Exception ex) { - configuration.save(file); - throw ex; - } - } - - @Override - public @NotNull ConfigInitializer getInitializer() { - return this.initializer; - } - - @Override - public String serializeValue(@NotNull String key, @NotNull Object value) { - FileConfiguration temp = new YamlConfiguration(); - temp.set(key, value); - return temp.saveToString(); - } - - @Override - public Set getKeys(@Nullable String sectionKey, boolean deep) { - if (sectionKey == null) return configuration.getKeys(deep); - - ConfigurationSection section = configuration.getConfigurationSection(sectionKey); - if (section == null) return null; - - return section.getKeys(deep); - } - - @Override - public @Nullable Object getValue(@NotNull String key) { - return configuration.get(key); - } - - @Override - public @Nullable List getHeaderComments(@Nullable String key) { - return comments.getHeaderComment(key); - } - -} diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigSource.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigSource.java deleted file mode 100644 index d8e7d8e..0000000 --- a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigSource.java +++ /dev/null @@ -1,4 +0,0 @@ -package cc.carm.lib.configuration.yaml; - -public class YAMLConfigSource { -} diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java deleted file mode 100644 index e2c8ca8..0000000 --- a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLSectionWrapper.java +++ /dev/null @@ -1,88 +0,0 @@ -package cc.carm.lib.configuration.yaml; - -import org.bspfsystems.yamlconfiguration.configuration.ConfigurationSection; -import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class YAMLSectionWrapper implements ConfigurationWrapper { - - private final ConfigurationSection section; - - private YAMLSectionWrapper(ConfigurationSection section) { - this.section = section; - } - - @Contract("!null->!null") - public static @Nullable YAMLSectionWrapper of(@Nullable ConfigurationSection section) { - return section == null ? null : new YAMLSectionWrapper(section); - } - - @Override - public @NotNull ConfigurationSection getSource() { - return this.section; - } - - @Override - public @NotNull Set getKeys(boolean deep) { - return new LinkedHashSet<>(section.getKeys(deep)); - } - - @Override - public @NotNull Map getValues(boolean deep) { - return section.getValues(deep); - } - - @Override - public void set(@NotNull String path, @Nullable Object value) { - this.section.set(path, value); - } - - @Override - public boolean contains(@NotNull String path) { - return this.section.contains(path); - } - - @Override - public @Nullable Object get(@NotNull String path) { - return this.section.get(path); - } - - @Override - public boolean isList(@NotNull String path) { - return this.section.isList(path); - } - - @Override - public @Nullable List getList(@NotNull String path) { - return this.section.getList(path); - } - - @Override - public boolean isConfigurationSection(@NotNull String path) { - return this.section.isConfigurationSection(path); - } - - @Override - public @Nullable YAMLSectionWrapper getConfigurationSection(@NotNull String path) { - return of(this.section.getConfigurationSection(path)); - } - - @Nullable - public T getSerializable(@NotNull String path, @NotNull Class clazz) { - return getSerializable(path, clazz, null); - } - - @Nullable - @Contract("_, _, !null -> !null") - public T getSerializable(@NotNull String path, @NotNull Class clazz, @Nullable T defaultValue) { - return this.section.getSerializable(path, clazz, defaultValue); - } - -} diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java deleted file mode 100644 index fec8efd..0000000 --- a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java +++ /dev/null @@ -1,28 +0,0 @@ -package cc.carm.lib.configuration.yaml; - -import cc.carm.lib.configuration.value.ValueManifest; -import cc.carm.lib.configuration.value.impl.CachedConfigValue; -import cc.carm.lib.configuration.yaml.builder.YAMLConfigBuilder; -import org.jetbrains.annotations.NotNull; - -public abstract class YAMLValue extends CachedConfigValue { - - public static @NotNull YAMLConfigBuilder builder() { - return new YAMLConfigBuilder(); - } - - public YAMLValue(@NotNull ValueManifest manifest) { - super(manifest); - } - - public YAMLConfigProvider getYAMLProvider() { - ConfigurationProvider provider = getProvider(); - if (provider instanceof YAMLConfigProvider) return (YAMLConfigProvider) getProvider(); - else throw new IllegalStateException("Provider is not a YamlConfigProvider"); - } - - public YAMLSectionWrapper getYAMLConfig() { - return getYAMLProvider().getConfiguration(); - } - -} diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/AbstractYAMLBuilder.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/AbstractYAMLBuilder.java deleted file mode 100644 index 1da838f..0000000 --- a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/AbstractYAMLBuilder.java +++ /dev/null @@ -1,13 +0,0 @@ -package cc.carm.lib.configuration.yaml.builder; - -import cc.carm.lib.configuration.core.builder.AbstractConfigBuilder; -import cc.carm.lib.configuration.yaml.YAMLConfigProvider; - -public abstract class AbstractYAMLBuilder> - extends AbstractConfigBuilder { - - public AbstractYAMLBuilder() { - super(YAMLConfigProvider.class); - } - -} diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/YAMLConfigBuilder.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/YAMLConfigBuilder.java deleted file mode 100644 index 51ffd9d..0000000 --- a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/YAMLConfigBuilder.java +++ /dev/null @@ -1,14 +0,0 @@ -package cc.carm.lib.configuration.yaml.builder; - -import cc.carm.lib.configuration.core.builder.ConfigBuilder; -import cc.carm.lib.configuration.yaml.builder.serializable.SerializableBuilder; -import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; -import org.jetbrains.annotations.NotNull; - -public class YAMLConfigBuilder extends ConfigBuilder { - - public @NotNull SerializableBuilder ofSerializable(@NotNull Class valueClass) { - return new SerializableBuilder<>(valueClass); - } - -} diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java deleted file mode 100644 index 955e93a..0000000 --- a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java +++ /dev/null @@ -1,29 +0,0 @@ -package cc.carm.lib.configuration.yaml.builder.serializable; - -import cc.carm.lib.configuration.yaml.builder.AbstractYAMLBuilder; -import cc.carm.lib.configuration.yaml.value.ConfiguredSerializable; -import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; -import org.jetbrains.annotations.NotNull; - -public class SerializableBuilder - extends AbstractYAMLBuilder> { - - protected final @NotNull Class valueClass; - - public SerializableBuilder(@NotNull Class valueClass) { - this.valueClass = valueClass; - } - - @Override - protected @NotNull SerializableBuilder getThis() { - return this; - } - - @Override - public @NotNull ConfiguredSerializable build() { - return new ConfiguredSerializable<>(buildManifest(), this.valueClass); - } - - -} - diff --git a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java b/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java deleted file mode 100644 index 454824b..0000000 --- a/providers/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java +++ /dev/null @@ -1,49 +0,0 @@ -package cc.carm.lib.configuration.yaml.value; - -import cc.carm.lib.configuration.value.ValueManifest; -import cc.carm.lib.configuration.yaml.YAMLValue; -import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class ConfiguredSerializable extends YAMLValue { - - public static ConfiguredSerializable of(@NotNull Class valueClass) { - return of(valueClass, null); - } - - public static ConfiguredSerializable of(@NotNull Class valueClass, - @Nullable V defaultValue) { - return builder().ofSerializable(valueClass).defaults(defaultValue).build(); - } - - protected final @NotNull Class valueClass; - - public ConfiguredSerializable(@NotNull ValueManifest manifest, @NotNull Class valueClass) { - super(manifest); - this.valueClass = valueClass; - } - - @Override - public @Nullable T get() { - if (!isExpired()) return getCachedOrDefault(); - - try { - // 若未出现错误,则直接更新缓存并返回。 - return updateCache(getYAMLConfig().getSerializable(getConfigPath(), valueClass, getDefaultValue())); - } catch (Exception e) { - // 出现了解析错误,提示并返回默认值。 - e.printStackTrace(); - return getDefaultValue(); - } - - } - - @Override - public void set(@Nullable T value) { - updateCache(value); - setValue(value); - } - - -} diff --git a/providers/yaml/src/test/java/config/DemoConfigTest.java b/providers/yaml/src/test/java/config/DemoConfigTest.java deleted file mode 100644 index ee68d7b..0000000 --- a/providers/yaml/src/test/java/config/DemoConfigTest.java +++ /dev/null @@ -1,52 +0,0 @@ -package config; - -import cc.carm.lib.configuration.EasyConfiguration; -import cc.carm.lib.configuration.demo.tests.ConfigurationTest; -import cc.carm.lib.configuration.demo.tests.model.AbstractRecord; -import cc.carm.lib.configuration.yaml.YAMLConfigProvider; -import config.model.AnyModel; -import config.model.SomeModel; -import config.source.ModelConfiguration; -import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerialization; -import org.junit.Test; - -public class DemoConfigTest { - - static { - ConfigurationSerialization.registerClass(SomeModel.class); - ConfigurationSerialization.registerClass(AnyModel.class); - } - - protected final YAMLConfigProvider provider = EasyConfiguration.from("target/config.yml", "test/test2/config.yml"); - - @Test - public void onTest() { - - ConfigurationTest.testDemo(this.provider); - ConfigurationTest.testInner(this.provider); - - testSerialization(this.provider); - - ConfigurationTest.save(this.provider); - } - - - public static void testSerialization(YAMLConfigProvider provider) { - provider.initialize(ModelConfiguration.class); - System.out.println("----------------------------------------------------"); - - AbstractRecord someModel = ModelConfiguration.SOME_MODEL.get(); - if (someModel != null) System.out.println(someModel.getName()); - - AbstractRecord anyModel = ModelConfiguration.ANY_MODEL.get(); - if (anyModel != null) System.out.println(anyModel.getName()); - - ModelConfiguration.MODELS.forEach(System.out::println); - ModelConfiguration.MODEL_MAP.forEach((v, anyModel1) -> System.out.println(v + " -> " + anyModel1.toString())); - - - System.out.println("----------------------------------------------------"); - } - - -} diff --git a/providers/yaml/src/test/java/config/model/AnyModel.java b/providers/yaml/src/test/java/config/model/AnyModel.java deleted file mode 100644 index 4f619a8..0000000 --- a/providers/yaml/src/test/java/config/model/AnyModel.java +++ /dev/null @@ -1,50 +0,0 @@ -package config.model; - -import cc.carm.lib.configuration.demo.tests.model.AbstractRecord; -import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; -import org.bspfsystems.yamlconfiguration.serialization.SerializableAs; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.TestOnly; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -@SerializableAs("AnyModel") -public class AnyModel extends AbstractRecord implements ConfigurationSerializable { - - public final boolean bool; - - public AnyModel(@NotNull String name, boolean bool) { - super(name); - this.bool = bool; - } - - @Override - public String toString() { - return "AnyModel{" + - "name='" + name + '\'' + - ", bool=" + bool + - '}'; - } - - @Override - public @NotNull Map serialize() { - Map map = new HashMap<>(); - map.put("name", name); - map.put("state", bool); - return map; - } - - public static AnyModel random() { - return new AnyModel(UUID.randomUUID().toString().substring(0, 5), Math.random() > 0.5); - } - - - @TestOnly - public static AnyModel deserialize(Map args) { - return new AnyModel((String) args.get("name"), (Boolean) args.get("state")); - } - - -} diff --git a/providers/yaml/src/test/java/config/model/SomeModel.java b/providers/yaml/src/test/java/config/model/SomeModel.java deleted file mode 100644 index 4308bfe..0000000 --- a/providers/yaml/src/test/java/config/model/SomeModel.java +++ /dev/null @@ -1,50 +0,0 @@ -package config.model; - -import cc.carm.lib.configuration.demo.tests.model.AbstractRecord; -import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; -import org.bspfsystems.yamlconfiguration.serialization.SerializableAs; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.TestOnly; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -@SerializableAs("SomeModel") -public class SomeModel extends AbstractRecord implements ConfigurationSerializable { - - public final int num; - - public SomeModel(@NotNull String name, int num) { - super(name); - this.num = num; - } - - @Override - public String toString() { - return "SomeModel{" + - "name='" + name + '\'' + - ", num=" + num + - '}'; - } - - @Override - public @NotNull Map serialize() { - Map map = new HashMap<>(); - map.put("name", name); - map.put("num", num); - return map; - } - - public static SomeModel random() { - return new SomeModel(UUID.randomUUID().toString().substring(0, 5), (int) (Math.random() * 1000)); - } - - - @TestOnly - public static SomeModel deserialize(Map args) { - return new SomeModel((String) args.get("name"), (Integer) args.get("num")); - } - - -} diff --git a/providers/yaml/src/test/java/config/source/ModelConfiguration.java b/providers/yaml/src/test/java/config/source/ModelConfiguration.java deleted file mode 100644 index 8095fe8..0000000 --- a/providers/yaml/src/test/java/config/source/ModelConfiguration.java +++ /dev/null @@ -1,43 +0,0 @@ -package config.source; - -import cc.carm.lib.configuration.source.Configuration; -import cc.carm.lib.configuration.annotation.ConfigPath; -import cc.carm.lib.configuration.annotation.HeaderComment; -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.ConfiguredSectionMap; -import cc.carm.lib.configuration.demo.tests.model.AbstractRecord; -import cc.carm.lib.configuration.yaml.value.ConfiguredSerializable; -import config.model.AnyModel; -import config.model.SomeModel; - -@HeaderComment("以下内容用于测试序列化") -@ConfigPath("model-test") -public class ModelConfiguration implements Configuration { - - public static final ConfigValue SOME_MODEL = ConfiguredSerializable.of( - SomeModel.class, SomeModel.random() - ); - - public static final ConfigValue ANY_MODEL = ConfiguredSerializable.of( - AnyModel.class, AnyModel.random() - ); - - public static final ConfiguredList MODELS = ConfiguredList.builderOf(AnyModel.class) - .fromMap() - .parseValue(AnyModel::deserialize).serializeValue(AnyModel::serialize) - .defaults(AnyModel.random(), AnyModel.random(), AnyModel.random()) - .build(); - - public static final ConfiguredSectionMap MODEL_MAP = ConfiguredMap.builderOf(String.class, AnyModel.class) - .asLinkedMap().fromSection() - .parseValue(v -> new AnyModel(v.getString("name", "EMPTY"), v.getBoolean("state", false))) - .serializeValue(AnyModel::serialize) - .defaults(m -> { - m.put("a", AnyModel.random()); - m.put("b", AnyModel.random()); - }) - .build(); - -} diff --git a/providers/yaml/src/test/java/sample/Sample.java b/providers/yaml/src/test/java/sample/Sample.java index 83a9b7c..9c458cd 100644 --- a/providers/yaml/src/test/java/sample/Sample.java +++ b/providers/yaml/src/test/java/sample/Sample.java @@ -1,7 +1,5 @@ package sample; -import cc.carm.lib.configuration.EasyConfiguration; - public class Sample { public static void main(String[] args) { From e840f6bd50d4019f766f44d11459c737ef297ffe Mon Sep 17 00:00:00 2001 From: Carm Date: Thu, 13 Feb 2025 04:42:49 +0800 Subject: [PATCH 16/17] feat(versioned): Add versioned feature --- features/versioned/pom.xml | 51 +++++++++++++++++++ .../annotation/ConfigVersion.java | 28 ++++++++++ .../commentable/VersionedMetaTypes.java | 25 +++++++++ .../option/VersionedOptions.java | 13 +++++ pom.xml | 1 + 5 files changed, 118 insertions(+) create mode 100644 features/versioned/pom.xml create mode 100644 features/versioned/src/main/java/cc/carm/lib/configuration/annotation/ConfigVersion.java create mode 100644 features/versioned/src/main/java/cc/carm/lib/configuration/commentable/VersionedMetaTypes.java create mode 100644 features/versioned/src/main/java/cc/carm/lib/configuration/option/VersionedOptions.java diff --git a/features/versioned/pom.xml b/features/versioned/pom.xml new file mode 100644 index 0000000..1b40382 --- /dev/null +++ b/features/versioned/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + cc.carm.lib + easyconfiguration-parent + 3.9.1 + ../../pom.xml + + + ${project.jdk.version} + ${project.jdk.version} + UTF-8 + UTF-8 + + + easyconfiguration-feature-versioned + jar + + + + ${project.groupId} + easyconfiguration-core + ${project.version} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + \ No newline at end of file diff --git a/features/versioned/src/main/java/cc/carm/lib/configuration/annotation/ConfigVersion.java b/features/versioned/src/main/java/cc/carm/lib/configuration/annotation/ConfigVersion.java new file mode 100644 index 0000000..19ba260 --- /dev/null +++ b/features/versioned/src/main/java/cc/carm/lib/configuration/annotation/ConfigVersion.java @@ -0,0 +1,28 @@ +package cc.carm.lib.configuration.annotation; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * The version of specific {@link cc.carm.lib.configuration.value.ConfigValue}. + *
Used for versioning target field for rewrite/upgrade. + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ConfigVersion { + + /** + * The version of the configuration field. + * + * @return the version of the configuration field + */ + @Range(from = 0, to = Integer.MAX_VALUE) + int value() default 0; + +} diff --git a/features/versioned/src/main/java/cc/carm/lib/configuration/commentable/VersionedMetaTypes.java b/features/versioned/src/main/java/cc/carm/lib/configuration/commentable/VersionedMetaTypes.java new file mode 100644 index 0000000..5b77346 --- /dev/null +++ b/features/versioned/src/main/java/cc/carm/lib/configuration/commentable/VersionedMetaTypes.java @@ -0,0 +1,25 @@ +package cc.carm.lib.configuration.commentable; + +import cc.carm.lib.configuration.annotation.ConfigVersion; +import cc.carm.lib.configuration.source.ConfigurationHolder; +import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; +import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; +import org.jetbrains.annotations.NotNull; + +public interface VersionedMetaTypes { + + /** + * The version of specific {@link cc.carm.lib.configuration.value.ConfigValue}. + *
Used for versioning target field for rewrite/upgrade. + */ + ConfigurationMetadata VERSION = ConfigurationMetadata.of(0); + + static void register(@NotNull ConfigurationHolder provider) { + register(provider.initializer()); + } + + static void register(@NotNull ConfigurationInitializer initializer) { + initializer.registerAnnotation(ConfigVersion.class, VERSION, ConfigVersion::value); + } + +} diff --git a/features/versioned/src/main/java/cc/carm/lib/configuration/option/VersionedOptions.java b/features/versioned/src/main/java/cc/carm/lib/configuration/option/VersionedOptions.java new file mode 100644 index 0000000..4387206 --- /dev/null +++ b/features/versioned/src/main/java/cc/carm/lib/configuration/option/VersionedOptions.java @@ -0,0 +1,13 @@ +package cc.carm.lib.configuration.option; + +import cc.carm.lib.configuration.source.option.ConfigurationOption; + +public interface VersionedOptions { + + /** + * Whether to set newer defaults when a {@link cc.carm.lib.configuration.value.ConfigValue}'s marked version + * is newer than the current in storage. + */ + ConfigurationOption RESET_NEWER_DEFAULTS = ConfigurationOption.of(true); + +} diff --git a/pom.xml b/pom.xml index fcbba7f..5e691ce 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ core features/commentable features/file + features/versioned providers/yaml providers/gson From 2cda4ae11c69e9033beeff7449910b5d1ef5867b Mon Sep 17 00:00:00 2001 From: Carm Date: Thu, 13 Feb 2025 04:46:27 +0800 Subject: [PATCH 17/17] chore(sql): Add readme descriptions --- providers/sql/README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/providers/sql/README.md b/providers/sql/README.md index 2bdf1e3..c2b19fd 100644 --- a/providers/sql/README.md +++ b/providers/sql/README.md @@ -6,17 +6,18 @@ SQL database implementation, support for MySQL or MariaDB. ```mysql CREATE TABLE IF NOT EXISTS conf ( -`namespace` VARCHAR(32) NOT NULL, # 命名空间 (代表其属于谁,类似于单个配置文件地址的概念) -`path` VARCHAR(96) NOT NULL, # 配置路径 (ConfigPath) -`type` TINYINT UNSIGNED NOT NULL DEFAULT 0, # 数据类型 (Integer/Byte/List/Map/...) -`value` MEDIUMTEXT, # 配置项的值 (可能为JSON格式) -`inline_comments` TEXT, # 行内注释 -`header_comments` MEDIUMTEXT, # 顶部注释 -`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, # 创建时间 -`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -PRIMARY KEY (`namespace`, `path`) + `namespace` VARCHAR(32) NOT NULL, # 命名空间 (代表其属于谁,类似于单个配置文件地址的概念) + `path` VARCHAR(96) NOT NULL, # 配置路径 (ConfigPath) + `type` TINYINT UNSIGNED NOT NULL DEFAULT 0, # 数据类型 (Integer/Byte/List/Map/...) + `value` MEDIUMTEXT, # 配置项的值 (可能为JSON格式) + `usage` TEXT, # 配置项的用法,本质是行内注释 + `descriptions` MEDIUMTEXT, # 配置项的描述,本质是顶部注释 + `version` INT UNSIGNED NOT NULL DEFAULT 0, # 配置项的版本 + `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, # 创建时间 + `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`namespace`, `path`) ) ENGINE = InnoDB -DEFAULT CHARSET = utf8mb4; + DEFAULT CHARSET = utf8mb4; ``` ## Dependencies