mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-04 18:48:20 +08:00
初始版本完成
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
package cc.carm.lib.configuration.core;
|
||||
|
||||
import cc.carm.lib.configuration.core.annotation.ConfigComment;
|
||||
import cc.carm.lib.configuration.core.annotation.ConfigPath;
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.core.value.ConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ConfigInitializer {
|
||||
|
||||
public static void initialize(ConfigurationProvider source, Class<? extends ConfigurationRoot> rootClazz) {
|
||||
initialize(source, rootClazz, true);
|
||||
}
|
||||
|
||||
public static void initialize(ConfigurationProvider provider, Class<? extends ConfigurationRoot> rootClazz, boolean saveDefault) {
|
||||
ConfigPath sectionAnnotation = rootClazz.getAnnotation(ConfigPath.class);
|
||||
|
||||
String rootSection = null;
|
||||
if (sectionAnnotation != null && sectionAnnotation.value().length() > 1) {
|
||||
rootSection = sectionAnnotation.value();
|
||||
}
|
||||
|
||||
for (Class<?> innerClass : rootClazz.getDeclaredClasses()) {
|
||||
initSection(provider, rootSection, innerClass, saveDefault);
|
||||
}
|
||||
|
||||
for (Field field : rootClazz.getFields()) {
|
||||
initValue(provider, rootSection, rootClazz, field, saveDefault);
|
||||
}
|
||||
|
||||
if (saveDefault) {
|
||||
try {
|
||||
provider.save();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void initSection(ConfigurationProvider provider, String parentSection, Class<?> clazz, boolean saveDefault) {
|
||||
if (!Modifier.isStatic(clazz.getModifiers()) || !Modifier.isPublic(clazz.getModifiers())) return;
|
||||
|
||||
String section = getSectionPath(clazz.getSimpleName(), parentSection, clazz.getAnnotation(ConfigPath.class));
|
||||
ConfigComment comments = clazz.getAnnotation(ConfigComment.class);
|
||||
if (comments != null && comments.value().length > 0) {
|
||||
provider.setComments(parentSection, comments.value());
|
||||
}
|
||||
|
||||
for (Field field : clazz.getFields()) initValue(provider, section, clazz, field, saveDefault);
|
||||
for (Class<?> innerClass : clazz.getDeclaredClasses()) initSection(provider, section, innerClass, saveDefault);
|
||||
|
||||
}
|
||||
|
||||
private static void initValue(ConfigurationProvider provider, String parentSection, Class<?> clazz, Field field, boolean saveDefault) {
|
||||
try {
|
||||
Object object = field.get(clazz);
|
||||
if (object instanceof ConfigValue<?>) {
|
||||
initializeValue(
|
||||
provider, (ConfigValue<?>) object,
|
||||
getSectionPath(field.getName(), parentSection, field.getAnnotation(ConfigPath.class)),
|
||||
Optional.ofNullable(field.getAnnotation(ConfigComment.class))
|
||||
.map(ConfigComment::value).orElse(new String[0]),
|
||||
saveDefault);
|
||||
}
|
||||
} catch (IllegalAccessException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void initializeValue(@NotNull ConfigurationProvider provider, @NotNull ConfigValue<?> value,
|
||||
@NotNull String path, @NotNull String[] comments, boolean saveDefault) {
|
||||
value.initialize(provider, path, comments);
|
||||
if (saveDefault && value.getDefaultValue() != null && !provider.getConfiguration().contains(path)) {
|
||||
value.setDefault();
|
||||
}
|
||||
}
|
||||
|
||||
public static String getSectionPath(@NotNull String name,
|
||||
@Nullable String parentSection,
|
||||
@Nullable ConfigPath pathAnnotation) {
|
||||
String parent = parentSection != null ? parentSection + "." : "";
|
||||
if (pathAnnotation != null && pathAnnotation.value().length() > 0) {
|
||||
return parent + pathAnnotation.value();
|
||||
} else {
|
||||
return parent + getSectionName(name);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getSectionName(String codeName) {
|
||||
return codeName.toLowerCase().replace("_", "-");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package cc.carm.lib.configuration.core;
|
||||
|
||||
public abstract class ConfigurationRoot {
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package cc.carm.lib.configuration.core.annotation;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ConfigComment {
|
||||
|
||||
@NotNull
|
||||
String[] value() default "";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package cc.carm.lib.configuration.core.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ConfigPath {
|
||||
|
||||
String value();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package cc.carm.lib.configuration.core.builder;
|
||||
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.core.value.ConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class AbstractConfigBuilder<B extends AbstractConfigBuilder<B, T>, T> {
|
||||
|
||||
|
||||
protected @Nullable ConfigurationProvider provider;
|
||||
protected @Nullable String path;
|
||||
|
||||
protected @NotNull String[] comments = new String[0];
|
||||
protected @Nullable T defaultValue;
|
||||
|
||||
protected abstract @NotNull B getThis();
|
||||
|
||||
public abstract @NotNull ConfigValue<?> build();
|
||||
|
||||
public @NotNull B from(@Nullable ConfigurationProvider provider) {
|
||||
this.provider = provider;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public @NotNull B path(@Nullable String path) {
|
||||
this.path = path;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public @NotNull B comments(@NotNull String... comments) {
|
||||
this.comments = comments;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
public @NotNull B defaults(@Nullable T defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
return getThis();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package cc.carm.lib.configuration.core.builder;
|
||||
|
||||
import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder;
|
||||
import cc.carm.lib.configuration.core.builder.map.ConfigMapBuilder;
|
||||
import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class ConfigBuilder {
|
||||
|
||||
public static <V> @NotNull ConfigValueBuilder<V> asValue(@NotNull Class<V> valueClass) {
|
||||
return new ConfigValueBuilder<>(valueClass);
|
||||
}
|
||||
|
||||
public static <V> @NotNull ConfigListBuilder<V> asList(@NotNull Class<V> valueClass) {
|
||||
return new ConfigListBuilder<>(valueClass);
|
||||
}
|
||||
|
||||
public static <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asMap(@NotNull Class<K> keyClass,
|
||||
@NotNull Class<V> valueClass) {
|
||||
return new ConfigMapBuilder<>(LinkedHashMap::new, keyClass, valueClass);
|
||||
}
|
||||
|
||||
public static <K, V> @NotNull ConfigMapBuilder<HashMap<K, V>, K, V> asHashMap(@NotNull Class<K> keyClass,
|
||||
@NotNull Class<V> valueClass) {
|
||||
return asMap(keyClass, valueClass).supplier(HashMap::new);
|
||||
}
|
||||
|
||||
public static <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> asLinkedMap(@NotNull Class<K> keyClass,
|
||||
@NotNull Class<V> valueClass) {
|
||||
return asMap(keyClass, valueClass);
|
||||
}
|
||||
|
||||
public static <K extends Comparable<K>, V> @NotNull ConfigMapBuilder<TreeMap<K, V>, K, V> asTreeMap(@NotNull Class<K> keyClass,
|
||||
@NotNull Class<V> valueClass) {
|
||||
return asMap(keyClass, valueClass).supplier(TreeMap::new);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package cc.carm.lib.configuration.core.builder.list;
|
||||
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ConfigListBuilder<V> {
|
||||
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
|
||||
public ConfigListBuilder(@NotNull Class<V> valueClass) {
|
||||
this.valueClass = valueClass;
|
||||
}
|
||||
|
||||
public @NotNull <S> SourceListBuilder<S, V> from(@NotNull Class<S> sourceClass,
|
||||
@NotNull ConfigDataFunction<Object, S> sourceParser,
|
||||
@NotNull ConfigDataFunction<S, V> valueParser,
|
||||
@NotNull ConfigDataFunction<V, S> valueSerializer,
|
||||
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
|
||||
return new SourceListBuilder<>(sourceClass, sourceParser, this.valueClass, valueParser, valueSerializer, sourceSerializer);
|
||||
}
|
||||
|
||||
|
||||
public @NotNull <S> SourceListBuilder<S, V> from(Class<S> sourceClass) {
|
||||
return from(sourceClass,
|
||||
ConfigDataFunction.required(), ConfigDataFunction.required(),
|
||||
ConfigDataFunction.required(), ConfigDataFunction.required()
|
||||
);
|
||||
}
|
||||
|
||||
public @NotNull SourceListBuilder<Object, V> fromObject() {
|
||||
return from(
|
||||
Object.class, ConfigDataFunction.identity(),
|
||||
ConfigDataFunction.castObject(valueClass),
|
||||
ConfigDataFunction.identity(), ConfigDataFunction.toObject()
|
||||
);
|
||||
}
|
||||
|
||||
public @NotNull SourceListBuilder<String, V> fromString() {
|
||||
return from(
|
||||
String.class, ConfigDataFunction.castToString(),
|
||||
ConfigDataFunction.castFromString(this.valueClass),
|
||||
ConfigDataFunction.castToString(), ConfigDataFunction.toObject()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package cc.carm.lib.configuration.core.builder.list;
|
||||
|
||||
import cc.carm.lib.configuration.core.builder.AbstractConfigBuilder;
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.core.value.type.ConfiguredList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SourceListBuilder<S, V>
|
||||
extends AbstractConfigBuilder<SourceListBuilder<S, V>, List<V>> {
|
||||
|
||||
protected final @NotNull Class<S> sourceClass;
|
||||
protected @NotNull ConfigDataFunction<Object, S> sourceParser;
|
||||
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
protected @NotNull ConfigDataFunction<S, V> valueParser;
|
||||
|
||||
protected @NotNull ConfigDataFunction<V, S> valueSerializer;
|
||||
protected @NotNull ConfigDataFunction<S, Object> sourceSerializer;
|
||||
|
||||
public SourceListBuilder(@NotNull Class<S> sourceClass, @NotNull ConfigDataFunction<Object, S> sourceParser,
|
||||
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<S, V> valueParser,
|
||||
@NotNull ConfigDataFunction<V, S> valueSerializer,
|
||||
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
|
||||
this.sourceClass = sourceClass;
|
||||
this.sourceParser = sourceParser;
|
||||
this.sourceSerializer = sourceSerializer;
|
||||
this.valueClass = valueClass;
|
||||
this.valueParser = valueParser;
|
||||
this.valueSerializer = valueSerializer;
|
||||
}
|
||||
|
||||
public @NotNull SourceListBuilder<S, V> parseSource(ConfigDataFunction<Object, S> sourceParser) {
|
||||
this.sourceParser = sourceParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceListBuilder<S, V> parseValue(ConfigDataFunction<S, V> valueParser) {
|
||||
this.valueParser = valueParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceListBuilder<S, V> serializeValue(ConfigDataFunction<V, S> serializer) {
|
||||
this.valueSerializer = serializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceListBuilder<S, V> serializeSource(ConfigDataFunction<S, Object> serializer) {
|
||||
this.sourceSerializer = serializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull SourceListBuilder<S, V> getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfiguredList<V> build() {
|
||||
return new ConfiguredList<>(
|
||||
this.provider, this.path, this.comments,
|
||||
this.valueClass, this.defaultValue,
|
||||
this.sourceParser.andThen(this.valueParser),
|
||||
this.valueSerializer.andThen(sourceSerializer)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package cc.carm.lib.configuration.core.builder.map;
|
||||
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ConfigMapBuilder<M extends Map<K, V>, K, V> {
|
||||
|
||||
protected final @NotNull Supplier<@NotNull M> supplier;
|
||||
|
||||
protected final @NotNull Class<K> keyClass;
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
|
||||
public ConfigMapBuilder(@NotNull Supplier<@NotNull M> supplier, @NotNull Class<K> keyClass, @NotNull Class<V> valueClass) {
|
||||
this.supplier = supplier;
|
||||
this.keyClass = keyClass;
|
||||
this.valueClass = valueClass;
|
||||
}
|
||||
|
||||
public <MAP extends Map<K, V>> ConfigMapBuilder<MAP, K, V> supplier(@NotNull Supplier<MAP> supplier) {
|
||||
return new ConfigMapBuilder<>(supplier, keyClass, valueClass);
|
||||
}
|
||||
|
||||
public <S> SourceMapBuilder<M, S, K, V> from(@NotNull Class<S> sourceClass,
|
||||
@NotNull ConfigDataFunction<S, V> valueParser,
|
||||
@NotNull ConfigDataFunction<V, S> valueSerializer) {
|
||||
return new SourceMapBuilder<>(supplier,
|
||||
keyClass, ConfigDataFunction.castFromString(this.keyClass), // #String -> key
|
||||
sourceClass, ConfigDataFunction.castObject(sourceClass), // #Object -> source
|
||||
valueClass, valueParser, // source -> value
|
||||
ConfigDataFunction.castToString(), // key -> #String
|
||||
valueSerializer/*value -> source*/,
|
||||
ConfigDataFunction.toObject()/* source -> #Object */
|
||||
);
|
||||
}
|
||||
|
||||
public <S> SourceMapBuilder<M, S, K, V> from(@NotNull Class<S> sourceClass) {
|
||||
return from(sourceClass, ConfigDataFunction.required(), ConfigDataFunction.required());
|
||||
}
|
||||
|
||||
public SourceMapBuilder<M, String, K, V> fromString(@NotNull ConfigDataFunction<String, V> valueParser) {
|
||||
return from(String.class, valueParser, ConfigDataFunction.castToString());
|
||||
}
|
||||
|
||||
public SourceMapBuilder<M, String, K, V> fromString() {
|
||||
return fromString(ConfigDataFunction.castFromString(this.valueClass));
|
||||
}
|
||||
|
||||
public SourceMapBuilder<M, Object, K, V> fromObject(@NotNull ConfigDataFunction<Object, V> valueParser) {
|
||||
return from(Object.class, valueParser, ConfigDataFunction.toObject());
|
||||
}
|
||||
|
||||
public SourceMapBuilder<M, Object, K, V> fromObject() {
|
||||
return fromObject(ConfigDataFunction.required());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package cc.carm.lib.configuration.core.builder.map;
|
||||
|
||||
import cc.carm.lib.configuration.core.builder.AbstractConfigBuilder;
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.core.value.type.ConfiguredMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SourceMapBuilder<M extends Map<K, V>, S, K, V>
|
||||
extends AbstractConfigBuilder<SourceMapBuilder<M, S, K, V>, M> {
|
||||
|
||||
protected final @NotNull Supplier<@NotNull M> supplier;
|
||||
|
||||
protected final @NotNull Class<K> keyClass;
|
||||
protected @NotNull ConfigDataFunction<String, K> keyParser;
|
||||
|
||||
protected final @NotNull Class<S> sourceClass;
|
||||
protected @NotNull ConfigDataFunction<Object, S> sourceParser;
|
||||
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
protected @NotNull ConfigDataFunction<S, V> valueParser;
|
||||
|
||||
protected @NotNull ConfigDataFunction<K, String> keySerializer;
|
||||
protected @NotNull ConfigDataFunction<V, S> valueSerializer;
|
||||
protected @NotNull ConfigDataFunction<S, Object> sourceSerializer;
|
||||
|
||||
public SourceMapBuilder(@NotNull Supplier<@NotNull M> supplier,
|
||||
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
|
||||
@NotNull Class<S> sourceClass, @NotNull ConfigDataFunction<Object, S> sourceParser,
|
||||
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<S, V> valueParser,
|
||||
@NotNull ConfigDataFunction<K, String> keySerializer,
|
||||
@NotNull ConfigDataFunction<V, S> valueSerializer,
|
||||
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
|
||||
this.supplier = supplier;
|
||||
this.keyClass = keyClass;
|
||||
this.keyParser = keyParser;
|
||||
this.valueClass = valueClass;
|
||||
this.valueParser = valueParser;
|
||||
this.sourceClass = sourceClass;
|
||||
this.sourceParser = sourceParser;
|
||||
this.keySerializer = keySerializer;
|
||||
this.valueSerializer = valueSerializer;
|
||||
this.sourceSerializer = sourceSerializer;
|
||||
}
|
||||
|
||||
public <MAP extends Map<K, V>> SourceMapBuilder<MAP, S, K, V> supplier(@NotNull Supplier<MAP> supplier) {
|
||||
return new SourceMapBuilder<>(supplier,
|
||||
keyClass, keyParser, sourceClass, sourceParser, valueClass, valueParser,
|
||||
keySerializer, valueSerializer, sourceSerializer
|
||||
);
|
||||
}
|
||||
|
||||
public @NotNull SourceMapBuilder<M, S, K, V> parseKey(@NotNull ConfigDataFunction<String, K> parser) {
|
||||
this.keyParser = parser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceMapBuilder<M, S, K, V> parseSource(@NotNull ConfigDataFunction<Object, S> parser) {
|
||||
this.sourceParser = parser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceMapBuilder<M, S, K, V> parseValue(@NotNull ConfigDataFunction<S, V> parser) {
|
||||
this.valueParser = parser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceMapBuilder<M, S, K, V> serializeKey(@NotNull ConfigDataFunction<K, String> serializer) {
|
||||
this.keySerializer = serializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceMapBuilder<M, S, K, V> serializeValue(@NotNull ConfigDataFunction<V, S> serializer) {
|
||||
this.valueSerializer = serializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceMapBuilder<M, S, K, V> serializeSource(@NotNull ConfigDataFunction<S, Object> serializer) {
|
||||
this.sourceSerializer = serializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull SourceMapBuilder<M, S, K, V> getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfiguredMap<K, V> build() {
|
||||
return new ConfiguredMap<>(
|
||||
this.provider, this.path, this.comments,
|
||||
this.defaultValue, this.supplier,
|
||||
this.keyClass, this.keyParser,
|
||||
this.valueClass, this.sourceParser.andThen(this.valueParser),
|
||||
this.keySerializer, this.valueSerializer.andThen(this.sourceSerializer)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package cc.carm.lib.configuration.core.builder.value;
|
||||
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.core.function.ConfigValueParser;
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ConfigValueBuilder<V> {
|
||||
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
|
||||
public ConfigValueBuilder(@NotNull Class<V> valueClass) {
|
||||
this.valueClass = valueClass;
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> fromSection() {
|
||||
return fromSection(ConfigValueParser.required(), ConfigDataFunction.required());
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> fromSection(@NotNull ConfigValueParser<ConfigurationWrapper, V> valueParser,
|
||||
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> valueSerializer) {
|
||||
return new SectionValueBuilder<>(this.valueClass, valueParser, valueSerializer);
|
||||
}
|
||||
|
||||
public @NotNull <S> SourceValueBuilder<S, V> from(Class<S> sourceClass) {
|
||||
return from(
|
||||
sourceClass, ConfigDataFunction.required(), ConfigValueParser.required(),
|
||||
ConfigDataFunction.required(), ConfigDataFunction.required()
|
||||
);
|
||||
}
|
||||
|
||||
public @NotNull <S> SourceValueBuilder<S, V> from(@NotNull Class<S> sourceClass,
|
||||
@NotNull ConfigDataFunction<Object, S> sourceParser,
|
||||
@NotNull ConfigValueParser<S, V> valueParser,
|
||||
@NotNull ConfigDataFunction<V, S> valueSerializer,
|
||||
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
|
||||
return new SourceValueBuilder<>(
|
||||
sourceClass, sourceParser, this.valueClass, valueParser,
|
||||
valueSerializer, sourceSerializer
|
||||
);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<Object, V> fromObject() {
|
||||
return from(
|
||||
Object.class, ConfigDataFunction.identity(),
|
||||
ConfigValueParser.castObject(valueClass),
|
||||
ConfigDataFunction.identity(), ConfigDataFunction.toObject()
|
||||
);
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<String, V> fromString() {
|
||||
return from(
|
||||
String.class, ConfigDataFunction.castToString(),
|
||||
ConfigValueParser.parseString(this.valueClass),
|
||||
ConfigDataFunction.castToString(), ConfigDataFunction.toObject()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package cc.carm.lib.configuration.core.builder.value;
|
||||
|
||||
import cc.carm.lib.configuration.core.builder.AbstractConfigBuilder;
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.core.function.ConfigValueParser;
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
|
||||
import cc.carm.lib.configuration.core.value.type.ConfiguredSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SectionValueBuilder<V>
|
||||
extends AbstractConfigBuilder<SectionValueBuilder<V>, V> {
|
||||
|
||||
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
|
||||
protected @NotNull ConfigValueParser<ConfigurationWrapper, V> parser;
|
||||
protected @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer;
|
||||
|
||||
public SectionValueBuilder(@NotNull Class<V> valueClass,
|
||||
@NotNull ConfigValueParser<ConfigurationWrapper, V> parser,
|
||||
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
|
||||
this.valueClass = valueClass;
|
||||
this.parser = parser;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected @NotNull SectionValueBuilder<V> getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> parseValue(ConfigValueParser<ConfigurationWrapper, V> valueParser) {
|
||||
this.parser = valueParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SectionValueBuilder<V> serializeValue(ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
|
||||
this.serializer = serializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfiguredSection<V> build() {
|
||||
return new ConfiguredSection<>(
|
||||
this.provider, this.path, this.comments,
|
||||
this.valueClass, this.defaultValue,
|
||||
this.parser, this.serializer
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package cc.carm.lib.configuration.core.builder.value;
|
||||
|
||||
import cc.carm.lib.configuration.core.builder.AbstractConfigBuilder;
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.core.function.ConfigValueParser;
|
||||
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class SourceValueBuilder<S, V> extends AbstractConfigBuilder<SourceValueBuilder<S, V>, V> {
|
||||
|
||||
protected final @NotNull Class<S> sourceClass;
|
||||
protected @NotNull ConfigDataFunction<Object, S> sourceParser;
|
||||
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
protected @NotNull ConfigValueParser<S, V> valueParser;
|
||||
|
||||
protected @NotNull ConfigDataFunction<S, Object> sourceSerializer;
|
||||
protected @NotNull ConfigDataFunction<V, S> valueSerializer;
|
||||
|
||||
public SourceValueBuilder(@NotNull Class<S> sourceClass, @NotNull ConfigDataFunction<Object, S> sourceParser,
|
||||
@NotNull Class<V> valueClass, @NotNull ConfigValueParser<S, V> valueParser,
|
||||
@NotNull ConfigDataFunction<V, S> valueSerializer,
|
||||
@NotNull ConfigDataFunction<S, Object> sourceSerializer) {
|
||||
this.sourceClass = sourceClass;
|
||||
this.sourceParser = sourceParser;
|
||||
this.valueClass = valueClass;
|
||||
this.valueParser = valueParser;
|
||||
this.sourceSerializer = sourceSerializer;
|
||||
this.valueSerializer = valueSerializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull SourceValueBuilder<S, V> getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<S, V> parseSource(@NotNull ConfigDataFunction<Object, S> sourceParser) {
|
||||
this.sourceParser = sourceParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<S, V> parseValue(@NotNull ConfigValueParser<S, V> valueParser) {
|
||||
this.valueParser = valueParser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<S, V> serializeValue(@NotNull ConfigDataFunction<V, S> serializer) {
|
||||
this.valueSerializer = serializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull SourceValueBuilder<S, V> serializeSource(@NotNull ConfigDataFunction<S, Object> serializer) {
|
||||
this.sourceSerializer = serializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfiguredValue<V> build() {
|
||||
return new ConfiguredValue<>(
|
||||
this.provider, this.path, this.comments,
|
||||
this.valueClass, this.defaultValue,
|
||||
this.valueParser.compose(this.sourceParser),
|
||||
this.valueSerializer.andThen(sourceSerializer)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package cc.carm.lib.configuration.core.function;
|
||||
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ConfigDataFunction<T, R> {
|
||||
|
||||
@NotNull R parse(@NotNull T data) throws Exception;
|
||||
|
||||
default <V> @NotNull ConfigDataFunction<T, V> andThen(@NotNull ConfigDataFunction<? super R, V> after) {
|
||||
Objects.requireNonNull(after);
|
||||
return ((data) -> after.parse(parse(data)));
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T> @NotNull ConfigDataFunction<T, ? super T> identity() {
|
||||
return (input) -> input;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T, V> @NotNull ConfigDataFunction<T, V> required() {
|
||||
return (input) -> {
|
||||
throw new IllegalArgumentException("Please specify the value parser.");
|
||||
};
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T> @NotNull ConfigDataFunction<T, Object> toObject() {
|
||||
return (input) -> input;
|
||||
}
|
||||
|
||||
|
||||
@Contract(pure = true)
|
||||
static <V> @NotNull ConfigDataFunction<Object, V> castObject(Class<V> valueClass) {
|
||||
return (input) -> {
|
||||
if (valueClass.isInstance(input)) return valueClass.cast(input);
|
||||
else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName());
|
||||
};
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <V> @NotNull ConfigDataFunction<String, V> castFromString(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 <T> @NotNull ConfigDataFunction<T, String> castToString() {
|
||||
return (input) -> {
|
||||
if (input instanceof String) return (String) input;
|
||||
else return input.toString();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
package cc.carm.lib.configuration.core.function;
|
||||
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ConfigValueParser<T, R> {
|
||||
|
||||
@Nullable R parse(@NotNull T data, @Nullable R defaultValue) throws Exception;
|
||||
|
||||
default <V> ConfigValueParser<T, V> andThen(@NotNull ConfigValueParser<R, V> after) {
|
||||
Objects.requireNonNull(after);
|
||||
return ((data, defaultValue) -> {
|
||||
R result = parse(data, null);
|
||||
if (result == null) return defaultValue;
|
||||
else return after.parse(result, defaultValue);
|
||||
});
|
||||
}
|
||||
|
||||
default <V> ConfigValueParser<V, R> compose(@NotNull ConfigDataFunction<? super V, ? extends T> before) {
|
||||
Objects.requireNonNull(before);
|
||||
return ((data, defaultValue) -> {
|
||||
T result = before.parse(data);
|
||||
return parse(result, defaultValue);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T> @NotNull ConfigValueParser<T, T> identity() {
|
||||
return (input, defaultValue) -> input;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T> @NotNull ConfigValueParser<T, Object> toObject() {
|
||||
return (input, defaultValue) -> input;
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <T, V> @NotNull ConfigValueParser<T, V> required() {
|
||||
return (input, defaultValue) -> {
|
||||
throw new IllegalArgumentException("Please specify the value parser.");
|
||||
};
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <V> @NotNull ConfigValueParser<Object, V> castObject(Class<V> valueClass) {
|
||||
return (input, defaultValue) -> {
|
||||
if (valueClass.isInstance(input)) return valueClass.cast(input);
|
||||
else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName());
|
||||
};
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static <V> @NotNull ConfigValueParser<String, V> parseString(Class<V> valueClass) {
|
||||
return (input, defaultValue) -> {
|
||||
if (valueClass.isInstance(input)) return valueClass.cast(input);
|
||||
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
|
||||
};
|
||||
}
|
||||
|
||||
@Contract(pure = true)
|
||||
static @NotNull ConfigValueParser<Object, String> castToString() {
|
||||
return (input, defaultValue) -> {
|
||||
if (input instanceof String) return (String) input;
|
||||
else return input.toString();
|
||||
};
|
||||
}
|
||||
|
||||
@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)
|
||||
static @NotNull ConfigValueParser<Object, Integer> intValue() {
|
||||
return (input, defaultValue) -> {
|
||||
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 ConfigValueParser<Object, Short> shortValue() {
|
||||
return (input, defaultValue) -> {
|
||||
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 ConfigValueParser<Object, Double> doubleValue() {
|
||||
return (input, defaultValue) -> {
|
||||
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 ConfigValueParser<Object, Byte> byteValue() {
|
||||
return (input, defaultValue) -> {
|
||||
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 ConfigValueParser<Object, Float> floatValue() {
|
||||
return (input, defaultValue) -> {
|
||||
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 ConfigValueParser<Object, Long> longValue() {
|
||||
return (input, defaultValue) -> {
|
||||
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 ConfigValueParser<Object, Boolean> booleanValue() {
|
||||
return (input, defaultValue) -> {
|
||||
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());
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package cc.carm.lib.configuration.core.source;
|
||||
|
||||
import cc.carm.lib.configuration.core.ConfigInitializer;
|
||||
import cc.carm.lib.configuration.core.ConfigurationRoot;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class ConfigurationProvider {
|
||||
|
||||
protected long updateTime;
|
||||
|
||||
public ConfigurationProvider() {
|
||||
this.updateTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public long getUpdateTime() {
|
||||
return updateTime;
|
||||
}
|
||||
|
||||
public boolean isExpired(long time) {
|
||||
return this.updateTime > time;
|
||||
}
|
||||
|
||||
public abstract @NotNull ConfigurationWrapper getConfiguration();
|
||||
|
||||
public abstract void reload() throws Exception;
|
||||
|
||||
public abstract void save() throws Exception;
|
||||
|
||||
public abstract void setComments(@NotNull String path, @NotNull String... comments);
|
||||
|
||||
public abstract @Nullable String[] getComments(@NotNull String path);
|
||||
|
||||
public void initialize(Class<? extends ConfigurationRoot> configClazz) {
|
||||
ConfigInitializer.initialize(this, configClazz, true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package cc.carm.lib.configuration.core.source;
|
||||
|
||||
import cc.carm.lib.configuration.core.function.ConfigValueParser;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
interface ConfigurationReader {
|
||||
|
||||
ConfigurationWrapper getWrapper();
|
||||
|
||||
default boolean isBoolean(@NotNull String path) {
|
||||
return getWrapper().isType(path, Boolean.class);
|
||||
}
|
||||
|
||||
default boolean getBoolean(@NotNull String path) {
|
||||
return getBoolean(path, false);
|
||||
}
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
|
||||
return getWrapper().get(path, def, ConfigValueParser.booleanValue());
|
||||
}
|
||||
|
||||
default @Nullable Boolean isByte(@NotNull String path) {
|
||||
return getWrapper().isType(path, Byte.class);
|
||||
}
|
||||
|
||||
|
||||
default @Nullable Byte getByte(@NotNull String path) {
|
||||
return getByte(path, (byte) 0);
|
||||
}
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
|
||||
return getWrapper().get(path, def, ConfigValueParser.byteValue());
|
||||
}
|
||||
|
||||
|
||||
default boolean isShort(@NotNull String path) {
|
||||
return getWrapper().isType(path, Short.class);
|
||||
}
|
||||
|
||||
|
||||
default @Nullable Short getShort(@NotNull String path) {
|
||||
return getShort(path, (short) 0);
|
||||
}
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
|
||||
return getWrapper().get(path, def, ConfigValueParser.shortValue());
|
||||
}
|
||||
|
||||
|
||||
default boolean isInt(@NotNull String path) {
|
||||
return getWrapper().isType(path, Integer.class);
|
||||
}
|
||||
|
||||
|
||||
default @Nullable Integer getInt(@NotNull String path) {
|
||||
return getInt(path, 0);
|
||||
}
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
|
||||
return getWrapper().get(path, def, ConfigValueParser.intValue());
|
||||
}
|
||||
|
||||
|
||||
default boolean isLong(@NotNull String path) {
|
||||
return getWrapper().isType(path, Long.class);
|
||||
}
|
||||
|
||||
|
||||
default @Nullable Long getLong(@NotNull String path) {
|
||||
return getLong(path, 0L);
|
||||
}
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
|
||||
return getWrapper().get(path, def, ConfigValueParser.longValue());
|
||||
}
|
||||
|
||||
|
||||
default boolean isFloat(@NotNull String path) {
|
||||
return getWrapper().isType(path, Float.class);
|
||||
}
|
||||
|
||||
|
||||
default @Nullable Float getFloat(@NotNull String path) {
|
||||
return getFloat(path, 0.0F);
|
||||
}
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
|
||||
return getWrapper().get(path, def, ConfigValueParser.floatValue());
|
||||
}
|
||||
|
||||
|
||||
default boolean isDouble(@NotNull String path) {
|
||||
return getWrapper().isType(path, Double.class);
|
||||
}
|
||||
|
||||
|
||||
default @Nullable Double getDouble(@NotNull String path) {
|
||||
return getDouble(path, 0.0D);
|
||||
}
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
|
||||
return getWrapper().get(path, def, ConfigValueParser.doubleValue());
|
||||
}
|
||||
|
||||
|
||||
default boolean isChar(@NotNull String path) {
|
||||
return getWrapper().isType(path, Boolean.class);
|
||||
}
|
||||
|
||||
|
||||
default @Nullable Character getChar(@NotNull String path) {
|
||||
return getChar(path, null);
|
||||
}
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable Character getChar(@NotNull String path, @Nullable Character def) {
|
||||
return getWrapper().get(path, def, Character.class);
|
||||
}
|
||||
|
||||
|
||||
default boolean isString(@NotNull String path) {
|
||||
return getWrapper().isType(path, String.class);
|
||||
}
|
||||
|
||||
default @Nullable String getString(@NotNull String path) {
|
||||
return getString(path, null);
|
||||
}
|
||||
|
||||
@Contract("_, !null -> !null")
|
||||
default @Nullable String getString(@NotNull String path, @Nullable String def) {
|
||||
return getWrapper().get(path, def, String.class);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package cc.carm.lib.configuration.core.source;
|
||||
|
||||
import cc.carm.lib.configuration.core.function.ConfigValueParser;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ConfigurationWrapper extends ConfigurationReader{
|
||||
|
||||
@Override
|
||||
default ConfigurationWrapper getWrapper() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
Set<String> getKeys(boolean deep);
|
||||
|
||||
@NotNull
|
||||
Map<String, Object> getValues(boolean deep);
|
||||
|
||||
void set(@NotNull String path, @Nullable Object value);
|
||||
|
||||
boolean contains(@NotNull String path);
|
||||
|
||||
default <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) {
|
||||
return typeClass.isInstance(get(path));
|
||||
}
|
||||
|
||||
@Nullable Object get(@NotNull String path);
|
||||
|
||||
default @Nullable <T> T get(@NotNull String path, @NotNull Class<T> clazz) {
|
||||
return get(path, null, clazz);
|
||||
}
|
||||
|
||||
default @Nullable <T> T get(@NotNull String path, @NotNull ConfigValueParser<Object, T> parser) {
|
||||
return get(path, null, parser);
|
||||
}
|
||||
|
||||
@Contract("_,!null,_->!null")
|
||||
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue, @NotNull Class<T> clazz) {
|
||||
return get(path, defaultValue, ConfigValueParser.castObject(clazz));
|
||||
}
|
||||
|
||||
@Contract("_,!null,_->!null")
|
||||
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue,
|
||||
@NotNull ConfigValueParser<Object, T> parser) {
|
||||
Object value = get(path);
|
||||
if (value != null) {
|
||||
try {
|
||||
return parser.parse(value, defaultValue);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
boolean isList(@NotNull String path);
|
||||
|
||||
@Nullable List<?> getList(@NotNull String path);
|
||||
|
||||
boolean isConfigurationSection(@NotNull String path);
|
||||
|
||||
@Nullable
|
||||
ConfigurationWrapper getConfigurationSection(@NotNull String path);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package cc.carm.lib.configuration.core.source.impl;
|
||||
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class FileConfigProvider extends ConfigurationProvider {
|
||||
|
||||
protected final @NotNull File file;
|
||||
|
||||
public FileConfigProvider(@NotNull File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public @NotNull File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public void initializeFile(@Nullable String sourcePath) throws IOException {
|
||||
if (getFile().exists()) return;
|
||||
if (!getFile().getParentFile().exists() && !getFile().getParentFile().mkdirs()) {
|
||||
throw new IOException("Failed to create directory " + file.getParentFile().getAbsolutePath());
|
||||
}
|
||||
if (!getFile().createNewFile()) {
|
||||
throw new IOException("Failed to create file " + file.getAbsolutePath());
|
||||
}
|
||||
if (sourcePath == null) return;
|
||||
try {
|
||||
saveResource(sourcePath, true);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public void saveResource(@NotNull String resourcePath, boolean replace)
|
||||
throws NullPointerException, IOException, IllegalArgumentException {
|
||||
Objects.requireNonNull(resourcePath, "ResourcePath cannot be null");
|
||||
if (resourcePath.equals("")) throw new IllegalArgumentException("ResourcePath cannot be empty");
|
||||
|
||||
resourcePath = resourcePath.replace('\\', '/');
|
||||
InputStream in = getResource(resourcePath);
|
||||
if (in == null) throw new IllegalArgumentException("The resource '" + resourcePath + "' not exists");
|
||||
|
||||
|
||||
int lastIndex = resourcePath.lastIndexOf('/');
|
||||
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 (!file.exists() || replace) {
|
||||
try {
|
||||
|
||||
OutputStream out = new FileOutputStream(file);
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
out.close();
|
||||
in.close();
|
||||
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public InputStream getResource(@NotNull String filename) {
|
||||
try {
|
||||
URL url = this.getClass().getClassLoader().getResource(filename);
|
||||
if (url == null) return null;
|
||||
URLConnection connection = url.openConnection();
|
||||
connection.setUseCaches(false);
|
||||
return connection.getInputStream();
|
||||
} catch (IOException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package cc.carm.lib.configuration.core.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class MapFactory<S extends Map<K, V>, K, V> {
|
||||
|
||||
private final S map;
|
||||
|
||||
protected MapFactory(S map) {
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
public MapFactory<S, K, V> put(K key, V value) {
|
||||
this.map.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MapFactory<S, K, V> remove(K key) {
|
||||
this.map.remove(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MapFactory<S, K, V> clear() {
|
||||
this.map.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public S build() {
|
||||
return get();
|
||||
}
|
||||
|
||||
public S get() {
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> MapFactory<HashMap<K, V>, K, V> hashMap() {
|
||||
return new MapFactory<>(new HashMap<>());
|
||||
}
|
||||
|
||||
public static <K, V> MapFactory<HashMap<K, V>, K, V> hashMap(K firstKey, V firstValue) {
|
||||
return MapFactory.<K, V>hashMap().put(firstKey, firstValue);
|
||||
}
|
||||
|
||||
public static <K, V> MapFactory<LinkedHashMap<K, V>, K, V> linkedMap() {
|
||||
return of(new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
public static <K, V> MapFactory<LinkedHashMap<K, V>, K, V> linkedMap(K firstKey, V firstValue) {
|
||||
return MapFactory.<K, V>linkedMap().put(firstKey, firstValue);
|
||||
}
|
||||
|
||||
public static <K extends Comparable<K>, V> MapFactory<TreeMap<K, V>, K, V> treeMap() {
|
||||
return of(new TreeMap<>());
|
||||
}
|
||||
|
||||
public static <K extends Comparable<K>, V> MapFactory<TreeMap<K, V>, K, V> treeMap(K firstKey, V firstValue) {
|
||||
return MapFactory.<K, V>treeMap().put(firstKey, firstValue);
|
||||
}
|
||||
|
||||
public static <M extends Map<K, V>, K, V> MapFactory<M, K, V> of(M map) {
|
||||
return new MapFactory<>(map);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cc.carm.lib.configuration.core.value;
|
||||
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public abstract class CachedConfigValue<T> extends ConfigValue<T> {
|
||||
|
||||
|
||||
protected @Nullable T cachedValue;
|
||||
protected long parsedTime = -1;
|
||||
|
||||
public CachedConfigValue(@Nullable ConfigurationProvider provider, @Nullable String sectionPath,
|
||||
@NotNull String[] comments, @Nullable T defaultValue) {
|
||||
super(provider, sectionPath, comments, defaultValue);
|
||||
}
|
||||
|
||||
protected T updateCache(T value) {
|
||||
this.parsedTime = System.currentTimeMillis();
|
||||
this.cachedValue = value;
|
||||
return getCachedValue();
|
||||
}
|
||||
|
||||
public @Nullable T getCachedValue() {
|
||||
return cachedValue;
|
||||
}
|
||||
|
||||
public boolean isExpired() {
|
||||
return this.parsedTime <= 0 || getProvider().isExpired(this.parsedTime);
|
||||
}
|
||||
|
||||
protected final T useDefault() {
|
||||
return useOrDefault(null);
|
||||
}
|
||||
|
||||
protected final T useOrDefault(@Nullable T value) {
|
||||
return updateCache(this.defaultValue == null ? value : this.defaultValue);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package cc.carm.lib.configuration.core.value;
|
||||
|
||||
import cc.carm.lib.configuration.core.builder.ConfigBuilder;
|
||||
import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder;
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class ConfigValue<T> {
|
||||
|
||||
public static <V> ConfigValueBuilder<V> builder(Class<V> valueClass) {
|
||||
return ConfigBuilder.asValue(valueClass);
|
||||
}
|
||||
|
||||
public static <V> ConfigValue<V> of(Class<V> valueClass) {
|
||||
return builder(valueClass).fromObject().build();
|
||||
}
|
||||
|
||||
protected @Nullable T defaultValue;
|
||||
|
||||
protected @Nullable ConfigurationProvider provider;
|
||||
protected @Nullable String configPath;
|
||||
protected @NotNull String[] comments;
|
||||
|
||||
public ConfigValue(@Nullable ConfigurationProvider provider, @Nullable String configPath,
|
||||
@NotNull String[] comments, @Nullable T defaultValue) {
|
||||
this.provider = provider;
|
||||
this.configPath = configPath;
|
||||
this.comments = comments;
|
||||
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public void initialize(@NotNull ConfigurationProvider provider, @NotNull String configPath,
|
||||
@NotNull String... comments) {
|
||||
if (this.provider == null) this.provider = provider;
|
||||
if (this.configPath == null) this.configPath = configPath;
|
||||
if (this.comments.length == 0) this.comments = comments;
|
||||
|
||||
this.provider.setComments(this.configPath, this.comments);
|
||||
get();
|
||||
}
|
||||
|
||||
public @Nullable T getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public void setDefaultValue(@Nullable T defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public abstract @Nullable T get();
|
||||
|
||||
public @Nullable T getOrDefault() {
|
||||
return Optional.ofNullable(get()).orElse(getDefaultValue());
|
||||
}
|
||||
|
||||
public @NotNull T getNotNull() {
|
||||
return Objects.requireNonNull(getOrDefault(), "Value(" + configPath + ") is null.");
|
||||
}
|
||||
|
||||
public @NotNull Optional<@Nullable T> getOptional() {
|
||||
return Optional.ofNullable(get());
|
||||
}
|
||||
|
||||
public abstract void set(@Nullable T value);
|
||||
|
||||
public void setDefault() {
|
||||
Optional.ofNullable(getDefaultValue()).ifPresent(this::set);
|
||||
}
|
||||
|
||||
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 String[] getComments() {
|
||||
return comments;
|
||||
}
|
||||
|
||||
public void setComments(String[] comments) {
|
||||
this.comments = comments;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package cc.carm.lib.configuration.core.value.type;
|
||||
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.core.value.CachedConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
|
||||
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
|
||||
protected final @NotNull ConfigDataFunction<Object, V> parser;
|
||||
protected final @NotNull ConfigDataFunction<V, Object> serializer;
|
||||
|
||||
public ConfiguredList(@Nullable ConfigurationProvider provider,
|
||||
@Nullable String sectionPath, @NotNull String[] comments,
|
||||
@NotNull Class<V> valueClass, @Nullable List<V> defaultValue,
|
||||
@NotNull ConfigDataFunction<Object, V> parser,
|
||||
@NotNull ConfigDataFunction<V, Object> serializer) {
|
||||
super(provider, sectionPath, comments, defaultValue);
|
||||
this.valueClass = valueClass;
|
||||
this.parser = parser;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<V> get() {
|
||||
if (isExpired()) { // 已过时的数据,需要重新解析一次。
|
||||
List<V> list = new ArrayList<>();
|
||||
|
||||
List<?> data = getConfiguration().getList(getConfigPath());
|
||||
if (data == null || data.isEmpty()) return useOrDefault(list);
|
||||
|
||||
for (Object dataVal : data) {
|
||||
if (dataVal == null) continue;
|
||||
try {
|
||||
list.add(parser.parse(dataVal));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return updateCache(list);
|
||||
} else if (getCachedValue() != null) return getCachedValue();
|
||||
else if (getDefaultValue() != null) return getDefaultValue();
|
||||
else return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(@Nullable List<V> value) {
|
||||
updateCache(value);
|
||||
if (value == null) setValue(null);
|
||||
else {
|
||||
List<Object> data = new ArrayList<>();
|
||||
for (V val : value) {
|
||||
if (val == null) continue;
|
||||
try {
|
||||
data.add(serializer.parse(val));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
setValue(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package cc.carm.lib.configuration.core.value.type;
|
||||
|
||||
import cc.carm.lib.configuration.core.builder.ConfigBuilder;
|
||||
import cc.carm.lib.configuration.core.builder.map.ConfigMapBuilder;
|
||||
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.value.CachedConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> {
|
||||
|
||||
public static <K, V> @NotNull ConfigMapBuilder<LinkedHashMap<K, V>, K, V> builder(@NotNull Class<K> keyClass,
|
||||
@NotNull Class<V> valueClass) {
|
||||
return ConfigBuilder.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, @NotNull String[] comments,
|
||||
@Nullable Map<K, V> defaultValue, @NotNull Supplier<? extends Map<K, V>> supplier,
|
||||
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
|
||||
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<Object, V> valueParser,
|
||||
@NotNull ConfigDataFunction<K, String> keySerializer,
|
||||
@NotNull ConfigDataFunction<V, Object> valueSerializer) {
|
||||
super(provider, sectionPath, comments, defaultValue);
|
||||
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
|
||||
public @NotNull Map<K, V> get() {
|
||||
if (isExpired()) { // 已过时的数据,需要重新解析一次。
|
||||
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 {
|
||||
String key = keySerializer.parse(entry.getKey());
|
||||
Object val = valueSerializer.parse(entry.getValue());
|
||||
data.put(key, val);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
setValue(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package cc.carm.lib.configuration.core.value.type;
|
||||
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
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.value.CachedConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ConfiguredSection<V> extends CachedConfigValue<V> {
|
||||
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
|
||||
protected final @NotNull ConfigValueParser<ConfigurationWrapper, V> parser;
|
||||
protected final @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer;
|
||||
|
||||
public ConfiguredSection(@Nullable ConfigurationProvider provider,
|
||||
@Nullable String sectionPath, @NotNull String[] comments,
|
||||
@NotNull Class<V> valueClass, @Nullable V defaultValue,
|
||||
@NotNull ConfigValueParser<ConfigurationWrapper, V> parser,
|
||||
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
|
||||
super(provider, sectionPath, comments, defaultValue);
|
||||
this.valueClass = valueClass;
|
||||
this.parser = parser;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
public @NotNull Class<V> getValueClass() {
|
||||
return valueClass;
|
||||
}
|
||||
|
||||
public @NotNull ConfigValueParser<ConfigurationWrapper, V> getParser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
public @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> getSerializer() {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable V get() {
|
||||
if (isExpired()) { // 已过时的数据,需要重新解析一次。
|
||||
ConfigurationWrapper section = getConfiguration().getConfigurationSection(getConfigPath());
|
||||
if (section == null) return useDefault();
|
||||
try {
|
||||
// 若未出现错误,则直接更新缓存并返回。
|
||||
return updateCache(this.parser.parse(section, this.defaultValue));
|
||||
} catch (Exception e) {
|
||||
// 出现了解析错误,提示并返回默认值。
|
||||
e.printStackTrace();
|
||||
return useDefault();
|
||||
}
|
||||
} else return Optional.ofNullable(getCachedValue()).orElse(defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(V value) {
|
||||
updateCache(value);
|
||||
if (value == null) setValue(null);
|
||||
else {
|
||||
try {
|
||||
setValue(serializer.parse(value));
|
||||
// getConfiguration().createSection(getSectionPath(), serializer.parse(value));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package cc.carm.lib.configuration.core.value.type;
|
||||
|
||||
import cc.carm.lib.configuration.core.function.ConfigDataFunction;
|
||||
import cc.carm.lib.configuration.core.function.ConfigValueParser;
|
||||
import cc.carm.lib.configuration.core.source.ConfigurationProvider;
|
||||
import cc.carm.lib.configuration.core.value.CachedConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
||||
|
||||
protected final @NotNull Class<V> valueClass;
|
||||
|
||||
protected final @NotNull ConfigValueParser<Object, V> parser;
|
||||
protected final @NotNull ConfigDataFunction<V, Object> serializer;
|
||||
|
||||
public ConfiguredValue(@Nullable ConfigurationProvider provider,
|
||||
@Nullable String sectionPath, @NotNull String[] comments,
|
||||
@NotNull Class<V> valueClass, @Nullable V defaultValue,
|
||||
@NotNull ConfigValueParser<Object, V> parser,
|
||||
@NotNull ConfigDataFunction<V, Object> serializer) {
|
||||
|
||||
super(provider, sectionPath, comments, defaultValue);
|
||||
this.valueClass = valueClass;
|
||||
this.parser = parser;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
public @NotNull Class<V> getValueClass() {
|
||||
return valueClass;
|
||||
}
|
||||
|
||||
public @NotNull ConfigValueParser<Object, V> getParser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get() {
|
||||
if (isExpired()) { // 已过时的数据,需要重新解析一次。
|
||||
Object value = getConfiguration().get(getConfigPath());
|
||||
if (value == null) return useDefault(); // 获取的值不存在,直接使用默认值。
|
||||
try {
|
||||
// 若未出现错误,则直接更新缓存并返回。
|
||||
return updateCache(this.parser.parse(value, this.defaultValue));
|
||||
} catch (Exception e) {
|
||||
// 出现了解析错误,提示并返回默认值。
|
||||
e.printStackTrace();
|
||||
return useDefault();
|
||||
}
|
||||
} else return Optional.ofNullable(getCachedValue()).orElse(defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(V value) {
|
||||
updateCache(value);
|
||||
if (value == null) setValue(null);
|
||||
else {
|
||||
try {
|
||||
setValue(serializer.parse(value));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user