mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-04 18:48:20 +08:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 89c8ec8adf | |||
| e8f49bf8bc | |||
| 8ac980fdbb | |||
| 9f2e4bc0cb | |||
| ae16d131c3 | |||
| bd8470a6e8 | |||
| 6af2d3fef5 | |||
| 00f83002c5 | |||
| 0aa548cbbf | |||
| 9c0ed1c5c2 | |||
| bb0998cbac | |||
| 1eb16f00b6 | |||
| 5ccf63b423 | |||
| f1c0c74574 | |||
| 8ee074474c | |||
| 27a68ead7c | |||
| c6cce5208f | |||
| bc67de06f6 | |||
| b668794f5d | |||
| 07424284b7 | |||
| 81e024e309 | |||
| 763fc7c758 | |||
| 56557221a4 | |||
| e4435bf883 | |||
| eee4a278d9 | |||
| 3a0a8e79b9 | |||
| 3b2b1b27cc | |||
| d84ea1b7da | |||
| a1f2cdca04 | |||
| c52183aadd | |||
| d71aabad2d | |||
| 6a007c5187 | |||
| 43b00f2b69 | |||
| 2e61e66cdb | |||
| 39f946c28e | |||
| 25931ffd7e | |||
| de103da879 | |||
| 457c22d461 | |||
| aa4225dbba | |||
| ddd33154be | |||
| 727c26a2fb | |||
| 9c95a16d90 | |||
| 92c05f1a59 | |||
| 739ed41885 | |||
| a66da01996 | |||
| 6dc0447502 | |||
| c49d904665 | |||
| b756074ddc | |||
| 9e3dff3e95 | |||
| fd01d9b7ef | |||
| 0f8383bbf3 | |||
| 1232c7c4da | |||
| 7ac39da4e9 | |||
| bf89f583db | |||
| 03c69ba3a2 | |||
| d9cbd1a283 | |||
| 96e90dd71b | |||
| a9f3d829bd |
+3
-3
@@ -5,12 +5,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>easyconfiguration-parent</artifactId>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<version>3.3.0</version>
|
<version>3.8.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
|
||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package cc.carm.lib.configuration.core.builder;
|
package cc.carm.lib.configuration.core.builder;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
||||||
|
import cc.carm.lib.configuration.core.value.ValueManifest;
|
||||||
import cc.carm.lib.configuration.core.value.ConfigValue;
|
import cc.carm.lib.configuration.core.value.ConfigValue;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T, B, P>, P extends ConfigurationProvider<?>> {
|
public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T, B, P>, P extends ConfigurationProvider<?>> {
|
||||||
|
|
||||||
@@ -61,4 +63,15 @@ public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T
|
|||||||
return getThis();
|
return getThis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NotNull B defaults(@NotNull Supplier<@Nullable T> defaultValueSupplier) {
|
||||||
|
return defaults(defaultValueSupplier.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected @NotNull ValueManifest<T> buildManifest() {
|
||||||
|
return ValueManifest.of(
|
||||||
|
this.provider, this.path,
|
||||||
|
this.headerComments, this.inlineComment, this.defaultValue
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package cc.carm.lib.configuration.core.builder;
|
|||||||
|
|
||||||
import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder;
|
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.ConfigMapBuilder;
|
||||||
|
import cc.carm.lib.configuration.core.builder.map.ConfigMapCreator;
|
||||||
import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder;
|
import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
@@ -19,24 +20,24 @@ public class ConfigBuilder {
|
|||||||
return new ConfigListBuilder<>(valueClass);
|
return new ConfigListBuilder<>(valueClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asMap(@NotNull Class<K> keyClass,
|
public <K, V> @NotNull ConfigMapCreator<K, V> asMap(@NotNull Class<K> keyClass,
|
||||||
@NotNull Class<V> valueClass) {
|
@NotNull Class<V> valueClass) {
|
||||||
return new ConfigMapBuilder<>(LinkedHashMap::new, keyClass, valueClass);
|
return new ConfigMapCreator<>(keyClass, valueClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <K, V> @NotNull ConfigMapBuilder<HashMap<K, V>, K, V> asHashMap(@NotNull Class<K> keyClass,
|
public <K, V> @NotNull ConfigMapBuilder<HashMap<K, V>, K, V> asHashMap(@NotNull Class<K> keyClass,
|
||||||
@NotNull Class<V> valueClass) {
|
@NotNull Class<V> valueClass) {
|
||||||
return asMap(keyClass, valueClass).supplier(HashMap::new);
|
return asMap(keyClass, valueClass).asHashMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asLinkedMap(@NotNull Class<K> keyClass,
|
public <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asLinkedMap(@NotNull Class<K> keyClass,
|
||||||
@NotNull Class<V> valueClass) {
|
@NotNull Class<V> valueClass) {
|
||||||
return asMap(keyClass, valueClass);
|
return asMap(keyClass, valueClass).asLinkedMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public <K extends Comparable<K>, V> @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap(@NotNull Class<K> keyClass,
|
public <K extends Comparable<K>, V> @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap(@NotNull Class<K> keyClass,
|
||||||
@NotNull Class<V> valueClass) {
|
@NotNull Class<V> valueClass) {
|
||||||
return asMap(keyClass, valueClass).supplier(TreeMap::new);
|
return asMap(keyClass, valueClass).asTreeMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-2
@@ -1,9 +1,10 @@
|
|||||||
package cc.carm.lib.configuration.core.builder.list;
|
package cc.carm.lib.configuration.core.builder.list;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.core.annotation.InlineComment;
|
|
||||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
public class ConfigListBuilder<V> {
|
public class ConfigListBuilder<V> {
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ public class ConfigListBuilder<V> {
|
|||||||
this.valueClass = valueClass;
|
this.valueClass = valueClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull <S> SourceListBuilder<S, V> from(@NotNull Class<S> sourceClass,
|
public @NotNull <S> SourceListBuilder<S, V> from(@NotNull Class<? super S> sourceClass,
|
||||||
@NotNull ConfigDataFunction<Object, S> sourceParser,
|
@NotNull ConfigDataFunction<Object, S> sourceParser,
|
||||||
@NotNull ConfigDataFunction<S, V> valueParser,
|
@NotNull ConfigDataFunction<S, V> valueParser,
|
||||||
@NotNull ConfigDataFunction<V, S> valueSerializer,
|
@NotNull ConfigDataFunction<V, S> valueSerializer,
|
||||||
@@ -45,4 +46,13 @@ public class ConfigListBuilder<V> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NotNull SourceListBuilder<Map<String, Object>, V> fromMap() {
|
||||||
|
return from(
|
||||||
|
Map.class, obj -> (Map<String, Object>) obj,
|
||||||
|
ConfigDataFunction.required(),
|
||||||
|
ConfigDataFunction.required(),
|
||||||
|
ConfigDataFunction.toObject()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-5
@@ -7,11 +7,12 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, SourceListBuilder<S, V>> {
|
public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, SourceListBuilder<S, V>> {
|
||||||
|
|
||||||
protected final @NotNull Class<S> sourceClass;
|
protected final @NotNull Class<? super S> sourceClass;
|
||||||
protected @NotNull ConfigDataFunction<Object, S> sourceParser;
|
protected @NotNull ConfigDataFunction<Object, S> sourceParser;
|
||||||
|
|
||||||
protected final @NotNull Class<V> valueClass;
|
protected final @NotNull Class<V> valueClass;
|
||||||
@@ -20,7 +21,7 @@ public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, Source
|
|||||||
protected @NotNull ConfigDataFunction<V, S> valueSerializer;
|
protected @NotNull ConfigDataFunction<V, S> valueSerializer;
|
||||||
protected @NotNull ConfigDataFunction<S, Object> sourceSerializer;
|
protected @NotNull ConfigDataFunction<S, Object> sourceSerializer;
|
||||||
|
|
||||||
public SourceListBuilder(@NotNull Class<S> sourceClass, @NotNull ConfigDataFunction<Object, S> sourceParser,
|
public SourceListBuilder(@NotNull Class<? super S> sourceClass, @NotNull ConfigDataFunction<Object, S> sourceParser,
|
||||||
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<S, V> valueParser,
|
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<S, V> valueParser,
|
||||||
@NotNull ConfigDataFunction<V, S> valueSerializer,
|
@NotNull ConfigDataFunction<V, S> valueSerializer,
|
||||||
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
|
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
|
||||||
@@ -37,6 +38,10 @@ public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, Source
|
|||||||
return defaults(new ArrayList<>(Arrays.asList(values)));
|
return defaults(new ArrayList<>(Arrays.asList(values)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final @NotNull SourceListBuilder<S, V> defaults(@NotNull Collection<V> values) {
|
||||||
|
return defaults(new ArrayList<>(values));
|
||||||
|
}
|
||||||
|
|
||||||
public @NotNull SourceListBuilder<S, V> parseSource(ConfigDataFunction<Object, S> sourceParser) {
|
public @NotNull SourceListBuilder<S, V> parseSource(ConfigDataFunction<Object, S> sourceParser) {
|
||||||
this.sourceParser = sourceParser;
|
this.sourceParser = sourceParser;
|
||||||
return this;
|
return this;
|
||||||
@@ -65,9 +70,7 @@ public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, Source
|
|||||||
@Override
|
@Override
|
||||||
public @NotNull ConfiguredList<V> build() {
|
public @NotNull ConfiguredList<V> build() {
|
||||||
return new ConfiguredList<>(
|
return new ConfiguredList<>(
|
||||||
this.provider, this.path,
|
buildManifest(), this.valueClass,
|
||||||
this.headerComments, this.inlineComment,
|
|
||||||
this.valueClass, this.defaultValue,
|
|
||||||
this.sourceParser.andThen(this.valueParser),
|
this.sourceParser.andThen(this.valueParser),
|
||||||
this.valueSerializer.andThen(sourceSerializer)
|
this.valueSerializer.andThen(sourceSerializer)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -48,6 +48,14 @@ public class ConfigMapBuilder<M extends Map<K, V>, K, V> {
|
|||||||
return fromString(ConfigDataFunction.castFromString(this.valueClass));
|
return fromString(ConfigDataFunction.castFromString(this.valueClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SectionMapBuilder<M, K, V> fromSection() {
|
||||||
|
return new SectionMapBuilder<>(
|
||||||
|
supplier,
|
||||||
|
keyClass, ConfigDataFunction.castFromString(keyClass),
|
||||||
|
valueClass, ConfigDataFunction.required(),
|
||||||
|
ConfigDataFunction.castToString(), ConfigDataFunction.required());
|
||||||
|
}
|
||||||
|
|
||||||
public SourceMapBuilder<M, Object, K, V> fromObject(@NotNull ConfigDataFunction<Object, V> valueParser) {
|
public SourceMapBuilder<M, Object, K, V> fromObject(@NotNull ConfigDataFunction<Object, V> valueParser) {
|
||||||
return from(Object.class, valueParser, ConfigDataFunction.toObject());
|
return from(Object.class, valueParser, ConfigDataFunction.toObject());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package cc.carm.lib.configuration.core.builder.map;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ConfigMapCreator<K, V> {
|
||||||
|
|
||||||
|
protected final @NotNull Class<K> keyClass;
|
||||||
|
protected final @NotNull Class<V> valueClass;
|
||||||
|
|
||||||
|
public ConfigMapCreator(@NotNull Class<K> keyClass, @NotNull Class<V> valueClass) {
|
||||||
|
this.keyClass = keyClass;
|
||||||
|
this.valueClass = valueClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <M extends Map<K, V>> @NotNull ConfigMapBuilder<M, K, V> asMap(Supplier<M> mapSuppler) {
|
||||||
|
return new ConfigMapBuilder<>(mapSuppler, keyClass, valueClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull ConfigMapBuilder<HashMap<K, V>, K, V> asHashMap() {
|
||||||
|
return asMap(HashMap::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asLinkedMap() {
|
||||||
|
return asMap(LinkedHashMap::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap() {
|
||||||
|
return asMap(TreeMap::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
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 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<M extends Map<K, V>, K, V> extends CommonConfigBuilder<M, SectionMapBuilder<M, K, V>> {
|
||||||
|
|
||||||
|
protected final @NotNull Supplier<@NotNull M> supplier;
|
||||||
|
|
||||||
|
protected final @NotNull Class<K> keyClass;
|
||||||
|
protected @NotNull ConfigDataFunction<String, K> keyParser;
|
||||||
|
|
||||||
|
protected final @NotNull Class<V> valueClass;
|
||||||
|
protected @NotNull ConfigDataFunction<ConfigurationWrapper<?>, V> valueParser;
|
||||||
|
|
||||||
|
protected @NotNull ConfigDataFunction<K, String> keySerializer;
|
||||||
|
protected @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> valueSerializer;
|
||||||
|
|
||||||
|
public SectionMapBuilder(@NotNull Supplier<@NotNull M> supplier,
|
||||||
|
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
|
||||||
|
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<ConfigurationWrapper<?>, V> valueParser,
|
||||||
|
@NotNull ConfigDataFunction<K, String> keySerializer,
|
||||||
|
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> valueSerializer) {
|
||||||
|
this.supplier = supplier;
|
||||||
|
this.keyClass = keyClass;
|
||||||
|
this.keyParser = keyParser;
|
||||||
|
this.valueClass = valueClass;
|
||||||
|
this.valueParser = valueParser;
|
||||||
|
this.keySerializer = keySerializer;
|
||||||
|
this.valueSerializer = valueSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <MAP extends Map<K, V>> SectionMapBuilder<MAP, K, V> supplier(@NotNull Supplier<MAP> supplier) {
|
||||||
|
return new SectionMapBuilder<>(supplier,
|
||||||
|
keyClass, keyParser, valueClass, valueParser, keySerializer, valueSerializer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SectionMapBuilder<M, K, V> defaults(@NotNull Consumer<M> factory) {
|
||||||
|
M map = supplier.get();
|
||||||
|
factory.accept(map);
|
||||||
|
return defaults(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SectionMapBuilder<M, K, V> parseKey(@NotNull ConfigDataFunction<String, K> parser) {
|
||||||
|
this.keyParser = parser;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SectionMapBuilder<M, K, V> parseValue(@NotNull ConfigDataFunction<ConfigurationWrapper<?>, V> parser) {
|
||||||
|
this.valueParser = parser;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SectionMapBuilder<M, K, V> serializeKey(@NotNull ConfigDataFunction<K, String> serializer) {
|
||||||
|
this.keySerializer = serializer;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SectionMapBuilder<M, K, V> serializeValue(@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
|
||||||
|
this.valueSerializer = serializer;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull SectionMapBuilder<M, K, V> serializeValue(@NotNull BiConsumer<V, Map<String, Object>> serializer) {
|
||||||
|
return serializeValue(v -> {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
serializer.accept(v, map);
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @NotNull SectionMapBuilder<M, K, V> getThis() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConfiguredSectionMap<K, V> 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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+10
-4
@@ -2,10 +2,12 @@ package cc.carm.lib.configuration.core.builder.map;
|
|||||||
|
|
||||||
import cc.carm.lib.configuration.core.builder.CommonConfigBuilder;
|
import cc.carm.lib.configuration.core.builder.CommonConfigBuilder;
|
||||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
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.core.value.type.ConfiguredMap;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class SourceMapBuilder<M extends Map<K, V>, S, K, V> extends CommonConfigBuilder<M, SourceMapBuilder<M, S, K, V>> {
|
public class SourceMapBuilder<M extends Map<K, V>, S, K, V> extends CommonConfigBuilder<M, SourceMapBuilder<M, S, K, V>> {
|
||||||
@@ -51,6 +53,12 @@ public class SourceMapBuilder<M extends Map<K, V>, S, K, V> extends CommonConfig
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NotNull SourceMapBuilder<M, S, K, V> defaults(@NotNull Consumer<M> factory) {
|
||||||
|
M map = supplier.get();
|
||||||
|
factory.accept(map);
|
||||||
|
return defaults(map);
|
||||||
|
}
|
||||||
|
|
||||||
public @NotNull SourceMapBuilder<M, S, K, V> parseKey(@NotNull ConfigDataFunction<String, K> parser) {
|
public @NotNull SourceMapBuilder<M, S, K, V> parseKey(@NotNull ConfigDataFunction<String, K> parser) {
|
||||||
this.keyParser = parser;
|
this.keyParser = parser;
|
||||||
return this;
|
return this;
|
||||||
@@ -89,10 +97,8 @@ public class SourceMapBuilder<M extends Map<K, V>, S, K, V> extends CommonConfig
|
|||||||
@Override
|
@Override
|
||||||
public @NotNull ConfiguredMap<K, V> build() {
|
public @NotNull ConfiguredMap<K, V> build() {
|
||||||
return new ConfiguredMap<>(
|
return new ConfiguredMap<>(
|
||||||
this.provider, this.path,
|
new ValueManifest<>(provider, path, headerComments, inlineComment, defaultValue),
|
||||||
this.headerComments, this.inlineComment,
|
this.supplier, this.keyClass, this.keyParser,
|
||||||
this.defaultValue, this.supplier,
|
|
||||||
this.keyClass, this.keyParser,
|
|
||||||
this.valueClass, this.sourceParser.andThen(this.valueParser),
|
this.valueClass, this.sourceParser.andThen(this.valueParser),
|
||||||
this.keySerializer, this.valueSerializer.andThen(this.sourceSerializer)
|
this.keySerializer, this.valueSerializer.andThen(this.sourceSerializer)
|
||||||
);
|
);
|
||||||
|
|||||||
+4
-1
@@ -46,7 +46,10 @@ public class ConfigValueBuilder<V> {
|
|||||||
return from(
|
return from(
|
||||||
Object.class, ConfigDataFunction.identity(),
|
Object.class, ConfigDataFunction.identity(),
|
||||||
ConfigValueParser.castObject(valueClass),
|
ConfigValueParser.castObject(valueClass),
|
||||||
ConfigDataFunction.toObject(), ConfigDataFunction.toObject()
|
s -> {
|
||||||
|
if (s instanceof Enum<?>) return ((Enum<?>) s).name();
|
||||||
|
else return s;
|
||||||
|
}, ConfigDataFunction.toObject()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-6
@@ -32,6 +32,10 @@ public class SectionValueBuilder<V>
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NotNull SectionValueBuilder<V> parseValue(ConfigDataFunction<ConfigurationWrapper<?>, V> valueParser) {
|
||||||
|
return parseValue((section, path) -> valueParser.parse(section));
|
||||||
|
}
|
||||||
|
|
||||||
public @NotNull SectionValueBuilder<V> parseValue(ConfigValueParser<ConfigurationWrapper<?>, V> valueParser) {
|
public @NotNull SectionValueBuilder<V> parseValue(ConfigValueParser<ConfigurationWrapper<?>, V> valueParser) {
|
||||||
this.parser = valueParser;
|
this.parser = valueParser;
|
||||||
return this;
|
return this;
|
||||||
@@ -44,12 +48,7 @@ public class SectionValueBuilder<V>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ConfiguredSection<V> build() {
|
public @NotNull ConfiguredSection<V> build() {
|
||||||
return new ConfiguredSection<>(
|
return new ConfiguredSection<>(buildManifest(), this.valueClass, this.parser, this.serializer);
|
||||||
this.provider, this.path,
|
|
||||||
this.headerComments, this.inlineComment,
|
|
||||||
this.valueClass, this.defaultValue,
|
|
||||||
this.parser, this.serializer
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -39,6 +39,10 @@ public class SourceValueBuilder<S, V> extends CommonConfigBuilder<V, SourceValue
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @NotNull SourceValueBuilder<S, V> parseValue(ConfigDataFunction<S, V> valueParser) {
|
||||||
|
return parseValue((section, path) -> valueParser.parse(section));
|
||||||
|
}
|
||||||
|
|
||||||
public @NotNull SourceValueBuilder<S, V> parseValue(@NotNull ConfigValueParser<S, V> valueParser) {
|
public @NotNull SourceValueBuilder<S, V> parseValue(@NotNull ConfigValueParser<S, V> valueParser) {
|
||||||
this.valueParser = valueParser;
|
this.valueParser = valueParser;
|
||||||
return this;
|
return this;
|
||||||
@@ -57,9 +61,7 @@ public class SourceValueBuilder<S, V> extends CommonConfigBuilder<V, SourceValue
|
|||||||
@Override
|
@Override
|
||||||
public @NotNull ConfiguredValue<V> build() {
|
public @NotNull ConfiguredValue<V> build() {
|
||||||
return new ConfiguredValue<>(
|
return new ConfiguredValue<>(
|
||||||
this.provider, this.path,
|
buildManifest(), this.valueClass,
|
||||||
this.headerComments, this.inlineComment,
|
|
||||||
this.valueClass, this.defaultValue,
|
|
||||||
this.valueParser.compose(this.sourceParser),
|
this.valueParser.compose(this.sourceParser),
|
||||||
this.valueSerializer.andThen(sourceSerializer)
|
this.valueSerializer.andThen(sourceSerializer)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,34 +13,34 @@ public interface ConfigDataFunction<T, R> {
|
|||||||
|
|
||||||
default <V> @NotNull ConfigDataFunction<T, V> andThen(@NotNull ConfigDataFunction<? super R, V> after) {
|
default <V> @NotNull ConfigDataFunction<T, V> andThen(@NotNull ConfigDataFunction<? super R, V> after) {
|
||||||
Objects.requireNonNull(after);
|
Objects.requireNonNull(after);
|
||||||
return ((data) -> after.parse(parse(data)));
|
return data -> after.parse(parse(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static <T> @NotNull ConfigDataFunction<T, T> identity() {
|
static <T> @NotNull ConfigDataFunction<T, T> identity() {
|
||||||
return (input) -> input;
|
return input -> input;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static <T> @NotNull ConfigDataFunction<T, T> identity(Class<T> type) {
|
static <T> @NotNull ConfigDataFunction<T, T> identity(Class<T> type) {
|
||||||
return (input) -> input;
|
return input -> input;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static <T, V> @NotNull ConfigDataFunction<T, V> required() {
|
static <T, V> @NotNull ConfigDataFunction<T, V> required() {
|
||||||
return (input) -> {
|
return input -> {
|
||||||
throw new IllegalArgumentException("Please specify the value parser.");
|
throw new IllegalArgumentException("Please specify the value parser.");
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static <T> @NotNull ConfigDataFunction<T, Object> toObject() {
|
static <T> @NotNull ConfigDataFunction<T, Object> toObject() {
|
||||||
return (input) -> input;
|
return input -> input;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static <V> @NotNull ConfigDataFunction<Object, V> castObject(Class<V> valueClass) {
|
static <V> @NotNull ConfigDataFunction<Object, V> castObject(Class<V> valueClass) {
|
||||||
return (input) -> {
|
return input -> {
|
||||||
if (valueClass.isInstance(input)) return valueClass.cast(input);
|
if (valueClass.isInstance(input)) return valueClass.cast(input);
|
||||||
else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName());
|
else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName());
|
||||||
};
|
};
|
||||||
@@ -48,7 +48,7 @@ public interface ConfigDataFunction<T, R> {
|
|||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static <V> @NotNull ConfigDataFunction<String, V> castFromString(Class<V> valueClass) {
|
static <V> @NotNull ConfigDataFunction<String, V> castFromString(Class<V> valueClass) {
|
||||||
return (input) -> {
|
return input -> {
|
||||||
if (valueClass.isInstance(input)) return valueClass.cast(input);
|
if (valueClass.isInstance(input)) return valueClass.cast(input);
|
||||||
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
|
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
|
||||||
};
|
};
|
||||||
@@ -56,12 +56,101 @@ public interface ConfigDataFunction<T, R> {
|
|||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static <T> @NotNull ConfigDataFunction<T, String> castToString() {
|
static <T> @NotNull ConfigDataFunction<T, String> castToString() {
|
||||||
return (input) -> {
|
return input -> {
|
||||||
if (input instanceof String) return (String) input;
|
if (input instanceof String) return (String) input;
|
||||||
|
else if (input instanceof Enum<?>) return ((Enum<?>) input).name();
|
||||||
else return input.toString();
|
else return input.toString();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
static <V> @NotNull ConfigDataFunction<String, V> parseString(Class<V> valueClass) {
|
||||||
|
return input -> {
|
||||||
|
if (valueClass.isInstance(input)) return valueClass.cast(input);
|
||||||
|
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
static @NotNull ConfigDataFunction<Object, Integer> intValue() {
|
||||||
|
return input -> {
|
||||||
|
if (input instanceof Integer) {
|
||||||
|
return (Integer) input;
|
||||||
|
} else if (input instanceof Number) {
|
||||||
|
return ((Number) input).intValue();
|
||||||
|
} else throw new IllegalArgumentException("Cannot cast value to " + Integer.class.getName());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
static @NotNull ConfigDataFunction<Object, Short> shortValue() {
|
||||||
|
return input -> {
|
||||||
|
if (input instanceof Short) {
|
||||||
|
return (Short) input;
|
||||||
|
} else if (input instanceof Number) {
|
||||||
|
return ((Number) input).shortValue();
|
||||||
|
} else throw new IllegalArgumentException("Cannot cast value to " + Short.class.getName());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
static @NotNull ConfigDataFunction<Object, Double> doubleValue() {
|
||||||
|
return input -> {
|
||||||
|
if (input instanceof Double) {
|
||||||
|
return (Double) input;
|
||||||
|
} else if (input instanceof Number) {
|
||||||
|
return ((Number) input).doubleValue();
|
||||||
|
} else throw new IllegalArgumentException("Cannot cast value to " + Double.class.getName());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
static @NotNull ConfigDataFunction<Object, Byte> byteValue() {
|
||||||
|
return input -> {
|
||||||
|
if (input instanceof Byte) {
|
||||||
|
return (Byte) input;
|
||||||
|
} else if (input instanceof Number) {
|
||||||
|
return ((Number) input).byteValue();
|
||||||
|
} else throw new IllegalArgumentException("Cannot cast value to " + Byte.class.getName());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
static @NotNull ConfigDataFunction<Object, Float> floatValue() {
|
||||||
|
return input -> {
|
||||||
|
if (input instanceof Float) {
|
||||||
|
return (Float) input;
|
||||||
|
} else if (input instanceof Number) {
|
||||||
|
return ((Number) input).floatValue();
|
||||||
|
} else throw new IllegalArgumentException("Cannot cast value to " + Float.class.getName());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
static @NotNull ConfigDataFunction<Object, Long> longValue() {
|
||||||
|
return input -> {
|
||||||
|
if (input instanceof Long) {
|
||||||
|
return (Long) input;
|
||||||
|
} else if (input instanceof Number) {
|
||||||
|
return ((Number) input).longValue();
|
||||||
|
} else throw new IllegalArgumentException("Cannot cast value to " + Long.class.getName());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
static @NotNull ConfigDataFunction<Object, Boolean> booleanValue() {
|
||||||
|
return input -> {
|
||||||
|
if (input instanceof Boolean) {
|
||||||
|
return (Boolean) input;
|
||||||
|
} else if (input instanceof String) {
|
||||||
|
String s = (String) input;
|
||||||
|
return Boolean.parseBoolean(s) || "yes".equalsIgnoreCase(s);
|
||||||
|
} else if (input instanceof Integer) {
|
||||||
|
return (Integer) input == 1;
|
||||||
|
} else throw new IllegalArgumentException("Cannot cast value to " + Boolean.class.getName());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,23 +50,25 @@ public interface ConfigValueParser<T, R> {
|
|||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static <V> @NotNull ConfigValueParser<Object, V> castObject(Class<V> valueClass) {
|
static <V> @NotNull ConfigValueParser<Object, V> castObject(Class<V> valueClass) {
|
||||||
return (input, defaultValue) -> {
|
return (input, defaultValue) -> {
|
||||||
|
|
||||||
if (Number.class.isAssignableFrom(valueClass)) {
|
if (Number.class.isAssignableFrom(valueClass)) {
|
||||||
if (Long.class.isAssignableFrom(valueClass)) {
|
if (Long.class.isAssignableFrom(valueClass) || long.class.isAssignableFrom(valueClass)) {
|
||||||
input = longValue().parse(input, (Long) defaultValue);
|
input = longValue().parse(input, (Long) defaultValue);
|
||||||
} else if (Integer.class.isAssignableFrom(valueClass)) {
|
} else if (Integer.class.isAssignableFrom(valueClass) || int.class.isAssignableFrom(valueClass)) {
|
||||||
input = intValue().parse(input, (Integer) defaultValue);
|
input = intValue().parse(input, (Integer) defaultValue);
|
||||||
} else if (Float.class.isAssignableFrom(valueClass)) {
|
} else if (Float.class.isAssignableFrom(valueClass) || float.class.isAssignableFrom(valueClass)) {
|
||||||
input = floatValue().parse(input, (Float) defaultValue);
|
input = floatValue().parse(input, (Float) defaultValue);
|
||||||
} else if (Double.class.isAssignableFrom(valueClass)) {
|
} else if (Double.class.isAssignableFrom(valueClass) || double.class.isAssignableFrom(valueClass)) {
|
||||||
input = doubleValue().parse(input, (Double) defaultValue);
|
input = doubleValue().parse(input, (Double) defaultValue);
|
||||||
} else if (Byte.class.isAssignableFrom(valueClass)) {
|
} else if (Byte.class.isAssignableFrom(valueClass) || byte.class.isAssignableFrom(valueClass)) {
|
||||||
input = byteValue().parse(input, (Byte) defaultValue);
|
input = byteValue().parse(input, (Byte) defaultValue);
|
||||||
} else if (Short.class.isAssignableFrom(valueClass)) {
|
} else if (Short.class.isAssignableFrom(valueClass) || short.class.isAssignableFrom(valueClass)) {
|
||||||
input = shortValue().parse(input, (Short) defaultValue);
|
input = shortValue().parse(input, (Short) defaultValue);
|
||||||
}
|
}
|
||||||
} else if (Boolean.class.isAssignableFrom(valueClass)) {
|
} else if (Boolean.class.isAssignableFrom(valueClass) || boolean.class.isAssignableFrom(valueClass)) {
|
||||||
input = booleanValue().parse(input, (Boolean) defaultValue);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valueClass.isInstance(input)) return valueClass.cast(input);
|
if (valueClass.isInstance(input)) return valueClass.cast(input);
|
||||||
@@ -90,91 +92,53 @@ public interface ConfigValueParser<T, R> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
|
||||||
static @NotNull <T> ConfigValueParser<T, String> castToString(Class<T> clazz) {
|
|
||||||
return (input, defaultValue) -> {
|
|
||||||
if (input instanceof String) return (String) input;
|
|
||||||
else return input.toString();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static @NotNull ConfigValueParser<Object, Integer> intValue() {
|
static @NotNull ConfigValueParser<Object, Integer> intValue() {
|
||||||
return (input, defaultValue) -> {
|
return (input, defaultValue) -> ConfigDataFunction.intValue().parse(input);
|
||||||
if (input instanceof Integer) {
|
|
||||||
return (Integer) input;
|
|
||||||
} else if (input instanceof Number) {
|
|
||||||
return ((Number) input).intValue();
|
|
||||||
} else throw new IllegalArgumentException("Cannot cast value to " + Integer.class.getName());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static @NotNull ConfigValueParser<Object, Short> shortValue() {
|
static @NotNull ConfigValueParser<Object, Short> shortValue() {
|
||||||
return (input, defaultValue) -> {
|
return (input, defaultValue) -> ConfigDataFunction.shortValue().parse(input);
|
||||||
if (input instanceof Short) {
|
|
||||||
return (Short) input;
|
|
||||||
} else if (input instanceof Number) {
|
|
||||||
return ((Number) input).shortValue();
|
|
||||||
} else throw new IllegalArgumentException("Cannot cast value to " + Short.class.getName());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static @NotNull ConfigValueParser<Object, Double> doubleValue() {
|
static @NotNull ConfigValueParser<Object, Double> doubleValue() {
|
||||||
return (input, defaultValue) -> {
|
return (input, defaultValue) -> ConfigDataFunction.doubleValue().parse(input);
|
||||||
if (input instanceof Double) {
|
|
||||||
return (Double) input;
|
|
||||||
} else if (input instanceof Number) {
|
|
||||||
return ((Number) input).doubleValue();
|
|
||||||
} else throw new IllegalArgumentException("Cannot cast value to " + Double.class.getName());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static @NotNull ConfigValueParser<Object, Byte> byteValue() {
|
static @NotNull ConfigValueParser<Object, Byte> byteValue() {
|
||||||
return (input, defaultValue) -> {
|
return (input, defaultValue) -> ConfigDataFunction.byteValue().parse(input);
|
||||||
if (input instanceof Byte) {
|
|
||||||
return (Byte) input;
|
|
||||||
} else if (input instanceof Number) {
|
|
||||||
return ((Number) input).byteValue();
|
|
||||||
} else throw new IllegalArgumentException("Cannot cast value to " + Byte.class.getName());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static @NotNull ConfigValueParser<Object, Float> floatValue() {
|
static @NotNull ConfigValueParser<Object, Float> floatValue() {
|
||||||
return (input, defaultValue) -> {
|
return (input, defaultValue) -> ConfigDataFunction.floatValue().parse(input);
|
||||||
if (input instanceof Float) {
|
|
||||||
return (Float) input;
|
|
||||||
} else if (input instanceof Number) {
|
|
||||||
return ((Number) input).floatValue();
|
|
||||||
} else throw new IllegalArgumentException("Cannot cast value to " + Float.class.getName());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static @NotNull ConfigValueParser<Object, Long> longValue() {
|
static @NotNull ConfigValueParser<Object, Long> longValue() {
|
||||||
return (input, defaultValue) -> {
|
return (input, defaultValue) -> ConfigDataFunction.longValue().parse(input);
|
||||||
if (input instanceof Long) {
|
|
||||||
return (Long) input;
|
|
||||||
} else if (input instanceof Number) {
|
|
||||||
return ((Number) input).longValue();
|
|
||||||
} else throw new IllegalArgumentException("Cannot cast value to " + Long.class.getName());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
static @NotNull ConfigValueParser<Object, Boolean> booleanValue() {
|
static @NotNull ConfigValueParser<Object, Boolean> booleanValue() {
|
||||||
|
return (input, defaultValue) -> ConfigDataFunction.booleanValue().parse(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
static @NotNull <E extends Enum<E>> ConfigValueParser<Object, E> enumValue(Class<E> enumClass) {
|
||||||
return (input, defaultValue) -> {
|
return (input, defaultValue) -> {
|
||||||
if (input instanceof Boolean) {
|
if (input instanceof Enum) {
|
||||||
return (Boolean) input;
|
return enumClass.cast(input);
|
||||||
} else if (input instanceof String) {
|
} else if (input instanceof String) {
|
||||||
String s = (String) input;
|
return Enum.valueOf(enumClass, (String) input);
|
||||||
return Boolean.parseBoolean(s) || "yes".equalsIgnoreCase(s);
|
} else if (input instanceof Number) {
|
||||||
} else if (input instanceof Integer) {
|
return enumClass.getEnumConstants()[((Number) input).intValue()];
|
||||||
return ((Integer) input) == 1;
|
} else {
|
||||||
} else throw new IllegalArgumentException("Cannot cast value to " + Boolean.class.getName());
|
throw new IllegalArgumentException("Cannot cast value to " + enumClass.getName());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import org.jetbrains.annotations.Unmodifiable;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public abstract class ConfigurationComments {
|
public class ConfigurationComments {
|
||||||
|
|
||||||
protected final @NotNull Map<String, List<String>> headerComments = new HashMap<>();
|
protected final @NotNull Map<String, List<String>> headerComments = new HashMap<>();
|
||||||
protected final @NotNull Map<String, String> inlineComments = new HashMap<>();
|
protected final @NotNull Map<String, String> inlineComments = new HashMap<>();
|
||||||
|
|||||||
@@ -11,11 +11,16 @@ import org.jetbrains.annotations.Unmodifiable;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置文件提供者,用于为 {@link ConfigValue} 提供配置文件的源,以便实现读取、保存等操作。
|
||||||
|
*
|
||||||
|
* @param <W> 配置文件的原生功能类
|
||||||
|
*/
|
||||||
public abstract class ConfigurationProvider<W extends ConfigurationWrapper<?>> {
|
public abstract class ConfigurationProvider<W extends ConfigurationWrapper<?>> {
|
||||||
|
|
||||||
protected long updateTime;
|
protected long updateTime;
|
||||||
|
|
||||||
public ConfigurationProvider() {
|
protected ConfigurationProvider() {
|
||||||
this.updateTime = System.currentTimeMillis();
|
this.updateTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+17
-17
@@ -5,16 +5,20 @@ import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public abstract class FileConfigProvider<W extends ConfigurationWrapper<?>> extends ConfigurationProvider<W> {
|
public abstract class FileConfigProvider<W extends ConfigurationWrapper<?>> extends ConfigurationProvider<W> {
|
||||||
|
|
||||||
protected final @NotNull File file;
|
protected final @NotNull File file;
|
||||||
|
|
||||||
public FileConfigProvider(@NotNull File file) {
|
protected FileConfigProvider(@NotNull File file) {
|
||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,39 +41,35 @@ public abstract class FileConfigProvider<W extends ConfigurationWrapper<?>> exte
|
|||||||
if (sourcePath != null) {
|
if (sourcePath != null) {
|
||||||
try {
|
try {
|
||||||
saveResource(sourcePath, true);
|
saveResource(sourcePath, true);
|
||||||
} catch (Exception ignored) {
|
} catch (IllegalArgumentException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveResource(@NotNull String resourcePath, boolean replace)
|
public void saveResource(@NotNull String resourcePath, boolean replace)
|
||||||
throws NullPointerException, IOException, IllegalArgumentException {
|
throws IOException, IllegalArgumentException {
|
||||||
Objects.requireNonNull(resourcePath, "ResourcePath cannot be null");
|
Objects.requireNonNull(resourcePath, "ResourcePath cannot be null");
|
||||||
if (resourcePath.equals("")) throw new IllegalArgumentException("ResourcePath cannot be empty");
|
if (resourcePath.isEmpty()) throw new IllegalArgumentException("ResourcePath cannot be empty");
|
||||||
|
|
||||||
resourcePath = resourcePath.replace('\\', '/');
|
resourcePath = resourcePath.replace('\\', '/');
|
||||||
InputStream in = getResource(resourcePath);
|
|
||||||
if (in == null) throw new IllegalArgumentException("The resource '" + resourcePath + "' not exists");
|
|
||||||
|
|
||||||
|
URL url = this.getClass().getClassLoader().getResource(resourcePath);
|
||||||
|
if (url == null) throw new IllegalArgumentException("The resource '" + resourcePath + "' not exists");
|
||||||
|
|
||||||
int lastIndex = resourcePath.lastIndexOf('/');
|
File outDir = file.getParentFile();
|
||||||
File outDir = new File(file, resourcePath.substring(0, Math.max(lastIndex, 0)));
|
|
||||||
|
|
||||||
if (!outDir.exists() && !outDir.mkdirs()) throw new IOException("Failed to create directory " + outDir);
|
if (!outDir.exists() && !outDir.mkdirs()) throw new IOException("Failed to create directory " + outDir);
|
||||||
if (!file.exists() || replace) {
|
if (!file.exists() || replace) {
|
||||||
try {
|
try (OutputStream out = Files.newOutputStream(file.toPath())) {
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
OutputStream out = new FileOutputStream(file);
|
connection.setUseCaches(false);
|
||||||
|
try (InputStream in = connection.getInputStream()) {
|
||||||
byte[] buf = new byte[1024];
|
byte[] buf = new byte[1024];
|
||||||
int len;
|
int len;
|
||||||
while ((len = in.read(buf)) > 0) {
|
while ((len = in.read(buf)) > 0) {
|
||||||
out.write(buf, 0, len);
|
out.write(buf, 0, len);
|
||||||
}
|
}
|
||||||
out.close();
|
}
|
||||||
in.close();
|
|
||||||
|
|
||||||
} catch (IOException ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,62 +2,42 @@ package cc.carm.lib.configuration.core.value;
|
|||||||
|
|
||||||
import cc.carm.lib.configuration.core.builder.ConfigBuilder;
|
import cc.carm.lib.configuration.core.builder.ConfigBuilder;
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
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.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.Unmodifiable;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
public abstract class ConfigValue<T> {
|
public abstract class ConfigValue<T> extends ValueManifest<T> {
|
||||||
|
|
||||||
public static @NotNull ConfigBuilder builder() {
|
public static @NotNull ConfigBuilder builder() {
|
||||||
return new ConfigBuilder();
|
return new ConfigBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected @Nullable ConfigurationProvider<?> provider;
|
protected ConfigValue(@NotNull ValueManifest<T> manifest) {
|
||||||
protected @Nullable String configPath;
|
super(manifest.provider, manifest.configPath, manifest.headerComments, manifest.inlineComment, manifest.defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
protected @Nullable List<String> headerComments;
|
/**
|
||||||
protected @Nullable String inlineComments;
|
* @param provider 配置文件提供者
|
||||||
|
* @param configPath 配置路径
|
||||||
protected @Nullable T defaultValue;
|
* @param headerComments 头部注释内容
|
||||||
|
* @param inlineComments 行内注释内容
|
||||||
public ConfigValue(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
|
* @param defaultValue 默认参数值
|
||||||
|
* @deprecated 请使用 {@link #ConfigValue(ValueManifest)} 构造器。
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
protected ConfigValue(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
|
||||||
@Nullable List<String> headerComments, @Nullable String inlineComments,
|
@Nullable List<String> headerComments, @Nullable String inlineComments,
|
||||||
@Nullable T defaultValue) {
|
@Nullable T defaultValue) {
|
||||||
this.provider = provider;
|
super(provider, configPath, headerComments, inlineComments, defaultValue);
|
||||||
this.configPath = configPath;
|
|
||||||
this.headerComments = headerComments;
|
|
||||||
this.inlineComments = inlineComments;
|
|
||||||
this.defaultValue = defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void initialize(@NotNull ConfigurationProvider<?> provider, boolean saveDefault, @NotNull String configPath,
|
public void initialize(@NotNull ConfigurationProvider<?> provider, boolean saveDefault, @NotNull String configPath,
|
||||||
@Nullable List<String> headerComments, @Nullable String inlineComments) {
|
@Nullable List<String> headerComments, @Nullable String inlineComments) {
|
||||||
if (this.provider == null) this.provider = provider;
|
this.initialize(provider, configPath, headerComments, inlineComments);
|
||||||
if (this.configPath == null) this.configPath = configPath;
|
|
||||||
if (this.headerComments == null) this.headerComments = headerComments;
|
|
||||||
if (this.inlineComments == null) this.inlineComments = inlineComments;
|
|
||||||
if (saveDefault) setDefault();
|
if (saveDefault) setDefault();
|
||||||
|
|
||||||
if (getHeaderComments() != null) {
|
|
||||||
this.provider.setHeaderComment(getConfigPath(), getHeaderComments());
|
|
||||||
}
|
|
||||||
if (getInlineComments() != null) {
|
|
||||||
this.provider.setInlineComment(getConfigPath(), getInlineComments());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable T getDefaultValue() {
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDefaultValue(@Nullable T defaultValue) {
|
|
||||||
this.defaultValue = defaultValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,39 +111,4 @@ public abstract class ConfigValue<T> {
|
|||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
|
||||||
return getConfiguration().get(getConfigPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setValue(@Nullable Object value) {
|
|
||||||
getConfiguration().set(getConfigPath(), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable String getInlineComments() {
|
|
||||||
return inlineComments;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Unmodifiable
|
|
||||||
public @Nullable List<String> getHeaderComments() {
|
|
||||||
return headerComments;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
package cc.carm.lib.configuration.core.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;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.Unmodifiable;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置值描述清单。用于描述一个配置值的相关基础信息。
|
||||||
|
*
|
||||||
|
* @param <T> 配置值类型
|
||||||
|
* @author CarmJos
|
||||||
|
*/
|
||||||
|
public class ValueManifest<T> {
|
||||||
|
|
||||||
|
public static <V> ValueManifest<V> of(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
|
||||||
|
@Nullable List<String> headerComments, @Nullable String inlineComments) {
|
||||||
|
return new ValueManifest<>(provider, configPath, headerComments, inlineComments, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <V> ValueManifest<V> of(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
|
||||||
|
@Nullable List<String> 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<String> headerComments;
|
||||||
|
protected @Nullable String inlineComment;
|
||||||
|
|
||||||
|
protected @Nullable T defaultValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param provider 配置文件提供者
|
||||||
|
* @param configPath 配置路径
|
||||||
|
* @param headerComments 头部注释内容
|
||||||
|
* @param inlineComment 行内注释内容
|
||||||
|
* @param defaultValue 默认参数值
|
||||||
|
*/
|
||||||
|
public ValueManifest(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
|
||||||
|
@Nullable List<String> headerComments, @Nullable String inlineComment,
|
||||||
|
@Nullable T defaultValue) {
|
||||||
|
this.provider = provider;
|
||||||
|
this.configPath = configPath;
|
||||||
|
this.headerComments = headerComments;
|
||||||
|
this.inlineComment = inlineComment;
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 此方法提供给 {@link ConfigInitializer},以便对配置值的相关信息进行统一初始化操作。
|
||||||
|
*
|
||||||
|
* @param provider 配置文件提供者
|
||||||
|
* @param configPath 配置路径
|
||||||
|
* @param headerComments 头部注释内容
|
||||||
|
* @param inlineComment 行内注释内容
|
||||||
|
*/
|
||||||
|
protected void initialize(@NotNull ConfigurationProvider<?> provider, @NotNull String configPath,
|
||||||
|
@Nullable List<String> 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<String> getHeaderComments() {
|
||||||
|
return headerComments;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+17
-12
@@ -1,21 +1,19 @@
|
|||||||
package cc.carm.lib.configuration.core.value.impl;
|
package cc.carm.lib.configuration.core.value.impl;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
|
||||||
import cc.carm.lib.configuration.core.value.ConfigValue;
|
import cc.carm.lib.configuration.core.value.ConfigValue;
|
||||||
|
import cc.carm.lib.configuration.core.value.ValueManifest;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class CachedConfigValue<T> extends ConfigValue<T> {
|
public abstract class CachedConfigValue<T> extends ConfigValue<T> {
|
||||||
|
|
||||||
|
|
||||||
protected @Nullable T cachedValue;
|
protected @Nullable T cachedValue;
|
||||||
protected long parsedTime = -1;
|
protected long parsedTime = -1;
|
||||||
|
|
||||||
public CachedConfigValue(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
|
protected CachedConfigValue(@NotNull ValueManifest<T> manifest) {
|
||||||
@Nullable List<String> headerComments, @Nullable String inlineComments,
|
super(manifest);
|
||||||
@Nullable T defaultValue) {
|
|
||||||
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected T updateCache(T value) {
|
protected T updateCache(T value) {
|
||||||
@@ -32,12 +30,19 @@ public abstract class CachedConfigValue<T> extends ConfigValue<T> {
|
|||||||
return this.parsedTime <= 0 || getProvider().isExpired(this.parsedTime);
|
return this.parsedTime <= 0 || getProvider().isExpired(this.parsedTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final T useDefault() {
|
protected final T getDefaultFirst(@Nullable T value) {
|
||||||
return useOrDefault(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final T useOrDefault(@Nullable T value) {
|
|
||||||
return updateCache(this.defaultValue == null ? value : this.defaultValue);
|
return updateCache(this.defaultValue == null ? value : this.defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected @Nullable T getCachedOrDefault() {
|
||||||
|
return getCachedOrDefault(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract("!null->!null")
|
||||||
|
protected T getCachedOrDefault(@Nullable T emptyValue) {
|
||||||
|
if (getCachedValue() != null) return getCachedValue();
|
||||||
|
else if (getDefaultValue() != null) return getDefaultValue();
|
||||||
|
else return emptyValue;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,214 @@
|
|||||||
|
package cc.carm.lib.configuration.core.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 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<K, V, S> extends CachedConfigValue<Map<K, V>> implements Map<K, V> {
|
||||||
|
|
||||||
|
public static <K, V> @NotNull ConfigMapCreator<K, V> builderOf(@NotNull Class<K> keyClass,
|
||||||
|
@NotNull Class<V> valueClass) {
|
||||||
|
return builder().asMap(keyClass, valueClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final @NotNull Supplier<? extends Map<K, V>> supplier;
|
||||||
|
|
||||||
|
protected final @NotNull Class<? super S> sourceClass;
|
||||||
|
protected final @NotNull Class<K> keyClass;
|
||||||
|
protected final @NotNull Class<V> valueClass;
|
||||||
|
|
||||||
|
protected final @NotNull ConfigDataFunction<String, K> keyParser;
|
||||||
|
protected final @NotNull ConfigDataFunction<S, V> valueParser;
|
||||||
|
|
||||||
|
protected final @NotNull ConfigDataFunction<K, String> keySerializer;
|
||||||
|
protected final @NotNull ConfigDataFunction<V, Object> valueSerializer;
|
||||||
|
|
||||||
|
|
||||||
|
protected ConfigValueMap(@NotNull ValueManifest<Map<K, V>> manifest, @NotNull Class<? super S> sourceClass,
|
||||||
|
@NotNull Supplier<? extends Map<K, V>> mapObjSupplier,
|
||||||
|
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
|
||||||
|
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<S, V> valueParser,
|
||||||
|
@NotNull ConfigDataFunction<K, String> keySerializer,
|
||||||
|
@NotNull ConfigDataFunction<V, Object> 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<? super S> getSourceClass() {
|
||||||
|
return sourceClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull Class<K> getKeyClass() {
|
||||||
|
return keyClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull Class<V> getValueClass() {
|
||||||
|
return valueClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull ConfigDataFunction<String, K> getKeyParser() {
|
||||||
|
return keyParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull ConfigDataFunction<S, V> getValueParser() {
|
||||||
|
return valueParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull ConfigDataFunction<K, String> getKeySerializer() {
|
||||||
|
return keySerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull ConfigDataFunction<V, Object> getValueSerializer() {
|
||||||
|
return valueSerializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract S getSource(ConfigurationWrapper<?> section, String dataKey);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Map<K, V> get() {
|
||||||
|
if (!isExpired()) return getCachedOrDefault(supplier.get());
|
||||||
|
|
||||||
|
// 已过时的数据,需要重新解析一次。
|
||||||
|
Map<K, V> map = supplier.get();
|
||||||
|
|
||||||
|
ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
|
||||||
|
if (section == null) return getDefaultFirst(map);
|
||||||
|
|
||||||
|
Set<String> 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<K, V> value) {
|
||||||
|
updateCache(value);
|
||||||
|
if (value == null) setValue(null);
|
||||||
|
else {
|
||||||
|
Map<String, Object> data = new LinkedHashMap<>();
|
||||||
|
for (Map.Entry<K, V> entry : value.entrySet()) {
|
||||||
|
try {
|
||||||
|
data.put(
|
||||||
|
keySerializer.parse(entry.getKey()),
|
||||||
|
valueSerializer.parse(entry.getValue())
|
||||||
|
);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setValue(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> @NotNull T modifyValue(Function<Map<K, V>, T> function) {
|
||||||
|
Map<K, V> m = get();
|
||||||
|
T result = function.apply(m);
|
||||||
|
set(m);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull Map<K, V> modifyMap(Consumer<Map<K, V>> consumer) {
|
||||||
|
Map<K, V> 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<? extends K, ? extends V> m) {
|
||||||
|
modifyMap(map -> map.putAll(m));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
modifyMap(Map::clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Set<K> keySet() {
|
||||||
|
return get().keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Collection<V> values() {
|
||||||
|
return get().values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
@Unmodifiable
|
||||||
|
public Set<Entry<K, V>> entrySet() {
|
||||||
|
return get().entrySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,34 +1,40 @@
|
|||||||
package cc.carm.lib.configuration.core.value.type;
|
package cc.carm.lib.configuration.core.value.type;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.core.annotation.HeaderComment;
|
|
||||||
import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder;
|
import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder;
|
||||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||||
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.core.value.impl.CachedConfigValue;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
|
public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements List<V> {
|
||||||
|
|
||||||
public static <V> @NotNull ConfigListBuilder<V> builder(@NotNull Class<V> valueClass) {
|
public static <V> @NotNull ConfigListBuilder<V> builderOf(@NotNull Class<V> valueClass) {
|
||||||
return builder().asList(valueClass);
|
return builder().asList(valueClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@HeaderComment
|
public static <V> @NotNull ConfiguredList<V> of(@NotNull Class<V> valueClass, @NotNull Collection<V> defaults) {
|
||||||
|
return builderOf(valueClass).fromObject().defaults(defaults).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
public static <V> @NotNull ConfiguredList<V> of(@NotNull Class<V> valueClass, @NotNull V... defaults) {
|
||||||
|
return builderOf(valueClass).fromObject().defaults(defaults).build();
|
||||||
|
}
|
||||||
|
|
||||||
protected final @NotNull Class<V> valueClass;
|
protected final @NotNull Class<V> valueClass;
|
||||||
|
|
||||||
protected final @NotNull ConfigDataFunction<Object, V> parser;
|
protected final @NotNull ConfigDataFunction<Object, V> parser;
|
||||||
protected final @NotNull ConfigDataFunction<V, Object> serializer;
|
protected final @NotNull ConfigDataFunction<V, Object> serializer;
|
||||||
|
|
||||||
public ConfiguredList(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
|
public ConfiguredList(@NotNull ValueManifest<List<V>> manifest, @NotNull Class<V> valueClass,
|
||||||
@Nullable List<String> headerComments, @Nullable String inlineComments,
|
|
||||||
@NotNull Class<V> valueClass, @Nullable List<V> defaultValue,
|
|
||||||
@NotNull ConfigDataFunction<Object, V> parser,
|
@NotNull ConfigDataFunction<Object, V> parser,
|
||||||
@NotNull ConfigDataFunction<V, Object> serializer) {
|
@NotNull ConfigDataFunction<V, Object> serializer) {
|
||||||
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
|
super(manifest);
|
||||||
this.valueClass = valueClass;
|
this.valueClass = valueClass;
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
this.serializer = serializer;
|
this.serializer = serializer;
|
||||||
@@ -36,10 +42,13 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull List<V> get() {
|
public @NotNull List<V> get() {
|
||||||
if (isExpired()) { // 已过时的数据,需要重新解析一次。
|
if (!isExpired()) return getCachedOrDefault(new ArrayList<>());
|
||||||
|
|
||||||
|
// 已过时的数据,需要重新解析一次。
|
||||||
List<V> list = new ArrayList<>();
|
List<V> list = new ArrayList<>();
|
||||||
List<?> data = getConfiguration().getList(getConfigPath());
|
List<?> data = getConfiguration().contains(getConfigPath()) ?
|
||||||
if (data == null || data.isEmpty()) return useOrDefault(list);
|
getConfiguration().getList(getConfigPath()) : null;
|
||||||
|
if (data == null) return getDefaultFirst(list);
|
||||||
for (Object dataVal : data) {
|
for (Object dataVal : data) {
|
||||||
if (dataVal == null) continue;
|
if (dataVal == null) continue;
|
||||||
try {
|
try {
|
||||||
@@ -49,9 +58,29 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updateCache(list);
|
return updateCache(list);
|
||||||
} else if (getCachedValue() != null) return getCachedValue();
|
}
|
||||||
else if (getDefaultValue() != null) return getDefaultValue();
|
|
||||||
else return new ArrayList<>();
|
@Override
|
||||||
|
public V get(int index) {
|
||||||
|
return get().get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull List<V> copy() {
|
||||||
|
return new ArrayList<>(get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> @NotNull T handle(Function<List<V>, T> function) {
|
||||||
|
List<V> list = get();
|
||||||
|
T result = function.apply(list);
|
||||||
|
set(list);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull List<V> modify(Consumer<List<V>> consumer) {
|
||||||
|
List<V> list = get();
|
||||||
|
consumer.accept(list);
|
||||||
|
set(list);
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -72,5 +101,121 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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<V> iterator() {
|
||||||
|
return get().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Object @NotNull [] toArray() {
|
||||||
|
return get().toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public <T> 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<? extends V> c) {
|
||||||
|
return handle(list -> list.addAll(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addAll(int index, @NotNull Collection<? extends V> 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<V> listIterator() {
|
||||||
|
return get().listIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public ListIterator<V> listIterator(int index) {
|
||||||
|
return get().listIterator(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public List<V> subList(int fromIndex, int toIndex) {
|
||||||
|
return get().subList(fromIndex, toIndex);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,126 +1,28 @@
|
|||||||
package cc.carm.lib.configuration.core.value.type;
|
package cc.carm.lib.configuration.core.value.type;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.core.builder.map.ConfigMapBuilder;
|
|
||||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
|
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
|
||||||
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
|
import cc.carm.lib.configuration.core.value.ValueManifest;
|
||||||
|
import cc.carm.lib.configuration.core.value.impl.ConfigValueMap;
|
||||||
import org.jetbrains.annotations.NotNull;
|
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.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> {
|
public class ConfiguredMap<K, V> extends ConfigValueMap<K, V, Object> {
|
||||||
|
|
||||||
public static <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> builder(@NotNull Class<K> keyClass,
|
public ConfiguredMap(@NotNull ValueManifest<Map<K, V>> manifest,
|
||||||
@NotNull Class<V> valueClass) {
|
@NotNull Supplier<? extends Map<K, V>> mapObjSupplier,
|
||||||
return builder().asMap(keyClass, valueClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final @NotNull Supplier<? extends Map<K, V>> supplier;
|
|
||||||
|
|
||||||
protected final @NotNull Class<K> keyClass;
|
|
||||||
protected final @NotNull Class<V> valueClass;
|
|
||||||
|
|
||||||
protected final @NotNull ConfigDataFunction<String, K> keyParser;
|
|
||||||
protected final @NotNull ConfigDataFunction<Object, V> valueParser;
|
|
||||||
|
|
||||||
protected final @NotNull ConfigDataFunction<K, String> keySerializer;
|
|
||||||
protected final @NotNull ConfigDataFunction<V, Object> valueSerializer;
|
|
||||||
|
|
||||||
public ConfiguredMap(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
|
|
||||||
@Nullable List<String> headerComments, @Nullable String inlineComments,
|
|
||||||
@Nullable Map<K, V> defaultValue, @NotNull Supplier<? extends Map<K, V>> supplier,
|
|
||||||
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
|
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
|
||||||
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<Object, V> valueParser,
|
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<Object, V> valueParser,
|
||||||
@NotNull ConfigDataFunction<K, String> keySerializer,
|
@NotNull ConfigDataFunction<K, String> keySerializer,
|
||||||
@NotNull ConfigDataFunction<V, Object> valueSerializer) {
|
@NotNull ConfigDataFunction<V, Object> valueSerializer) {
|
||||||
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
|
super(manifest, Object.class, mapObjSupplier, keyClass, keyParser, valueClass, valueParser, keySerializer, valueSerializer);
|
||||||
this.supplier = supplier;
|
|
||||||
this.keyClass = keyClass;
|
|
||||||
this.valueClass = valueClass;
|
|
||||||
this.keyParser = keyParser;
|
|
||||||
this.valueParser = valueParser;
|
|
||||||
this.keySerializer = keySerializer;
|
|
||||||
this.valueSerializer = valueSerializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull Class<K> getKeyClass() {
|
|
||||||
return keyClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull Class<V> getValueClass() {
|
|
||||||
return valueClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull ConfigDataFunction<String, K> getKeyParser() {
|
|
||||||
return keyParser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull ConfigDataFunction<Object, V> getValueParser() {
|
|
||||||
return valueParser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull ConfigDataFunction<K, String> getKeySerializer() {
|
|
||||||
return keySerializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NotNull ConfigDataFunction<V, Object> getValueSerializer() {
|
|
||||||
return valueSerializer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Map<K, V> get() {
|
public Object getSource(ConfigurationWrapper<?> section, String dataKey) {
|
||||||
if (isExpired()) { // 已过时的数据,需要重新解析一次。
|
return section.get(dataKey);
|
||||||
Map<K, V> map = supplier.get();
|
|
||||||
|
|
||||||
ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
|
|
||||||
if (section == null) return useOrDefault(map);
|
|
||||||
|
|
||||||
Set<String> keys = section.getKeys(false);
|
|
||||||
if (keys.isEmpty()) return useOrDefault(map);
|
|
||||||
|
|
||||||
for (String dataKey : keys) {
|
|
||||||
Object dataVal = section.get(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);
|
|
||||||
} else if (getCachedValue() != null) return getCachedValue();
|
|
||||||
else if (getDefaultValue() != null) return getDefaultValue();
|
|
||||||
else return supplier.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void set(Map<K, V> value) {
|
|
||||||
updateCache(value);
|
|
||||||
if (value == null) setValue(null);
|
|
||||||
else {
|
|
||||||
Map<String, Object> data = new LinkedHashMap<>();
|
|
||||||
for (Map.Entry<K, V> entry : value.entrySet()) {
|
|
||||||
try {
|
|
||||||
data.put(
|
|
||||||
keySerializer.parse(entry.getKey()),
|
|
||||||
valueSerializer.parse(entry.getValue())
|
|
||||||
);
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setValue(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-12
@@ -3,19 +3,17 @@ package cc.carm.lib.configuration.core.value.type;
|
|||||||
import cc.carm.lib.configuration.core.builder.value.SectionValueBuilder;
|
import cc.carm.lib.configuration.core.builder.value.SectionValueBuilder;
|
||||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||||
import cc.carm.lib.configuration.core.function.ConfigValueParser;
|
import cc.carm.lib.configuration.core.function.ConfigValueParser;
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
|
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.core.value.impl.CachedConfigValue;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class ConfiguredSection<V> extends CachedConfigValue<V> {
|
public class ConfiguredSection<V> extends CachedConfigValue<V> {
|
||||||
|
|
||||||
public static <V> @NotNull SectionValueBuilder<V> builder(@NotNull Class<V> valueClass) {
|
public static <V> @NotNull SectionValueBuilder<V> builderOf(@NotNull Class<V> valueClass) {
|
||||||
return builder().asValue(valueClass).fromSection();
|
return builder().asValue(valueClass).fromSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,12 +22,10 @@ public class ConfiguredSection<V> extends CachedConfigValue<V> {
|
|||||||
protected final @NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser;
|
protected final @NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser;
|
||||||
protected final @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer;
|
protected final @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer;
|
||||||
|
|
||||||
public ConfiguredSection(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
|
public ConfiguredSection(@NotNull ValueManifest<V> manifest, @NotNull Class<V> valueClass,
|
||||||
@Nullable List<String> headerComments, @Nullable String inlineComments,
|
|
||||||
@NotNull Class<V> valueClass, @Nullable V defaultValue,
|
|
||||||
@NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser,
|
@NotNull ConfigValueParser<ConfigurationWrapper<?>, V> parser,
|
||||||
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
|
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
|
||||||
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
|
super(manifest);
|
||||||
this.valueClass = valueClass;
|
this.valueClass = valueClass;
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
this.serializer = serializer;
|
this.serializer = serializer;
|
||||||
@@ -49,18 +45,21 @@ public class ConfiguredSection<V> extends CachedConfigValue<V> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable V get() {
|
public @Nullable V get() {
|
||||||
if (isExpired()) { // 已过时的数据,需要重新解析一次。
|
if (!isExpired()) return getCachedOrDefault();
|
||||||
|
// 已过时的数据,需要重新解析一次。
|
||||||
|
|
||||||
ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
|
ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
|
||||||
if (section == null) return useDefault();
|
if (section == null) return getDefaultValue();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 若未出现错误,则直接更新缓存并返回。
|
// 若未出现错误,则直接更新缓存并返回。
|
||||||
return updateCache(this.parser.parse(section, this.defaultValue));
|
return updateCache(this.parser.parse(section, this.defaultValue));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 出现了解析错误,提示并返回默认值。
|
// 出现了解析错误,提示并返回默认值。
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return useDefault();
|
return getDefaultValue();
|
||||||
}
|
}
|
||||||
} else return Optional.ofNullable(getCachedValue()).orElse(defaultValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
package cc.carm.lib.configuration.core.value.type;
|
||||||
|
|
||||||
|
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 org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ConfiguredSectionMap<K, V> extends ConfigValueMap<K, V, ConfigurationWrapper<?>> {
|
||||||
|
|
||||||
|
public ConfiguredSectionMap(@NotNull ValueManifest<Map<K, V>> manifest,
|
||||||
|
@NotNull Supplier<? extends Map<K, V>> mapObjSupplier,
|
||||||
|
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
|
||||||
|
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<ConfigurationWrapper<?>, V> valueParser,
|
||||||
|
@NotNull ConfigDataFunction<K, String> keySerializer,
|
||||||
|
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,17 +3,14 @@ package cc.carm.lib.configuration.core.value.type;
|
|||||||
import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder;
|
import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder;
|
||||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||||
import cc.carm.lib.configuration.core.function.ConfigValueParser;
|
import cc.carm.lib.configuration.core.function.ConfigValueParser;
|
||||||
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.core.value.impl.CachedConfigValue;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
||||||
|
|
||||||
public static <V> ConfigValueBuilder<V> builder(Class<V> valueClass) {
|
public static <V> ConfigValueBuilder<V> builderOf(Class<V> valueClass) {
|
||||||
return builder().asValue(valueClass);
|
return builder().asValue(valueClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,7 +19,7 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <V> ConfiguredValue<V> of(Class<V> valueClass, @Nullable V defaultValue) {
|
public static <V> ConfiguredValue<V> of(Class<V> valueClass, @Nullable V defaultValue) {
|
||||||
return builder(valueClass).fromObject().defaults(defaultValue).build();
|
return builderOf(valueClass).fromObject().defaults(defaultValue).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final @NotNull Class<V> valueClass;
|
protected final @NotNull Class<V> valueClass;
|
||||||
@@ -30,13 +27,10 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
|||||||
protected final @NotNull ConfigValueParser<Object, V> parser;
|
protected final @NotNull ConfigValueParser<Object, V> parser;
|
||||||
protected final @NotNull ConfigDataFunction<V, Object> serializer;
|
protected final @NotNull ConfigDataFunction<V, Object> serializer;
|
||||||
|
|
||||||
public ConfiguredValue(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
|
public ConfiguredValue(@NotNull ValueManifest<V> manifest, @NotNull Class<V> valueClass,
|
||||||
@Nullable List<String> headerComments, @Nullable String inlineComments,
|
|
||||||
@NotNull Class<V> valueClass, @Nullable V defaultValue,
|
|
||||||
@NotNull ConfigValueParser<Object, V> parser,
|
@NotNull ConfigValueParser<Object, V> parser,
|
||||||
@NotNull ConfigDataFunction<V, Object> serializer) {
|
@NotNull ConfigDataFunction<V, Object> serializer) {
|
||||||
|
super(manifest);
|
||||||
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
|
|
||||||
this.valueClass = valueClass;
|
this.valueClass = valueClass;
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
this.serializer = serializer;
|
this.serializer = serializer;
|
||||||
@@ -52,18 +46,20 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public V get() {
|
public V get() {
|
||||||
if (isExpired()) { // 已过时的数据,需要重新解析一次。
|
if (!isExpired()) return getCachedOrDefault();
|
||||||
|
// 已过时的数据,需要重新解析一次。
|
||||||
|
|
||||||
Object value = getValue();
|
Object value = getValue();
|
||||||
if (value == null) return useDefault(); // 获取的值不存在,直接使用默认值。
|
if (value == null) return getDefaultValue(); // 获取的值不存在,直接使用默认值。
|
||||||
try {
|
try {
|
||||||
// 若未出现错误,则直接更新缓存并返回。
|
// 若未出现错误,则直接更新缓存并返回。
|
||||||
return updateCache(this.parser.parse(value, this.defaultValue));
|
return updateCache(this.parser.parse(value, this.defaultValue));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 出现了解析错误,提示并返回默认值。
|
// 出现了解析错误,提示并返回默认值。
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return useDefault();
|
return getDefaultValue();
|
||||||
}
|
}
|
||||||
} else return Optional.ofNullable(getCachedValue()).orElse(defaultValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+24
-3
@@ -5,12 +5,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>easyconfiguration-parent</artifactId>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<version>3.3.0</version>
|
<version>3.8.1</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
|
||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
</properties>
|
</properties>
|
||||||
@@ -28,4 +28,25 @@
|
|||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
package cc.carm.lib.configuration.demo.tests;
|
package cc.carm.lib.configuration.demo.tests;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
||||||
import cc.carm.lib.configuration.demo.tests.model.TestModel;
|
|
||||||
import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration;
|
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.conf.TestConfiguration;
|
||||||
|
import cc.carm.lib.configuration.demo.tests.model.TestModel;
|
||||||
|
import org.jetbrains.annotations.TestOnly;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -13,6 +14,7 @@ import java.util.stream.IntStream;
|
|||||||
|
|
||||||
public class ConfigurationTest {
|
public class ConfigurationTest {
|
||||||
|
|
||||||
|
@TestOnly
|
||||||
public static void testDemo(ConfigurationProvider<?> provider) {
|
public static void testDemo(ConfigurationProvider<?> provider) {
|
||||||
provider.initialize(DemoConfiguration.class);
|
provider.initialize(DemoConfiguration.class);
|
||||||
|
|
||||||
@@ -30,16 +32,25 @@ public class ConfigurationTest {
|
|||||||
System.out.println("after: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get());
|
System.out.println("after: " + DemoConfiguration.Sub.UUID_CONFIG_VALUE.get());
|
||||||
|
|
||||||
System.out.println("> Test List:");
|
System.out.println("> Test List:");
|
||||||
DemoConfiguration.Sub.That.OPERATORS.getNotNull().forEach(System.out::println);
|
|
||||||
|
System.out.println(" Before:");
|
||||||
|
DemoConfiguration.Sub.That.OPERATORS.forEach(System.out::println);
|
||||||
List<UUID> operators = IntStream.range(0, 5).mapToObj(i -> UUID.randomUUID()).collect(Collectors.toList());
|
List<UUID> 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);
|
||||||
|
|
||||||
|
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("> Test Section:");
|
System.out.println("> Test Section:");
|
||||||
System.out.println(DemoConfiguration.MODEL_TEST.get());
|
System.out.println(DemoConfiguration.MODEL_TEST.get());
|
||||||
DemoConfiguration.MODEL_TEST.set(TestModel.random());
|
DemoConfiguration.MODEL_TEST.set(TestModel.random());
|
||||||
|
|
||||||
System.out.println("> Test Maps:");
|
System.out.println("> Test Maps:");
|
||||||
DemoConfiguration.USERS.getNotNull().forEach((k, v) -> System.out.println(k + ": " + v));
|
DemoConfiguration.USERS.forEach((k, v) -> System.out.println(k + ": " + v));
|
||||||
LinkedHashMap<Integer, UUID> data = new LinkedHashMap<>();
|
LinkedHashMap<Integer, UUID> data = new LinkedHashMap<>();
|
||||||
for (int i = 1; i <= 5; i++) {
|
for (int i = 1; i <= 5; i++) {
|
||||||
data.put(i, UUID.randomUUID());
|
data.put(i, UUID.randomUUID());
|
||||||
|
|||||||
+13
-14
@@ -12,16 +12,12 @@ import cc.carm.lib.configuration.core.value.type.ConfiguredSection;
|
|||||||
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
|
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
|
||||||
import cc.carm.lib.configuration.demo.tests.model.TestModel;
|
import cc.carm.lib.configuration.demo.tests.model.TestModel;
|
||||||
|
|
||||||
import java.util.List;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
||||||
@HeaderComment({
|
@HeaderComment({"此处内容将显示在配置文件的最上方"})
|
||||||
"此处内容将显示在配置文件的最上方",
|
|
||||||
""/*添加一个空行与其他配置的注释分割*/
|
|
||||||
})
|
|
||||||
public class DemoConfiguration extends ConfigurationRoot {
|
public class DemoConfiguration extends ConfigurationRoot {
|
||||||
|
|
||||||
@ConfigPath(root = true)
|
@ConfigPath(root = true)
|
||||||
@@ -30,6 +26,8 @@ public class DemoConfiguration extends ConfigurationRoot {
|
|||||||
@ConfigPath(root = true)
|
@ConfigPath(root = true)
|
||||||
public static final ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(Long.class, 1000000L);
|
public static final ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(Long.class, 1000000L);
|
||||||
|
|
||||||
|
public static final ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
|
||||||
|
|
||||||
// 支持通过 Class<?> 变量标注子配置,一并注册。
|
// 支持通过 Class<?> 变量标注子配置,一并注册。
|
||||||
// 注意: 若对应类也有注解,则优先使用类的注解。
|
// 注意: 若对应类也有注解,则优先使用类的注解。
|
||||||
@ConfigPath("other-class-config") //支持通过注解修改子配置的主路径,若不修改则以变量名自动生成。
|
@ConfigPath("other-class-config") //支持通过注解修改子配置的主路径,若不修改则以变量名自动生成。
|
||||||
@@ -38,17 +36,18 @@ public class DemoConfiguration extends ConfigurationRoot {
|
|||||||
public static final Class<?> OTHER = OtherConfiguration.class;
|
public static final Class<?> OTHER = OtherConfiguration.class;
|
||||||
|
|
||||||
@ConfigPath("user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
|
@ConfigPath("user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
|
||||||
@HeaderComment({"", "Section类型数据测试"}) // 通过注解给配置添加注释。
|
@HeaderComment({"Section类型数据测试"}) // 通过注解给配置添加注释。
|
||||||
@InlineComment("Section数据也支持InlineComment注释")
|
@InlineComment("Section数据也支持InlineComment注释")
|
||||||
public static final ConfigValue<TestModel> MODEL_TEST = ConfiguredSection
|
public static final ConfigValue<TestModel> MODEL_TEST = ConfiguredSection
|
||||||
.builder(TestModel.class)
|
.builderOf(TestModel.class)
|
||||||
.defaults(new TestModel("Carm", UUID.randomUUID()))
|
.defaults(new TestModel("Carm", UUID.randomUUID()))
|
||||||
.parseValue((section, defaultValue) -> TestModel.deserialize(section))
|
.parseValue((section, defaultValue) -> TestModel.deserialize(section))
|
||||||
.serializeValue(TestModel::serialize).build();
|
.serializeValue(TestModel::serialize).build();
|
||||||
|
|
||||||
@HeaderComment({"", "[ID - UUID]对照表", "", "用于测试Map类型的解析与序列化保存"})
|
@HeaderComment({"[ID - UUID]对照表", "", "用于测试Map类型的解析与序列化保存"})
|
||||||
public static final ConfigValue<Map<Integer, UUID>> USERS = ConfiguredMap
|
public static final ConfiguredMap<Integer, UUID> USERS = ConfiguredMap
|
||||||
.builder(Integer.class, UUID.class).fromString()
|
.builderOf(Integer.class, UUID.class)
|
||||||
|
.asLinkedMap().fromString()
|
||||||
.parseKey(Integer::parseInt)
|
.parseKey(Integer::parseInt)
|
||||||
.parseValue(v -> Objects.requireNonNull(UUID.fromString(v)))
|
.parseValue(v -> Objects.requireNonNull(UUID.fromString(v)))
|
||||||
.build();
|
.build();
|
||||||
@@ -63,14 +62,14 @@ public class DemoConfiguration extends ConfigurationRoot {
|
|||||||
@ConfigPath(value = "uuid-value", root = true)
|
@ConfigPath(value = "uuid-value", root = true)
|
||||||
@InlineComment("This is an inline comment")
|
@InlineComment("This is an inline comment")
|
||||||
public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
|
public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
|
||||||
.builder(UUID.class).fromString()
|
.builderOf(UUID.class).fromString()
|
||||||
.parseValue((data, defaultValue) -> UUID.fromString(data))
|
.parseValue((data, defaultValue) -> UUID.fromString(data))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
public static class That extends ConfigurationRoot {
|
public static class That extends ConfigurationRoot {
|
||||||
|
|
||||||
public static final ConfigValue<List<UUID>> OPERATORS = ConfiguredList
|
public static final ConfiguredList<UUID> OPERATORS = ConfiguredList
|
||||||
.builder(UUID.class).fromString()
|
.builderOf(UUID.class).fromString()
|
||||||
.parseValue(s -> Objects.requireNonNull(UUID.fromString(s)))
|
.parseValue(s -> Objects.requireNonNull(UUID.fromString(s)))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ public class TestConfiguration extends ConfigurationRoot {
|
|||||||
public final ConfigValue<Double> CLASS_VALUE = ConfiguredValue.of(Double.class, 1.0D);
|
public final ConfigValue<Double> CLASS_VALUE = ConfiguredValue.of(Double.class, 1.0D);
|
||||||
|
|
||||||
@ConfigPath("test.user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
|
@ConfigPath("test.user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
|
||||||
@HeaderComment({"", "Section类型数据测试"}) // 通过注解给配置添加注释。
|
@HeaderComment({"Section类型数据测试"}) // 通过注解给配置添加注释。
|
||||||
@InlineComment("Section数据也支持InlineComment注释")
|
@InlineComment("Section数据也支持InlineComment注释")
|
||||||
public final ConfigValue<TestModel> TEST_MODEL = ConfiguredSection
|
public final ConfigValue<TestModel> TEST_MODEL = ConfiguredSection
|
||||||
.builder(TestModel.class)
|
.builderOf(TestModel.class)
|
||||||
.defaults(new TestModel("Carm", UUID.randomUUID()))
|
.defaults(new TestModel("Carm", UUID.randomUUID()))
|
||||||
.parseValue((section, defaultValue) -> TestModel.deserialize(section))
|
.parseValue((section, defaultValue) -> TestModel.deserialize(section))
|
||||||
.serializeValue(TestModel::serialize).build();
|
.serializeValue(TestModel::serialize).build();
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>easyconfiguration-parent</artifactId>
|
||||||
|
<version>3.8.1</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
|
||||||
|
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
|
</properties>
|
||||||
|
<artifactId>easyconfiguration-hocon</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>easyconfiguration-core</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
|
<artifactId>easyconfiguration-demo</artifactId>
|
||||||
|
<version>${project.parent.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.typesafe</groupId>
|
||||||
|
<artifactId>config</artifactId>
|
||||||
|
<version>1.4.3</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package cc.carm.lib.configuration;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.hocon.HOCONFileConfigProvider;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class EasyConfiguration {
|
||||||
|
|
||||||
|
private EasyConfiguration() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HOCONFileConfigProvider from(File file, String source) {
|
||||||
|
HOCONFileConfigProvider provider = new HOCONFileConfigProvider(file);
|
||||||
|
try {
|
||||||
|
provider.initializeFile(source);
|
||||||
|
provider.initializeConfig();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HOCONFileConfigProvider from(File file) {
|
||||||
|
return from(file, file.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HOCONFileConfigProvider from(String fileName) {
|
||||||
|
return from(fileName, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HOCONFileConfigProvider from(String fileName, String source) {
|
||||||
|
return from(new File(fileName), source);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
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;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class HOCONConfigWrapper implements ConfigurationWrapper<Map<String, Object>> {
|
||||||
|
private static final char SEPARATOR = '.';
|
||||||
|
protected final Map<String, Object> data;
|
||||||
|
|
||||||
|
public HOCONConfigWrapper(ConfigObject config) {
|
||||||
|
this.data = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
config.forEach((key, value) -> {
|
||||||
|
Config cfg = config.toConfig();
|
||||||
|
ConfigValue cv = cfg.getValue(key);
|
||||||
|
if (cv.valueType() == ConfigValueType.OBJECT) {
|
||||||
|
HOCONConfigWrapper.this.data.put(key, new HOCONConfigWrapper((ConfigObject) cv));
|
||||||
|
} else {
|
||||||
|
HOCONConfigWrapper.this.data.put(key, value.unwrapped());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Map<String, Object> getSource() {
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Set<String> getKeys(boolean deep) {
|
||||||
|
return this.getValues(deep).keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Map<String, Object> getValues(boolean deep) {
|
||||||
|
return HOCONUtils.getKeysFromObject(this, deep, "").stream().collect(
|
||||||
|
LinkedHashMap::new,
|
||||||
|
(map, key) -> map.put(key, get(key)),
|
||||||
|
LinkedHashMap::putAll
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(@NotNull String path, @Nullable Object value) {
|
||||||
|
if (value instanceof Map) {
|
||||||
|
//noinspection unchecked
|
||||||
|
value = new HOCONConfigWrapper(ConfigFactory.parseMap((Map<String, ?>) value).root());
|
||||||
|
}
|
||||||
|
|
||||||
|
HOCONConfigWrapper section = HOCONUtils.getObjectOn(this, path, SEPARATOR);
|
||||||
|
String simplePath = HOCONUtils.getSimplePath(path, SEPARATOR);
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
section.data.remove(simplePath);
|
||||||
|
} else {
|
||||||
|
section.setDirect(simplePath, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只能设置当前路径下的内容
|
||||||
|
* 避免环回
|
||||||
|
*
|
||||||
|
* @param path 路径
|
||||||
|
*/
|
||||||
|
public void setDirect(@NotNull String path, @Nullable Object value) {
|
||||||
|
this.data.put(path, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(@NotNull String path) {
|
||||||
|
return this.get(path) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Object get(@NotNull String path) {
|
||||||
|
HOCONConfigWrapper section = HOCONUtils.getObjectOn(this, path, SEPARATOR);
|
||||||
|
return section.getDirect(HOCONUtils.getSimplePath(path, SEPARATOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只能获取当前路径下的内容
|
||||||
|
* 避免环回
|
||||||
|
*
|
||||||
|
* @param path 路径
|
||||||
|
*/
|
||||||
|
public Object getDirect(@NotNull String path) {
|
||||||
|
return this.data.get(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isList(@NotNull String path) {
|
||||||
|
return this.get(path) instanceof List<?>;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<?> getList(@NotNull String path) {
|
||||||
|
Object val = this.get(path);
|
||||||
|
return (val instanceof List<?>) ? (List<?>) val : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isConfigurationSection(@NotNull String path) {
|
||||||
|
return this.get(path) instanceof HOCONConfigWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ConfigurationWrapper<Map<String, Object>> getConfigurationSection(@NotNull String path) {
|
||||||
|
Object val = get(path);
|
||||||
|
return (val instanceof HOCONConfigWrapper) ? (HOCONConfigWrapper) val : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
+106
@@ -0,0 +1,106 @@
|
|||||||
|
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.core.source.impl.FileConfigProvider;
|
||||||
|
import cc.carm.lib.configuration.hocon.exception.HOCONGetValueException;
|
||||||
|
import cc.carm.lib.configuration.hocon.util.HOCONUtils;
|
||||||
|
import com.typesafe.config.*;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class HOCONFileConfigProvider extends FileConfigProvider<HOCONConfigWrapper> {
|
||||||
|
protected final @NotNull ConfigurationComments comments = new ConfigurationComments();
|
||||||
|
protected HOCONConfigWrapper configuration;
|
||||||
|
protected ConfigInitializer<HOCONFileConfigProvider> initializer;
|
||||||
|
|
||||||
|
public HOCONFileConfigProvider(@NotNull File file) {
|
||||||
|
super(file);
|
||||||
|
this.initializer = new ConfigInitializer<>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initializeConfig() {
|
||||||
|
try {
|
||||||
|
this.configuration = new HOCONConfigWrapper(ConfigFactory.parseFile(this.file, ConfigParseOptions.defaults()
|
||||||
|
.setSyntax(ConfigSyntax.CONF)
|
||||||
|
.setAllowMissing(false)).root());
|
||||||
|
} catch (ConfigException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull HOCONConfigWrapper getConfiguration() {
|
||||||
|
return this.configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() throws IOException {
|
||||||
|
Files.write(this.file.toPath(), HOCONUtils.renderWithComment(configuration, comments::getHeaderComment).getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onReload() throws ConfigException {
|
||||||
|
ConfigObject conf = ConfigFactory.parseFile(this.file, ConfigParseOptions.defaults()
|
||||||
|
.setSyntax(ConfigSyntax.CONF)
|
||||||
|
.setAllowMissing(false)).root();
|
||||||
|
this.configuration = new HOCONConfigWrapper(conf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConfigurationComments getComments() {
|
||||||
|
return this.comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConfigInitializer<HOCONFileConfigProvider> getInitializer() {
|
||||||
|
return this.initializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String serializeValue(@NotNull String key, @NotNull Object value) {
|
||||||
|
// 带有 key=value 的新空对象
|
||||||
|
return ConfigFactory.empty()
|
||||||
|
.withValue(key, ConfigValueFactory.fromAnyRef(value))
|
||||||
|
.root().render();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull Set<String> getKeys() {
|
||||||
|
return getKeys(null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract("null,_->!null")
|
||||||
|
public @Nullable Set<String> getKeys(@Nullable String sectionKey, boolean deep) {
|
||||||
|
if (sectionKey == null) { // 当前路径
|
||||||
|
return HOCONUtils.getKeysFromObject(this.configuration, deep, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
HOCONConfigWrapper section;
|
||||||
|
try {
|
||||||
|
// 获取目标字段所在路径
|
||||||
|
section = (HOCONConfigWrapper) this.configuration.get(sectionKey);
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
// 值和类型不匹配
|
||||||
|
throw new HOCONGetValueException(e);
|
||||||
|
}
|
||||||
|
if (section == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return HOCONUtils.getKeysFromObject(section, deep, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Object getValue(@NotNull String key) {
|
||||||
|
return this.configuration.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable List<String> getHeaderComments(@Nullable String key) {
|
||||||
|
return this.comments.getHeaderComment(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
package cc.carm.lib.configuration.hocon.exception;
|
||||||
|
|
||||||
|
public class HOCONGetValueException extends RuntimeException {
|
||||||
|
public HOCONGetValueException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public HOCONGetValueException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HOCONGetValueException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HOCONGetValueException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
package cc.carm.lib.configuration.hocon.util;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.hocon.HOCONConfigWrapper;
|
||||||
|
import cc.carm.lib.configuration.hocon.exception.HOCONGetValueException;
|
||||||
|
import com.typesafe.config.*;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class HOCONUtils {
|
||||||
|
|
||||||
|
private HOCONUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSimplePath(String path, char separator) {
|
||||||
|
int index = path.lastIndexOf(separator);
|
||||||
|
return (index == -1) ? path : path.substring(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HOCONConfigWrapper getObjectOn(@NotNull HOCONConfigWrapper parent, @NotNull String path, char separator) {
|
||||||
|
String currentPath = path;
|
||||||
|
HOCONConfigWrapper currentObject = parent;
|
||||||
|
int index;
|
||||||
|
while ((index = currentPath.indexOf(separator)) != -1) {
|
||||||
|
HOCONConfigWrapper previousObject = currentObject;
|
||||||
|
String pathName = currentPath.substring(0, index);
|
||||||
|
try {
|
||||||
|
currentObject = (HOCONConfigWrapper) previousObject.getDirect(pathName);
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
throw new HOCONGetValueException(e);
|
||||||
|
}
|
||||||
|
if (currentObject == null) {
|
||||||
|
currentObject = new HOCONConfigWrapper(ConfigFactory.empty().root());
|
||||||
|
previousObject.setDirect(pathName, currentObject);
|
||||||
|
}
|
||||||
|
currentPath = currentPath.substring(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在 Object 中获取所有键
|
||||||
|
* 思路:在第一次执行时 prefix 应该是 ""
|
||||||
|
* 后续找到了更深层的键,将会变为 "deep."
|
||||||
|
* 下一次键名就是 "deep.key"
|
||||||
|
*
|
||||||
|
* @param parent Object
|
||||||
|
* @param deep 是否更深层获取
|
||||||
|
* @param prefix 当前 Object 键名前缀
|
||||||
|
* @return Object 中的所有键
|
||||||
|
*/
|
||||||
|
public static Set<String> getKeysFromObject(HOCONConfigWrapper parent, boolean deep, String prefix) {
|
||||||
|
return parent.getSource().entrySet().stream().collect(
|
||||||
|
LinkedHashSet::new,
|
||||||
|
(set, entry) -> {
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value instanceof HOCONConfigWrapper && deep) {
|
||||||
|
set.addAll(HOCONUtils.getKeysFromObject((HOCONConfigWrapper) value, true, prefix + entry.getKey() + "."));
|
||||||
|
} else {
|
||||||
|
set.add(prefix + entry.getKey());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
LinkedHashSet::addAll
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 Object 保存为字符串
|
||||||
|
* 并使用注释器打上注释
|
||||||
|
*
|
||||||
|
* @param object Object
|
||||||
|
* @param commenter 注释器
|
||||||
|
* @return 保存的字符串
|
||||||
|
*/
|
||||||
|
public static @NotNull String renderWithComment(@NotNull HOCONConfigWrapper object, @NotNull Function<String, List<String>> commenter) {
|
||||||
|
return HOCONUtils.makeConfigWithComment(object, "", commenter).root().render(
|
||||||
|
ConfigRenderOptions.defaults()
|
||||||
|
.setJson(false)
|
||||||
|
.setOriginComments(false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull Config makeConfigWithComment(@NotNull HOCONConfigWrapper object, @NotNull String prefix, @NotNull Function<String, List<String>> commenter) {
|
||||||
|
Config config = ConfigFactory.empty();
|
||||||
|
for (Map.Entry<String, Object> entry : object.getSource().entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
String fullKey = prefix + key;
|
||||||
|
Object value = entry.getValue();
|
||||||
|
ConfigValue result;
|
||||||
|
if (value instanceof Iterable) {
|
||||||
|
result = ConfigValueFactory.fromIterable((Iterable<?>) value);
|
||||||
|
} else if (value instanceof HOCONConfigWrapper) {
|
||||||
|
result = makeConfigWithComment((HOCONConfigWrapper) value, fullKey + ".", commenter).root();
|
||||||
|
} else {
|
||||||
|
result = ConfigValueFactory.fromAnyRef(value);
|
||||||
|
}
|
||||||
|
result = result.withOrigin(
|
||||||
|
ConfigOriginFactory.newSimple()
|
||||||
|
.withComments(commenter.apply(fullKey))
|
||||||
|
);
|
||||||
|
config = config.withValue(key, result);
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package online.flowerinsnow.test.easyconfiguration;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.EasyConfiguration;
|
||||||
|
//import cc.carm.lib.configuration.demo.DatabaseConfiguration;
|
||||||
|
//import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration;
|
||||||
|
import cc.carm.lib.configuration.hocon.HOCONFileConfigProvider;
|
||||||
|
import online.flowerinsnow.test.easyconfiguration.config.Config;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class HOCONTest {
|
||||||
|
@Test
|
||||||
|
public void onTest() {
|
||||||
|
HOCONFileConfigProvider provider = EasyConfiguration.from(new File("target/hocon.conf"));
|
||||||
|
provider.initialize(Config.class);
|
||||||
|
// provider.initialize(DatabaseConfiguration.class);
|
||||||
|
try {
|
||||||
|
provider.reload();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
package online.flowerinsnow.test.easyconfiguration.config;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.core.ConfigurationRoot;
|
||||||
|
import cc.carm.lib.configuration.core.annotation.HeaderComment;
|
||||||
|
import cc.carm.lib.configuration.core.value.type.ConfiguredList;
|
||||||
|
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
|
||||||
|
|
||||||
|
public class Config extends ConfigurationRoot {
|
||||||
|
@HeaderComment("测试字段 int")
|
||||||
|
public static final ConfiguredValue<Integer> TEST_INT = ConfiguredValue.of(Integer.class, 15);
|
||||||
|
|
||||||
|
@HeaderComment("测试字段 List<String>")
|
||||||
|
public static final ConfiguredList<String> TEST_LIST_STRING = ConfiguredList.of(String.class, "li", "li", "li1");
|
||||||
|
|
||||||
|
@HeaderComment("测试对象")
|
||||||
|
public static class TestObject extends ConfigurationRoot {
|
||||||
|
@HeaderComment("测试字段 Boolean")
|
||||||
|
public static final ConfiguredValue<Boolean> TEST_BOOLEAN = ConfiguredValue.of(Boolean.class, true);
|
||||||
|
@HeaderComment("inner")
|
||||||
|
public static class InnerObject extends ConfigurationRoot {
|
||||||
|
@HeaderComment("测试字段")
|
||||||
|
public static final ConfiguredValue<Boolean> TEST_BOOLEAN_1 = ConfiguredValue.of(Boolean.class, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-4
@@ -5,13 +5,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>easyconfiguration-parent</artifactId>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<version>3.3.0</version>
|
<version>3.8.1</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
|
||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
</properties>
|
</properties>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
<version>2.10</version>
|
<version>2.10.1</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import java.io.IOException;
|
|||||||
|
|
||||||
public class EasyConfiguration {
|
public class EasyConfiguration {
|
||||||
|
|
||||||
|
private EasyConfiguration() {
|
||||||
|
}
|
||||||
|
|
||||||
public static JSONConfigProvider from(File file, String source) {
|
public static JSONConfigProvider from(File file, String source) {
|
||||||
JSONConfigProvider provider = new JSONConfigProvider(file);
|
JSONConfigProvider provider = new JSONConfigProvider(file);
|
||||||
try {
|
try {
|
||||||
|
|||||||
+3
-3
@@ -5,13 +5,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>easyconfiguration-parent</artifactId>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<version>3.3.0</version>
|
<version>3.8.1</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
|
||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,7 @@ package cc.carm.lib.configuration;
|
|||||||
|
|
||||||
public class EasyConfiguration {
|
public class EasyConfiguration {
|
||||||
|
|
||||||
|
private EasyConfiguration() {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
CREATE TABLE IF NOT EXISTS conf
|
CREATE TABLE IF NOT EXISTS conf
|
||||||
(
|
(
|
||||||
`namespace` VARCHAR(255) NOT NULL, # 命名空间
|
`namespace` VARCHAR(255) NOT NULL, # 命名空间
|
||||||
`section` VARCHAR(255) NOT NULL, # 配置路径 (ConfigPath)
|
`path` VARCHAR(255) NOT NULL, # 配置路径 (ConfigPath)
|
||||||
`type` VARCHAR(255) NOT NULL, # 数据类型 (Integer/Byte/List/Map/...)
|
`type` TINYINT UNSIGNED NOT NULL DEFAULT 0, # 数据类型 (Integer/Byte/List/Map/...)
|
||||||
`value` MEDIUMTEXT, # 配置项的值 (可能为JSON格式)
|
`value` MEDIUMTEXT, # 配置项的值 (可能为JSON格式)
|
||||||
`inline_comments` TINYTEXT, # 行内注释
|
`inline_comments` TEXT, # 行内注释
|
||||||
`header_comments` TEXT, # 顶部注释
|
`header_comments` MEDIUMTEXT, # 顶部注释
|
||||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, # 创建时间
|
||||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
PRIMARY KEY (`namespace`, `section`)
|
PRIMARY KEY (`namespace`, `path`)
|
||||||
) ENGINE = InnoDB
|
) ENGINE = InnoDB
|
||||||
DEFAULT CHARSET = utf8mb4;
|
DEFAULT CHARSET = utf8mb4;
|
||||||
|
|
||||||
|
|||||||
+11
-5
@@ -5,13 +5,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>easyconfiguration-parent</artifactId>
|
||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<version>3.3.0</version>
|
<version>3.8.1</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
|
||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
</properties>
|
</properties>
|
||||||
@@ -28,17 +28,23 @@
|
|||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>cc.carm.lib</groupId>
|
||||||
|
<artifactId>yamlcommentwriter</artifactId>
|
||||||
|
<version>1.0.1</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.parent.groupId}</groupId>
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
<artifactId>easyconfiguration-demo</artifactId>
|
<artifactId>easyconfiguration-demo</artifactId>
|
||||||
<version>${project.parent.version}</version>
|
<version>${project.parent.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bspfsystems</groupId>
|
<groupId>org.bspfsystems</groupId>
|
||||||
<artifactId>yamlconfiguration</artifactId>
|
<artifactId>yamlconfiguration</artifactId>
|
||||||
<version>1.3.0</version>
|
<version>2.0.0</version>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import java.io.IOException;
|
|||||||
|
|
||||||
public class EasyConfiguration {
|
public class EasyConfiguration {
|
||||||
|
|
||||||
|
private EasyConfiguration() {
|
||||||
|
}
|
||||||
|
|
||||||
public static YAMLConfigProvider from(File file, String source) {
|
public static YAMLConfigProvider from(File file, String source) {
|
||||||
YAMLConfigProvider provider = new YAMLConfigProvider(file);
|
YAMLConfigProvider provider = new YAMLConfigProvider(file);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
package cc.carm.lib.configuration.yaml;
|
|
||||||
|
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationComments;
|
|
||||||
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.BufferedWriter;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.StringJoiner;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.IntStream;
|
|
||||||
|
|
||||||
import static cc.carm.lib.configuration.yaml.YAMLConfigProvider.SEPARATOR;
|
|
||||||
|
|
||||||
@SuppressWarnings("SpellCheckingInspection")
|
|
||||||
public class YAMLComments extends ConfigurationComments {
|
|
||||||
|
|
||||||
public @Nullable String buildHeaderComments(@Nullable String path, @NotNull String indents) {
|
|
||||||
List<String> comments = getHeaderComment(path);
|
|
||||||
if (comments == null || comments.size() == 0) return null;
|
|
||||||
|
|
||||||
StringJoiner joiner = new StringJoiner("\n");
|
|
||||||
for (String comment : comments) {
|
|
||||||
if (comment.length() == 0) joiner.add(" ");
|
|
||||||
else joiner.add(indents + "# " + comment);
|
|
||||||
}
|
|
||||||
return joiner + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从一个文件读取配置并写入注释到某个写入器中。
|
|
||||||
* 该方法的部分源代码借鉴自 tchristofferson/ConfigUpdater 项目。
|
|
||||||
*
|
|
||||||
* @param source 源配置文件
|
|
||||||
* @param writer 配置写入器
|
|
||||||
* @throws IOException 当写入发生错误时抛出
|
|
||||||
*/
|
|
||||||
public void writeComments(@NotNull YamlConfiguration source, @NotNull BufferedWriter writer) throws IOException {
|
|
||||||
FileConfiguration temp = new YamlConfiguration(); // 该对象用于临时记录配置内容
|
|
||||||
|
|
||||||
String configHeader = buildHeaderComments(null, "");
|
|
||||||
if (configHeader != null) writer.write(configHeader);
|
|
||||||
|
|
||||||
for (String fullKey : source.getKeys(true)) {
|
|
||||||
Object currentValue = source.get(fullKey);
|
|
||||||
|
|
||||||
String indents = getIndents(fullKey);
|
|
||||||
String headerComments = buildHeaderComments(fullKey, indents);
|
|
||||||
String inlineComment = getInlineComment(fullKey);
|
|
||||||
|
|
||||||
if (headerComments != null) writer.write(headerComments);
|
|
||||||
|
|
||||||
String[] splitFullKey = fullKey.split("[" + SEPARATOR + "]");
|
|
||||||
String trailingKey = splitFullKey[splitFullKey.length - 1];
|
|
||||||
|
|
||||||
if (currentValue instanceof ConfigurationSection) {
|
|
||||||
ConfigurationSection section = (ConfigurationSection) currentValue;
|
|
||||||
writer.write(indents + trailingKey + ":");
|
|
||||||
if (inlineComment != null && inlineComment.length() > 0) {
|
|
||||||
writer.write(" # " + inlineComment);
|
|
||||||
}
|
|
||||||
if (!section.getKeys(false).isEmpty()) {
|
|
||||||
writer.write("\n");
|
|
||||||
} else {
|
|
||||||
writer.write(" {}\n");
|
|
||||||
if (indents.length() == 0) writer.write("\n");
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
temp.set(trailingKey, currentValue);
|
|
||||||
String yaml = temp.saveToString();
|
|
||||||
temp.set(trailingKey, null);
|
|
||||||
|
|
||||||
yaml = yaml.substring(0, yaml.length() - 1);
|
|
||||||
|
|
||||||
if (inlineComment != null && inlineComment.length() > 0) {
|
|
||||||
if (yaml.contains("\n")) {
|
|
||||||
// section为多行内容,需要 InlineComment 加在首行末尾
|
|
||||||
String[] splitLine = yaml.split("\n", 2);
|
|
||||||
yaml = splitLine[0] + " # " + inlineComment + "\n" + splitLine[1];
|
|
||||||
} else {
|
|
||||||
// 其他情况下就直接加载后面就好。
|
|
||||||
yaml += " # " + inlineComment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.write(indents + yaml.replace("\n", "\n" + indents) + "\n");
|
|
||||||
if (indents.length() == 0) writer.write("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 得到一个键的缩进。
|
|
||||||
* 该方法的源代码来自 tchristofferson/ConfigUpdater 项目。
|
|
||||||
*
|
|
||||||
* @param key 键
|
|
||||||
* @return 该键的缩进文本
|
|
||||||
*/
|
|
||||||
protected static String getIndents(String key) {
|
|
||||||
String[] splitKey = key.split("[" + YAMLConfigProvider.SEPARATOR + "]");
|
|
||||||
return IntStream.range(1, splitKey.length).mapToObj(i -> " ").collect(Collectors.joining());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -3,22 +3,21 @@ package cc.carm.lib.configuration.yaml;
|
|||||||
import cc.carm.lib.configuration.core.ConfigInitializer;
|
import cc.carm.lib.configuration.core.ConfigInitializer;
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationComments;
|
import cc.carm.lib.configuration.core.source.ConfigurationComments;
|
||||||
import cc.carm.lib.configuration.core.source.impl.FileConfigProvider;
|
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.bspfsystems.yamlconfiguration.file.YamlConfiguration;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.StringWriter;
|
import java.util.List;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.util.Set;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> {
|
public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> implements CommentedYAML {
|
||||||
|
|
||||||
protected static final char SEPARATOR = '.';
|
protected final @NotNull ConfigurationComments comments = new ConfigurationComments();
|
||||||
|
|
||||||
protected final @NotNull YAMLComments comments = new YAMLComments();
|
|
||||||
protected YamlConfiguration configuration;
|
protected YamlConfiguration configuration;
|
||||||
protected ConfigInitializer<YAMLConfigProvider> initializer;
|
protected ConfigInitializer<YAMLConfigProvider> initializer;
|
||||||
|
|
||||||
@@ -42,27 +41,18 @@ public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable ConfigurationComments getComments() {
|
public @NotNull ConfigurationComments getComments() {
|
||||||
return this.comments;
|
return this.comments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("SpellCheckingInspection")
|
|
||||||
public void save() throws Exception {
|
public void save() throws Exception {
|
||||||
configuration.save(getFile());
|
try {
|
||||||
|
CommentedYAMLWriter.writeWithComments(this, this.file);
|
||||||
// tchristofferson/ConfigUpdater start
|
} catch (Exception ex) {
|
||||||
StringWriter writer = new StringWriter();
|
configuration.save(file);
|
||||||
this.comments.writeComments(configuration, new BufferedWriter(writer));
|
throw ex;
|
||||||
String value = writer.toString(); // config contents
|
|
||||||
|
|
||||||
Path toUpdatePath = getFile().toPath();
|
|
||||||
if (!value.equals(new String(Files.readAllBytes(toUpdatePath), StandardCharsets.UTF_8))) {
|
|
||||||
// if updated contents are not the same as current file contents, update
|
|
||||||
Files.write(toUpdatePath, value.getBytes(StandardCharsets.UTF_8));
|
|
||||||
}
|
}
|
||||||
// tchristofferson/ConfigUpdater end
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -70,4 +60,31 @@ public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> {
|
|||||||
return this.initializer;
|
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<String> 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<String> getHeaderComments(@Nullable String key) {
|
||||||
|
return comments.getHeaderComment(key);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package cc.carm.lib.configuration.yaml;
|
package cc.carm.lib.configuration.yaml;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
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.core.value.impl.CachedConfigValue;
|
||||||
import cc.carm.lib.configuration.yaml.builder.YAMLConfigBuilder;
|
import cc.carm.lib.configuration.yaml.builder.YAMLConfigBuilder;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class YAMLValue<T> extends CachedConfigValue<T> {
|
public abstract class YAMLValue<T> extends CachedConfigValue<T> {
|
||||||
|
|
||||||
@@ -14,10 +12,8 @@ public abstract class YAMLValue<T> extends CachedConfigValue<T> {
|
|||||||
return new YAMLConfigBuilder();
|
return new YAMLConfigBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public YAMLValue(@Nullable YAMLConfigProvider provider, @Nullable String configPath,
|
public YAMLValue(@NotNull ValueManifest<T> manifest) {
|
||||||
@Nullable List<String> headerComments, @Nullable String inlineComments,
|
super(manifest);
|
||||||
@Nullable T defaultValue) {
|
|
||||||
super(provider, configPath, headerComments, inlineComments, defaultValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public YAMLConfigProvider getYAMLProvider() {
|
public YAMLConfigProvider getYAMLProvider() {
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ public class SerializableBuilder<T extends ConfigurationSerializable>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ConfiguredSerializable<T> build() {
|
public @NotNull ConfiguredSerializable<T> build() {
|
||||||
return new ConfiguredSerializable<>(this.provider, this.path, this.headerComments, this.inlineComment, this.valueClass, this.defaultValue);
|
return new ConfiguredSerializable<>(buildManifest(), this.valueClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+7
-11
@@ -1,14 +1,11 @@
|
|||||||
package cc.carm.lib.configuration.yaml.value;
|
package cc.carm.lib.configuration.yaml.value;
|
||||||
|
|
||||||
import cc.carm.lib.configuration.yaml.YAMLConfigProvider;
|
import cc.carm.lib.configuration.core.value.ValueManifest;
|
||||||
import cc.carm.lib.configuration.yaml.YAMLValue;
|
import cc.carm.lib.configuration.yaml.YAMLValue;
|
||||||
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable;
|
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class ConfiguredSerializable<T extends ConfigurationSerializable> extends YAMLValue<T> {
|
public class ConfiguredSerializable<T extends ConfigurationSerializable> extends YAMLValue<T> {
|
||||||
|
|
||||||
public static <V extends ConfigurationSerializable> ConfiguredSerializable<V> of(@NotNull Class<V> valueClass) {
|
public static <V extends ConfigurationSerializable> ConfiguredSerializable<V> of(@NotNull Class<V> valueClass) {
|
||||||
@@ -22,25 +19,24 @@ public class ConfiguredSerializable<T extends ConfigurationSerializable> extends
|
|||||||
|
|
||||||
protected final @NotNull Class<T> valueClass;
|
protected final @NotNull Class<T> valueClass;
|
||||||
|
|
||||||
public ConfiguredSerializable(@Nullable YAMLConfigProvider provider, @Nullable String configPath,
|
public ConfiguredSerializable(@NotNull ValueManifest<T> manifest, @NotNull Class<T> valueClass) {
|
||||||
@Nullable List<String> headerComments, @Nullable String inlineComments,
|
super(manifest);
|
||||||
@NotNull Class<T> valueClass, @Nullable T defaultValue) {
|
|
||||||
super(provider, configPath, headerComments, inlineComments, defaultValue);
|
|
||||||
this.valueClass = valueClass;
|
this.valueClass = valueClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable T get() {
|
public @Nullable T get() {
|
||||||
if (isExpired()) { // 已过时的数据,需要重新解析一次。
|
if (!isExpired()) return getCachedOrDefault();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 若未出现错误,则直接更新缓存并返回。
|
// 若未出现错误,则直接更新缓存并返回。
|
||||||
return updateCache(getYAMLConfig().getSerializable(getConfigPath(), valueClass, getDefaultValue()));
|
return updateCache(getYAMLConfig().getSerializable(getConfigPath(), valueClass, getDefaultValue()));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 出现了解析错误,提示并返回默认值。
|
// 出现了解析错误,提示并返回默认值。
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return useDefault();
|
return getDefaultValue();
|
||||||
}
|
}
|
||||||
} else return Optional.ofNullable(getCachedValue()).orElse(defaultValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import config.source.ModelConfiguration;
|
|||||||
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerialization;
|
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerialization;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public class DemoConfigTest {
|
public class DemoConfigTest {
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@@ -17,10 +19,11 @@ public class DemoConfigTest {
|
|||||||
ConfigurationSerialization.registerClass(AnyModel.class);
|
ConfigurationSerialization.registerClass(AnyModel.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final YAMLConfigProvider provider = EasyConfiguration.from("target/config.yml", "config.yml");
|
protected final YAMLConfigProvider provider = EasyConfiguration.from("target/config.yml", "test/test2/config.yml");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onTest() {
|
public void onTest() {
|
||||||
|
|
||||||
ConfigurationTest.testDemo(this.provider);
|
ConfigurationTest.testDemo(this.provider);
|
||||||
ConfigurationTest.testInner(this.provider);
|
ConfigurationTest.testInner(this.provider);
|
||||||
|
|
||||||
@@ -40,6 +43,10 @@ public class DemoConfigTest {
|
|||||||
AbstractModel anyModel = ModelConfiguration.ANY_MODEL.get();
|
AbstractModel anyModel = ModelConfiguration.ANY_MODEL.get();
|
||||||
if (anyModel != null) System.out.println(anyModel.getName());
|
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("----------------------------------------------------");
|
System.out.println("----------------------------------------------------");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,17 @@ package config.source;
|
|||||||
|
|
||||||
import cc.carm.lib.configuration.core.ConfigurationRoot;
|
import cc.carm.lib.configuration.core.ConfigurationRoot;
|
||||||
import cc.carm.lib.configuration.core.annotation.ConfigPath;
|
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.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.demo.tests.model.AbstractModel;
|
import cc.carm.lib.configuration.demo.tests.model.AbstractModel;
|
||||||
import cc.carm.lib.configuration.yaml.value.ConfiguredSerializable;
|
import cc.carm.lib.configuration.yaml.value.ConfiguredSerializable;
|
||||||
import config.model.AnyModel;
|
import config.model.AnyModel;
|
||||||
import config.model.SomeModel;
|
import config.model.SomeModel;
|
||||||
|
|
||||||
|
@HeaderComment("以下内容用于测试序列化")
|
||||||
@ConfigPath("model-test")
|
@ConfigPath("model-test")
|
||||||
public class ModelConfiguration extends ConfigurationRoot {
|
public class ModelConfiguration extends ConfigurationRoot {
|
||||||
|
|
||||||
@@ -19,4 +24,20 @@ public class ModelConfiguration extends ConfigurationRoot {
|
|||||||
AnyModel.class, AnyModel.random()
|
AnyModel.class, AnyModel.random()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public static final ConfiguredList<AnyModel> MODELS = ConfiguredList.builderOf(AnyModel.class)
|
||||||
|
.fromMap()
|
||||||
|
.parseValue(AnyModel::deserialize).serializeValue(AnyModel::serialize)
|
||||||
|
.defaults(AnyModel.random(), AnyModel.random(), AnyModel.random())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public static final ConfiguredSectionMap<String, AnyModel> 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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# Test Header
|
|
||||||
version: 1.0
|
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
version: 1.0
|
||||||
|
test-save: false
|
||||||
@@ -5,9 +5,9 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<java.version>1.8</java.version>
|
<project.jdk.version>1.8</project.jdk.version>
|
||||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
|
||||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||||
</properties>
|
</properties>
|
||||||
@@ -15,13 +15,14 @@
|
|||||||
<groupId>cc.carm.lib</groupId>
|
<groupId>cc.carm.lib</groupId>
|
||||||
<artifactId>easyconfiguration-parent</artifactId>
|
<artifactId>easyconfiguration-parent</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<version>3.3.0</version>
|
<version>3.8.1</version>
|
||||||
<modules>
|
<modules>
|
||||||
<module>core</module>
|
<module>core</module>
|
||||||
|
<module>demo</module>
|
||||||
<module>impl/yaml</module>
|
<module>impl/yaml</module>
|
||||||
<module>impl/json</module>
|
<module>impl/json</module>
|
||||||
<module>impl/sql</module>
|
<module>impl/sql</module>
|
||||||
<module>demo</module>
|
<module>impl/hocon</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<name>EasyConfiguration</name>
|
<name>EasyConfiguration</name>
|
||||||
@@ -109,7 +110,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains</groupId>
|
<groupId>org.jetbrains</groupId>
|
||||||
<artifactId>annotations</artifactId>
|
<artifactId>annotations</artifactId>
|
||||||
<version>23.0.0</version>
|
<version>24.1.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<version>2.22.2</version>
|
<version>3.2.3</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<useSystemClassLoader>false</useSystemClassLoader>
|
<useSystemClassLoader>false</useSystemClassLoader>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -130,7 +131,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
<version>3.0.1</version>
|
<version>3.1.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>sign-artifacts</id>
|
<id>sign-artifacts</id>
|
||||||
@@ -150,7 +151,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-release-plugin</artifactId>
|
<artifactId>maven-release-plugin</artifactId>
|
||||||
<version>2.5.3</version>
|
<version>3.0.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<autoVersionSubmodules>true</autoVersionSubmodules>
|
<autoVersionSubmodules>true</autoVersionSubmodules>
|
||||||
<useReleaseProfile>false</useReleaseProfile>
|
<useReleaseProfile>false</useReleaseProfile>
|
||||||
@@ -166,7 +167,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-javadoc-plugin</artifactId>
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
<version>3.4.1</version>
|
<version>3.6.3</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<classifier>javadoc</classifier>
|
<classifier>javadoc</classifier>
|
||||||
<detectJavaApiLink>false</detectJavaApiLink>
|
<detectJavaApiLink>false</detectJavaApiLink>
|
||||||
@@ -193,10 +194,10 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.10.1</version>
|
<version>3.12.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>${java.version}</source>
|
<source>${project.jdk.version}</source>
|
||||||
<target>${java.version}</target>
|
<target>${project.jdk.version}</target>
|
||||||
<encoding>UTF-8</encoding>
|
<encoding>UTF-8</encoding>
|
||||||
<compilerArgument>-parameters</compilerArgument>
|
<compilerArgument>-parameters</compilerArgument>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -211,7 +212,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-source-plugin</artifactId>
|
<artifactId>maven-source-plugin</artifactId>
|
||||||
<version>3.2.1</version>
|
<version>3.3.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
@@ -225,7 +226,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>3.4.1</version>
|
<version>3.5.1</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
|
|||||||
Reference in New Issue
Block a user