1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-04 10:38:19 +08:00

feat(json): Implement json sources

This commit is contained in:
2025-02-12 04:25:29 +08:00
parent c68d2371ee
commit 05ff61a9d9
44 changed files with 656 additions and 558 deletions
@@ -55,13 +55,13 @@ public class ValueAdapter<TYPE>
@Override
public Object serialize(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type, @NotNull TYPE value) throws Exception {
if (serializer == null) throw new UnsupportedOperationException("Serializer is not supported");
return serializer.serialize(provider, type, value);
return serializer.serialize(holder, type, value);
}
@Override
public TYPE parse(@NotNull ConfigurationHolder<?> holder, @NotNull ValueType<? super TYPE> type, @NotNull Object value) throws Exception {
if (deserializer == null) throw new UnsupportedOperationException("Deserializer is not supported");
return deserializer.parse(provider, type, value);
return deserializer.parse(holder, type, value);
}
@Override
@@ -101,7 +101,7 @@ public class ValueAdapterRegistry {
@Contract("_,_,null -> null")
public <T> T deserialize(@NotNull ConfigurationHolder<?> holder, @NotNull Class<T> type, @Nullable Object source) throws Exception {
return deserialize(provider, ValueType.of(type), source);
return deserialize(holder, ValueType.of(type), source);
}
@Contract("_,_,null -> null")
@@ -110,7 +110,7 @@ public class ValueAdapterRegistry {
if (type.isInstance(source)) return type.cast(source); // Not required to deserialize
ValueAdapter<T> adapter = adapterOf(type);
if (adapter == null) throw new RuntimeException("No adapter for type " + type);
return adapter.parse(provider, type, source);
return adapter.parse(holder, type, source);
}
@Contract("_,null -> null")
@@ -119,7 +119,7 @@ public class ValueAdapterRegistry {
ValueType<T> type = ValueType.of(value);
ValueAdapter<T> adapter = adapterOf(type);
if (adapter == null) return value; // No adapters, try to return the original value
return adapter.serialize(provider, type, value);
return adapter.serialize(holder, type, value);
}
@@ -3,7 +3,6 @@ package cc.carm.lib.configuration.adapter;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Objects;
@@ -12,12 +11,45 @@ import java.util.Objects;
*/
public abstract class ValueType<T> {
public static final ValueType<String> STRING = ofPrimitiveType(String.class);
public static final ValueType<Integer> INTEGER = ofPrimitiveType(Integer.class);
public static final ValueType<Integer> INTEGER_TYPE = ofPrimitiveType(int.class);
public static final ValueType<Long> LONG = ofPrimitiveType(Long.class);
public static final ValueType<Long> LONG_TYPE = ofPrimitiveType(long.class);
public static final ValueType<Double> DOUBLE = ofPrimitiveType(Double.class);
public static final ValueType<Double> DOUBLE_TYPE = ofPrimitiveType(double.class);
public static final ValueType<Float> FLOAT = ofPrimitiveType(Float.class);
public static final ValueType<Float> FLOAT_TYPE = ofPrimitiveType(float.class);
public static final ValueType<Boolean> BOOLEAN = ofPrimitiveType(Boolean.class);
public static final ValueType<Boolean> BOOLEAN_TYPE = ofPrimitiveType(boolean.class);
public static final ValueType<Byte> BYTE = ofPrimitiveType(Byte.class);
public static final ValueType<Byte> BYTE_TYPE = ofPrimitiveType(byte.class);
public static final ValueType<Short> SHORT = ofPrimitiveType(Short.class);
public static final ValueType<Short> SHORT_TYPE = ofPrimitiveType(short.class);
public static final ValueType<Character> CHAR = ofPrimitiveType(Character.class);
public static final ValueType<Character> CHAR_TYPE = ofPrimitiveType(char.class);
public static final ValueType<?>[] PRIMITIVE_TYPES = {
STRING, INTEGER, LONG, DOUBLE, FLOAT, BOOLEAN, BYTE, SHORT, CHAR,
INTEGER_TYPE, LONG_TYPE, DOUBLE_TYPE, FLOAT_TYPE, BOOLEAN_TYPE, BYTE_TYPE, SHORT_TYPE, CHAR_TYPE
};
@SuppressWarnings("unchecked")
public static <T> ValueType<T> of(@NotNull T value) {
return of((Class<T>) value.getClass());
}
@SuppressWarnings("unchecked")
public static <T> ValueType<T> of(final Type type) {
if (type == null) throw new NullPointerException("Type cannot be null");
if (type instanceof Class<?>) { // Try handle primitive types
Class<?> clazz = (Class<?>) type;
for (ValueType<?> valueType : PRIMITIVE_TYPES) {
if (valueType.getRawType() == clazz) {
return (ValueType<T>) valueType;
}
}
}
return new ValueType<T>(type) {
};
}
@@ -54,6 +86,11 @@ public abstract class ValueType<T> {
return of(parameterizedType);
}
private static <T> ValueType<T> ofPrimitiveType(Class<T> clazz) {
return new ValueType<T>(clazz) {
};
}
private final Type type;
protected ValueType() {
@@ -139,6 +176,9 @@ public abstract class ValueType<T> {
if (obj instanceof ValueType) {
return Objects.equals(type, ((ValueType<?>) obj).type);
}
if (obj instanceof Type) {
return Objects.equals(type, obj);
}
return false;
}
@@ -2,16 +2,16 @@ package cc.carm.lib.configuration.adapter.strandard;
import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.section.ConfigurationSection;
import cc.carm.lib.configuration.source.section.ConfigureSection;
public interface StandardAdapters {
ValueAdapter<ConfigurationSection> SECTION_ADAPTER = new ValueAdapter<>(
ValueType.of(ConfigurationSection.class),
ValueAdapter<ConfigureSection> SECTION_ADAPTER = new ValueAdapter<>(
ValueType.of(ConfigureSection.class),
(provider, type, value) -> value,
(provider, type, value) -> {
if (value instanceof ConfigurationSection) {
return (ConfigurationSection) value;
if (value instanceof ConfigureSection) {
return (ConfigureSection) value;
} else throw new IllegalArgumentException("Value is not a ConfigurationSection");
}
);
@@ -5,7 +5,7 @@ import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigurationSection;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.ConfigValue;
import org.jetbrains.annotations.NotNull;
@@ -21,39 +21,39 @@ public abstract class AbstractSectionBuilder<
protected final @NotNull ValueType<PARAM> paramType;
protected @NotNull ValueHandler<ConfigurationSection, PARAM> parser;
protected @NotNull ValueHandler<PARAM, ? extends Map<Object, Object>> serializer;
protected @NotNull ValueHandler<ConfigureSection, PARAM> parser;
protected @NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer;
public AbstractSectionBuilder(@NotNull ValueType<TYPE> type, @NotNull ValueType<PARAM> paramType,
@NotNull ValueHandler<ConfigurationSection, PARAM> parser,
@NotNull ValueHandler<PARAM, ? extends Map<Object, Object>> serializer) {
@NotNull ValueHandler<ConfigureSection, PARAM> parser,
@NotNull ValueHandler<PARAM, ? extends Map<String, Object>> serializer) {
super(type);
this.paramType = paramType;
this.parser = parser;
this.serializer = serializer;
}
public @NotNull SELF parse(DataFunction<ConfigurationSection, PARAM> valueParser) {
public @NotNull SELF parse(DataFunction<ConfigureSection, PARAM> valueParser) {
return parse((p, section) -> valueParser.handle(section));
}
public @NotNull SELF parse(ValueHandler<ConfigurationSection, PARAM> valueParser) {
public @NotNull SELF parse(ValueHandler<ConfigureSection, PARAM> valueParser) {
this.parser = valueParser;
return self();
}
public @NotNull SELF serialize(DataFunction<PARAM, ? extends Map<Object, Object>> serializer) {
public @NotNull SELF serialize(DataFunction<PARAM, ? extends Map<String, Object>> serializer) {
return serialize((p, value) -> serializer.handle(value));
}
public @NotNull SELF serialize(ValueHandler<PARAM, ? extends Map<Object, Object>> serializer) {
public @NotNull SELF serialize(ValueHandler<PARAM, ? extends Map<String, Object>> serializer) {
this.serializer = serializer;
return self();
}
public @NotNull SELF serialize(Consumer<Map<Object, Object>> serializer) {
public @NotNull SELF serialize(Consumer<Map<String, Object>> serializer) {
return serialize((p, value) -> {
Map<Object, Object> map = new LinkedHashMap<>();
Map<String, Object> map = new LinkedHashMap<>();
serializer.accept(map);
return map;
});
@@ -62,12 +62,12 @@ public abstract class AbstractSectionBuilder<
protected ValueAdapter<PARAM> buildAdapter() {
return new ValueAdapter<>(this.paramType)
.parser((p, type, data) -> {
ConfigurationSection section = p.deserialize(ConfigurationSection.class, data);
ConfigureSection section = p.deserialize(ConfigureSection.class, data);
if (section == null) return null;
return this.parser.handle(p, section);
})
.serializer((p, type, data) -> {
Map<Object, Object> map = this.serializer.handle(p, data);
Map<String, Object> map = this.serializer.handle(p, data);
return map == null || map.isEmpty() ? null : map;
});
}
@@ -49,13 +49,13 @@ public abstract class AbstractSourceBuilder<
protected ValueAdapter<PARAM> buildAdapter() {
return new ValueAdapter<>(this.paramType)
.parser((p, type, data) -> {
SOURCE source = p.deserialize(this.sourceType, data);
return this.valueParser.handle(p, source);
.parser((holder, type, data) -> {
SOURCE source = holder.deserialize(this.sourceType, data);
return this.valueParser.handle(holder, source);
})
.serializer((p, type, data) -> {
SOURCE source = this.valueSerializer.handle(p, data);
return p.serialize(source);
.serializer((holder, type, data) -> {
SOURCE source = this.valueSerializer.handle(holder, data);
return holder.serialize(source);
});
}
@@ -23,7 +23,7 @@ public class ConfigListBuilder<V> {
}
public @NotNull SourceListBuilder<String, V> fromString() {
return from(String.class);
return new SourceListBuilder<>(ValueType.STRING, type, ValueHandler.required(), ValueHandler.stringValue(), ArrayList::new);
}
public @NotNull SectionListBuilder<V> fromSection() {
@@ -3,7 +3,7 @@ package cc.carm.lib.configuration.builder.list;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.impl.AbstractSectionBuilder;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigurationSection;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.standard.ConfiguredList;
import org.jetbrains.annotations.NotNull;
@@ -15,8 +15,8 @@ public class SectionListBuilder<V> extends AbstractSectionBuilder<List<V>, V, Co
protected @NotNull Supplier<? extends List<V>> constructor;
public SectionListBuilder(@NotNull ValueType<V> paramType,
@NotNull ValueHandler<ConfigurationSection, V> parser,
@NotNull ValueHandler<V, ? extends Map<Object, Object>> serializer,
@NotNull ValueHandler<ConfigureSection, V> parser,
@NotNull ValueHandler<V, ? extends Map<String, Object>> serializer,
@NotNull Supplier<? extends List<V>> constructor) {
super(new ValueType<List<V>>() {
}, paramType, parser, serializer);
@@ -2,7 +2,7 @@ package cc.carm.lib.configuration.builder.value;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigurationSection;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
@@ -30,7 +30,7 @@ public class ConfigValueBuilder<V> {
}
public @NotNull SourceValueBuilder<String, V> fromString() {
return from(String.class);
return from(ValueType.STRING, ValueHandler.required(), ValueHandler.stringValue());
}
public @NotNull SectionValueBuilder<V> fromSection() {
@@ -38,8 +38,8 @@ public class ConfigValueBuilder<V> {
}
public @NotNull SectionValueBuilder<V> fromSection(
@NotNull ValueHandler<ConfigurationSection, V> valueParser,
@NotNull ValueHandler<V, ? extends Map<Object, Object>> valueSerializer
@NotNull ValueHandler<ConfigureSection, V> valueParser,
@NotNull ValueHandler<V, ? extends Map<String, Object>> valueSerializer
) {
return new SectionValueBuilder<>(this.type, valueParser, valueSerializer);
}
@@ -3,7 +3,7 @@ package cc.carm.lib.configuration.builder.value;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.builder.impl.AbstractSectionBuilder;
import cc.carm.lib.configuration.function.ValueHandler;
import cc.carm.lib.configuration.source.section.ConfigurationSection;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
import org.jetbrains.annotations.NotNull;
@@ -12,8 +12,8 @@ import java.util.Map;
public class SectionValueBuilder<V> extends AbstractSectionBuilder<V, V, ConfiguredValue<V>, SectionValueBuilder<V>> {
public SectionValueBuilder(@NotNull ValueType<V> type,
@NotNull ValueHandler<ConfigurationSection, V> parser,
@NotNull ValueHandler<V, ? extends Map<Object, Object>> serializer) {
@NotNull ValueHandler<ConfigureSection, V> parser,
@NotNull ValueHandler<V, ? extends Map<String, Object>> serializer) {
super(type, type, parser, serializer);
}
@@ -50,6 +50,11 @@ public interface ValueHandler<T, R> {
return ConfigurationHolder::serialize;
}
@Contract(pure = true)
static <T> @NotNull ValueHandler<T, String> stringValue() {
return (provider, input) -> String.valueOf(input);
}
@Contract(pure = true)
static <T> @NotNull ValueHandler<Object, T> fromObject(ValueType<T> type) {
return (provider, input) -> provider.deserialize(type, input);
@@ -1,46 +1,38 @@
package cc.carm.lib.configuration.source;
import cc.carm.lib.configuration.adapter.ValueAdapterRegistry;
import cc.carm.lib.configuration.adapter.*;
import cc.carm.lib.configuration.adapter.strandard.PrimitiveAdapter;
import cc.carm.lib.configuration.adapter.strandard.StandardAdapters;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.loader.PathGenerator;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.source.option.ConfigurationOption;
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
import cc.carm.lib.configuration.source.section.ConfigurationSource;
import cc.carm.lib.configuration.source.section.ConfigureSource;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.Annotation;
import java.util.function.Consumer;
import java.util.function.Function;
public abstract class ConfigurationFactory<SOURCE extends ConfigurationSource<SOURCE, ?>, PROVIDER extends ConfigurationHolder<SOURCE>, SELF> {
protected Function<PROVIDER, ConfigurationInitializer> loaderFunction = PROVIDER -> new ConfigurationInitializer();
protected Consumer<ConfigurationInitializer> loaderConsumer = loader -> {
};
public abstract class ConfigurationFactory<
SOURCE extends ConfigureSource<?, ?, SOURCE>,
HOLDER extends ConfigurationHolder<SOURCE>,
SELF
> {
protected ValueAdapterRegistry adapters = new ValueAdapterRegistry();
protected ConfigurationOptionHolder options = new ConfigurationOptionHolder();
protected ConfigurationInitializer initializer = new ConfigurationInitializer();
public ConfigurationFactory() {
this.adapters.register(PrimitiveAdapter.ADAPTERS);
this.adapters.register(StandardAdapters.SECTION_ADAPTER);
}
public abstract SELF self();
public SELF loader(Function<PROVIDER, ConfigurationInitializer> loaderFunction) {
this.loaderFunction = loaderFunction;
return self();
}
public SELF loader(ConfigurationInitializer loader) {
return loader(PROVIDER -> loader);
}
public SELF loader(Consumer<ConfigurationInitializer> loaderConsumer) {
this.loaderConsumer = this.loaderConsumer.andThen(loaderConsumer);
return self();
}
public SELF pathGenerator(PathGenerator generator) {
return loader(loader -> {
loader.pathGenerator(generator);
});
}
public SELF adapters(ValueAdapterRegistry adapters) {
this.adapters = adapters;
@@ -52,18 +44,37 @@ public abstract class ConfigurationFactory<SOURCE extends ConfigurationSource<SO
return self();
}
// public SELF adapter(@NotNull ValueAdapter<?, ?> adapter) {
// return adapter(a -> a.register(adapter));
// }
//
// public <T> SELF adapter(Class<T> clazz, @NotNull ValueAdapter<?, T> adapter) {
// return adapter(a -> a.register(clazz, adapter));
// }
//
// public <B, V> SELF adapter(Class<B> baseClass, Class<V> valueClass,
// ConfigDataFunction<B, V> parser, ConfigDataFunction<V, B> serializer) {
// return adapter(a -> a.register(baseClass, valueClass, parser, serializer));
// }
public <T> SELF adapter(@NotNull ValueAdapter<T> adapter) {
return adapter(a -> a.register(adapter));
}
public <T> SELF adapter(@NotNull ValueType<T> type, @NotNull ValueSerializer<T> serializer) {
return adapter(a -> a.register(type, serializer));
}
public <T> SELF adapter(@NotNull ValueType<T> type, @NotNull ValueParser<T> parser) {
return adapter(a -> a.register(type, parser));
}
public <FROM, TO> SELF adapter(@NotNull Class<FROM> from, @NotNull Class<TO> to,
@NotNull DataFunction<FROM, TO> parser,
@NotNull DataFunction<TO, FROM> serializer) {
return adapter(a -> a.register(from, to, parser, serializer));
}
public <FROM, TO> SELF adapter(@NotNull ValueType<FROM> from, @NotNull ValueType<TO> to,
@NotNull DataFunction<FROM, TO> parser,
@NotNull DataFunction<TO, FROM> serializer) {
return adapter(a -> a.register(from, to, parser, serializer));
}
public <T> SELF adapter(@NotNull ValueType<T> type, @NotNull ValueSerializer<T> serializer, @NotNull ValueParser<T> parser) {
return adapter(a -> a.register(type, serializer, parser));
}
public <T> SELF adapter(@NotNull Class<T> type, @NotNull ValueSerializer<T> serializer, @NotNull ValueParser<T> parser) {
return adapter(ValueType.of(type), serializer, parser);
}
public SELF options(ConfigurationOptionHolder options) {
this.options = options;
@@ -79,6 +90,29 @@ public abstract class ConfigurationFactory<SOURCE extends ConfigurationSource<SO
return option(o -> o.set(option, value));
}
public abstract @NotNull PROVIDER build();
public SELF initializer(ConfigurationInitializer initializer) {
this.initializer = initializer;
return self();
}
public SELF initializer(Consumer<ConfigurationInitializer> initializerConsumer) {
initializerConsumer.accept(initializer);
return self();
}
public SELF pathGenerator(PathGenerator generator) {
return initializer(loader -> {
loader.pathGenerator(generator);
});
}
public <M, A extends Annotation> SELF metaAnnotation(@NotNull Class<A> annotation,
@NotNull ConfigurationMetadata<M> metadata,
@NotNull Function<A, M> extractor) {
return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor));
}
public abstract @NotNull HOLDER build();
}
@@ -6,16 +6,15 @@ import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
import cc.carm.lib.configuration.source.section.ConfigurationSource;
import cc.carm.lib.configuration.source.section.ConfigureSource;
import cc.carm.lib.configuration.value.ValueManifest;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Objects;
public class ConfigurationHolder<S extends ConfigurationSource<S, ?>> {
public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, SOURCE>> {
protected final @NotNull ValueAdapterRegistry adapters;
protected final @NotNull ConfigurationOptionHolder options;
@@ -23,8 +22,6 @@ public class ConfigurationHolder<S extends ConfigurationSource<S, ?>> {
protected final @NotNull ConfigurationInitializer initializer;
protected @Nullable S source;
public ConfigurationHolder(@NotNull ValueAdapterRegistry adapters,
@NotNull ConfigurationOptionHolder options,
@NotNull Map<String, ConfigurationMetaHolder> metadata,
@@ -35,16 +32,14 @@ public class ConfigurationHolder<S extends ConfigurationSource<S, ?>> {
this.metadata = metadata;
}
public @NotNull S source() {
return Objects.requireNonNull(source, "Source is not initialized");
}
public abstract @NotNull SOURCE config();
public void reload() throws Exception {
source().reload();
config().reload();
}
public void save() throws Exception {
source().save();
config().save();
}
public ConfigurationOptionHolder options() {
@@ -83,7 +78,7 @@ public class ConfigurationHolder<S extends ConfigurationSource<S, ?>> {
return adapters().serialize(this, value);
}
public void load(Class<? extends Configuration> configClass) {
public void initialize(Class<? extends Configuration> configClass) {
try {
initializer.initialize(this, configClass);
} catch (Exception e) {
@@ -91,7 +86,7 @@ public class ConfigurationHolder<S extends ConfigurationSource<S, ?>> {
}
}
public void load(@NotNull Configuration config) {
public void initialize(@NotNull Configuration config) {
try {
initializer.initialize(this, config);
} catch (Exception e) {
@@ -99,7 +94,7 @@ public class ConfigurationHolder<S extends ConfigurationSource<S, ?>> {
}
}
public void load(@NotNull ValueManifest<?> value) {
public void initialize(@NotNull ValueManifest<?> value) {
value.holder(this);
}
@@ -70,49 +70,49 @@ public class ConfigurationInitializer {
public <T, A extends Annotation> void registerAnnotation(@NotNull Class<A> annotation,
@NotNull ConfigurationMetadata<T> metadata,
@NotNull Function<A, T> extractor) {
appendFieldInitializer((provider, path, field) -> {
appendFieldInitializer((holder, path, field) -> {
A data = field.getAnnotation(annotation);
if (data == null) return;
provider.metadata(path).setIfAbsent(metadata, extractor.apply(data));
holder.metadata(path).setIfAbsent(metadata, extractor.apply(data));
});
appendClassInitializer((provider, path, clazz) -> {
appendClassInitializer((holder, path, clazz) -> {
A data = clazz.getAnnotation(annotation);
if (data == null) return;
provider.metadata(path).setIfAbsent(metadata, extractor.apply(data));
holder.metadata(path).setIfAbsent(metadata, extractor.apply(data));
});
}
public @Nullable String getFieldPath(ConfigurationHolder<?> holder, @Nullable String parentPath, @NotNull Field field) {
return pathGenerator.getFieldPath(provider, parentPath, field);
return pathGenerator.getFieldPath(holder, parentPath, field);
}
public @Nullable String getClassPath(ConfigurationHolder<?> holder, @Nullable String parentPath,
@NotNull Class<?> clazz, @Nullable Field clazzField) {
return pathGenerator.getClassPath(provider, parentPath, clazz, clazzField);
return pathGenerator.getClassPath(holder, parentPath, clazz, clazzField);
}
public void initialize(ConfigurationHolder<?> holder, @NotNull Configuration config) throws Exception {
initializeInstance(provider, config, null, null);
if (provider.options().get(StandardOptions.SET_DEFAULTS)) provider.save();
initializeInstance(holder, config, null, null);
if (holder.options().get(StandardOptions.SET_DEFAULTS)) holder.save();
}
public void initialize(ConfigurationHolder<?> holder, @NotNull Class<? extends Configuration> clazz) throws Exception {
initializeStaticClass(provider, clazz, null, null);
if (provider.options().get(StandardOptions.SET_DEFAULTS)) provider.save();
initializeStaticClass(holder, clazz, null, null);
if (holder.options().get(StandardOptions.SET_DEFAULTS)) holder.save();
}
// 针对实例类的初始化方法
protected void initializeInstance(@NotNull ConfigurationHolder<?> holder,
@NotNull Configuration root, @Nullable String parentPath, @Nullable Field configField) {
String path = getClassPath(provider, parentPath, root.getClass(), configField);
String path = getClassPath(holder, parentPath, root.getClass(), configField);
try {
this.classInitializer.whenInitialize(provider, path, root.getClass());
this.classInitializer.whenInitialize(holder, path, root.getClass());
} catch (Exception e) {
e.printStackTrace();
}
Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(provider, root, field, path));
Arrays.stream(root.getClass().getDeclaredFields()).forEach(field -> initializeField(holder, root, field, path));
}
// 针对静态类的初始化方法
@@ -121,22 +121,22 @@ public class ConfigurationInitializer {
@NotNull Class<?> clazz, @Nullable String parentPath, @Nullable Field configField) {
if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类
String path = getClassPath(provider, parentPath, clazz, configField);
String path = getClassPath(holder, parentPath, clazz, configField);
try {
this.classInitializer.whenInitialize(provider, path, (Class<? extends Configuration>) clazz);
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz);
} catch (Exception e) {
e.printStackTrace();
}
for (Field field : clazz.getDeclaredFields()) {
initializeField(provider, clazz, field, path);
initializeField(holder, clazz, field, path);
}
if (provider.options().get(StandardOptions.LOAD_SUB_CLASSES)) {
if (holder.options().get(StandardOptions.LOAD_SUB_CLASSES)) {
Class<?>[] classes = clazz.getDeclaredClasses();
for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。
initializeStaticClass(provider, classes[i], path, null);
initializeStaticClass(holder, classes[i], path, null);
}
}
}
@@ -150,20 +150,20 @@ public class ConfigurationInitializer {
if (object instanceof ConfigValue<?>) {
// 目标是 ConfigValue 实例,进行具体的初始化注入
ConfigValue<?> value = (ConfigValue<?>) object;
String path = getFieldPath(provider, parent, field);
String path = getFieldPath(holder, parent, field);
if (path == null) return;
value.initialize(provider, path);
value.initialize(holder, path);
try {
this.fieldInitializer.whenInitialize(provider, path, field);
this.fieldInitializer.whenInitialize(holder, path, field);
} catch (Exception e) {
e.printStackTrace();
}
} else if (source instanceof Configuration && object instanceof Configuration) {
// 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。
initializeInstance(provider, (Configuration) object, parent, field);
initializeInstance(holder, (Configuration) object, parent, field);
} else if (source instanceof Class<?> && object instanceof Class<?>) {
// 当且仅当 源字段与字段 均为静态类时,才对目标字段进行下一步初始化加载。
initializeStaticClass(provider, (Class<?>) object, parent, field);
initializeStaticClass(holder, (Class<?>) object, parent, field);
}
// 以上判断实现以下规范:
@@ -40,8 +40,8 @@ public class PathGenerator {
public @Nullable String getFieldPath(@NotNull ConfigurationHolder<?> holder,
@Nullable String parentPath, @NotNull Field field) {
ConfigPath path = field.getAnnotation(ConfigPath.class);
if (path == null) return link(provider, parentPath, false, field.getName()); // No annotation, use field name.
else return link(provider, parentPath, path.root(), select(path.value(), field.getName()));
if (path == null) return link(holder, parentPath, false, field.getName()); // No annotation, use field name.
else return link(holder, parentPath, path.root(), select(path.value(), field.getName()));
}
public @Nullable String getClassPath(@NotNull ConfigurationHolder<?> holder,
@@ -52,14 +52,14 @@ public class PathGenerator {
// and use filed information.
ConfigPath clazzPath = clazz.getAnnotation(ConfigPath.class);
if (clazzPath != null) return link(provider, parentPath, clazzPath.root(), clazzPath.value());
if (clazzPath != null) return link(holder, parentPath, clazzPath.root(), clazzPath.value());
if (clazzField == null) {
return link(provider, parentPath, false, clazz.getSimpleName()); // No field, use class name.
return link(holder, parentPath, false, clazz.getSimpleName()); // No field, use class name.
}
ConfigPath fieldPath = clazzField.getAnnotation(ConfigPath.class);
if (fieldPath == null) return link(provider, parentPath, false, clazzField.getName());
else return getFieldPath(provider, parentPath, clazzField);
if (fieldPath == null) return link(holder, parentPath, false, clazzField.getName());
else return getFieldPath(holder, parentPath, clazzField);
}
protected String select(String path, String defaultValue) {
@@ -70,7 +70,7 @@ public class PathGenerator {
protected @Nullable String link(@NotNull ConfigurationHolder<?> holder,
@Nullable String parent, boolean root, @Nullable String path) {
if (path == null || path.isEmpty()) return root ? null : parent;
return root || parent == null ? covertPath(path) : parent + pathSeparator(provider) + covertPath(path);
return root || parent == null ? covertPath(path) : parent + pathSeparator(holder) + covertPath(path);
}
public static boolean isBlank(String path) {
@@ -78,7 +78,7 @@ public class PathGenerator {
}
public static char pathSeparator(ConfigurationHolder<?> holder) {
return provider.options().get(StandardOptions.PATH_SEPARATOR);
return holder.options().get(StandardOptions.PATH_SEPARATOR);
}
/**
@@ -27,7 +27,7 @@ public interface StandardOptions {
* <br> if false, the values will be parsed when calling
* {@link cc.carm.lib.configuration.value.ConfigValue#get()}
* <br> if true, the values will be parsed when
* {@link ConfigurationHolder#load(Configuration)}.
* {@link ConfigurationHolder#initialize(Configuration)}.
*/
ConfigurationOption<Boolean> PRELOAD = of(false);
@@ -1,46 +0,0 @@
package cc.carm.lib.configuration.source.section;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
public abstract class ConfigurationSource<SELF extends ConfigurationSource<SELF, ORIGINAL>, ORIGINAL>
implements ConfigurationSection {
protected final @NotNull ConfigurationHolder<? extends SELF> holder;
protected long lastUpdateMillis;
protected ConfigurationSource(@NotNull ConfigurationHolder<? extends SELF> holder,
long lastUpdateMillis) {
this.holder = holder;
this.lastUpdateMillis = lastUpdateMillis;
}
public @NotNull ConfigurationHolder<? extends SELF> holder() {
return holder;
}
public void reload() throws Exception {
onReload(); // 调用重写的Reload方法
this.lastUpdateMillis = System.currentTimeMillis();
}
protected abstract SELF self();
/**
* @return Original configuration object
*/
public abstract @NotNull ORIGINAL original();
public abstract void save() throws Exception;
protected abstract void onReload() throws Exception;
public long getLastUpdateMillis() {
return this.lastUpdateMillis;
}
public boolean isExpired(long parsedTime) {
return getLastUpdateMillis() > parsedTime;
}
}
@@ -1,6 +1,7 @@
package cc.carm.lib.configuration.source.section;
import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.source.option.StandardOptions;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -8,7 +9,13 @@ import org.jetbrains.annotations.Unmodifiable;
import java.util.*;
public interface ConfigurationSection {
public interface ConfigureSection {
@NotNull ConfigureSource<?, ?, ?> source();
default char separator() {
return source().holder().options().get(StandardOptions.PATH_SEPARATOR);
}
@NotNull
default Set<String> getKeys(boolean deep) {
@@ -33,7 +40,7 @@ public interface ConfigurationSection {
boolean isSection(@NotNull String path);
@Nullable
ConfigurationSection getSection(@NotNull String path);
ConfigureSection getSection(@NotNull String path);
@Nullable Object get(@NotNull String path);
@@ -0,0 +1,97 @@
package cc.carm.lib.configuration.source.section;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
public abstract class ConfigureSource<
SECTION extends ConfigureSection, ORIGINAL,
SELF extends ConfigureSource<SECTION, ORIGINAL, SELF>>
implements ConfigureSection {
protected final @NotNull ConfigurationHolder<? extends SELF> holder;
protected long lastUpdateMillis;
protected ConfigureSource(@NotNull ConfigurationHolder<? extends SELF> holder, long lastUpdateMillis) {
this.holder = holder;
this.lastUpdateMillis = lastUpdateMillis;
}
public @NotNull ConfigurationHolder<? extends SELF> holder() {
return holder;
}
public void reload() throws Exception {
onReload(); // 调用重写的Reload方法
this.lastUpdateMillis = System.currentTimeMillis();
}
protected abstract SELF self();
/**
* @return Original configuration object
*/
public abstract @NotNull ORIGINAL original();
/**
* @return Configuration section
*/
public abstract @NotNull SECTION section();
public abstract void save() throws Exception;
protected abstract void onReload() throws Exception;
public long getLastUpdateMillis() {
return this.lastUpdateMillis;
}
public boolean isExpired(long parsedTime) {
return getLastUpdateMillis() > parsedTime;
}
@Override
public @NotNull Map<String, Object> getValues(boolean deep) {
return section().getValues(deep);
}
@Override
public void set(@NotNull String path, @Nullable Object value) {
section().set(path, value);
}
@Override
public boolean contains(@NotNull String path) {
return section().contains(path);
}
@Override
public boolean isList(@NotNull String path) {
return section().isList(path);
}
@Override
public @Nullable List<?> getList(@NotNull String path) {
return section().getList(path);
}
@Override
public boolean isSection(@NotNull String path) {
return section().isSection(path);
}
@Override
public @Nullable ConfigureSection getSection(@NotNull String path) {
return section().getSection(path);
}
@Override
public @Nullable Object get(@NotNull String path) {
return section().get(path);
}
}
@@ -3,7 +3,7 @@ package cc.carm.lib.configuration.value;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.section.ConfigurationSource;
import cc.carm.lib.configuration.source.section.ConfigureSource;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -101,8 +101,8 @@ public class ValueManifest<T> {
throw new IllegalStateException("Value does not have a provider.");
}
public @NotNull ConfigurationSource<?, ?> config() {
return holder().source();
public @NotNull ConfigureSource<?, ?, ?> config() {
return holder().config();
}
public ConfigurationMetaHolder metadata() {
@@ -4,7 +4,7 @@ import cc.carm.lib.configuration.adapter.ValueAdapter;
import cc.carm.lib.configuration.adapter.ValueParser;
import cc.carm.lib.configuration.adapter.ValueSerializer;
import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.section.ConfigurationSection;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.value.ValueManifest;
import cc.carm.lib.configuration.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull;
@@ -58,7 +58,7 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> implements
// If the value is expired, we need to update it
Map<K, V> map = createMap();
ConfigurationSection section = config().getSection(path());
ConfigureSection section = config().getSection(path());
if (section == null) return getDefaultFirst(map);
Set<String> keys = section.getKeys(false);
@@ -30,6 +30,11 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
return of(ValueType.of(type), () -> null);
}
public static <V> ConfiguredValue<V> of(@NotNull Class<V> type, @NotNull V defaults) {
return of(ValueType.of(type), () -> defaults);
}
public static <V> ConfiguredValue<V> of(@NotNull Class<V> type, @NotNull Supplier<@Nullable V> defaultSupplier) {
return of(ValueType.of(type), defaultSupplier);
}
+11 -3
View File
@@ -5,6 +5,7 @@ import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
import cc.carm.test.config.TestSource;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.time.Duration;
@@ -28,10 +29,17 @@ public class AdaptTest {
data -> Duration.between(LocalTime.now(), data)
);
ConfigurationHolder<TestSource> provider = new ConfigurationHolder<>(
new TestSource(), registry, new ConfigurationOptionHolder(),
ConfigurationHolder<TestSource> provider = new ConfigurationHolder<TestSource>(
registry, new ConfigurationOptionHolder(),
new ConcurrentHashMap<>(), new ConfigurationInitializer()
);
) {
final TestSource source = new TestSource(this, System.currentTimeMillis());
@Override
public @NotNull TestSource config() {
return source;
}
};
LocalTime v = registry.deserialize(provider, LocalTime.class, 600000L);
Object d = registry.serialize(provider, v);
+1
View File
@@ -1,3 +1,4 @@
import cc.carm.lib.configuration.source.loader.PathGenerator;
import org.junit.Test;
public class NameTest {
@@ -6,6 +6,7 @@ import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
import org.jetbrains.annotations.NotNull;
import org.junit.Test;
import java.util.concurrent.ConcurrentHashMap;
@@ -14,10 +15,17 @@ public class LoaderTest {
@Test
public void test() throws Exception {
ConfigurationHolder<TestSource> provider = new ConfigurationHolder<>(
new TestSource(), new ValueAdapterRegistry(), new ConfigurationOptionHolder(),
ConfigurationHolder<TestSource> provider = new ConfigurationHolder<TestSource>(
new ValueAdapterRegistry(), new ConfigurationOptionHolder(),
new ConcurrentHashMap<>(), new ConfigurationInitializer()
);
) {
final TestSource source = new TestSource(this, System.currentTimeMillis());
@Override
public @NotNull TestSource config() {
return source;
}
};
ConfigurationInitializer loader = new ConfigurationInitializer();
loader.initialize(provider, ROOT.class);
@@ -0,0 +1,57 @@
package cc.carm.test.config;
import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.source.section.ConfigureSource;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class TestSection implements ConfigureSection {
@Override
public @NotNull ConfigureSource<?, ?, ?> source() {
return null;
}
@Override
public @NotNull Map<String, Object> getValues(boolean deep) {
return Collections.emptyMap();
}
@Override
public void set(@NotNull String path, @Nullable Object value) {
}
@Override
public boolean contains(@NotNull String path) {
return false;
}
@Override
public boolean isList(@NotNull String path) {
return false;
}
@Override
public @Nullable List<?> getList(@NotNull String path) {
return Collections.emptyList();
}
@Override
public boolean isSection(@NotNull String path) {
return false;
}
@Override
public @Nullable ConfigureSection getSection(@NotNull String path) {
return null;
}
@Override
public @Nullable Object get(@NotNull String path) {
return null;
}
}
@@ -1,18 +1,16 @@
package cc.carm.test.config;
import cc.carm.lib.configuration.source.section.ConfigurationSection;
import cc.carm.lib.configuration.source.section.ConfigurationSource;
import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class TestSource extends ConfigurationSource<TestSource, Map<String, String>> {
public class TestSource extends ConfigureSource<TestSection, Map<String, String>, TestSource> {
public TestSource() {
super(System.currentTimeMillis());
public TestSource(@NotNull ConfigurationHolder<? extends TestSource> holder, long lastUpdateMillis) {
super(holder, lastUpdateMillis);
}
@Override
@@ -36,47 +34,12 @@ public class TestSource extends ConfigurationSource<TestSource, Map<String, Stri
}
@Override
public @NotNull Set<String> getKeys(boolean deep) {
public @NotNull TestSection section() {
return null;
}
@Override
public @NotNull Map<String, Object> getValues(boolean deep) {
return null;
}
@Override
public @Nullable Object get(@NotNull String path) {
return null;
}
@Override
public void set(@NotNull String path, @Nullable Object value) {
}
@Override
public boolean contains(@NotNull String path) {
return false;
}
@Override
public boolean isList(@NotNull String path) {
return false;
}
@Override
public @Nullable List<?> getList(@NotNull String path) {
return null;
}
@Override
public boolean isSection(@NotNull String path) {
return false;
}
@Override
public @Nullable ConfigurationSection getSection(@NotNull String path) {
public @NotNull ConfigureSource<?, ?, ?> source() {
return null;
}
}