mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2024-09-19 20:25:51 +00:00
feat(interface): Support interface root configurations.
This commit is contained in:
parent
60eed8a14d
commit
db8b227317
@ -14,7 +14,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* 配置文件类初始化方法
|
||||
* 用于初始化 {@link ConfigurationRoot} 中的每个 {@link ConfigValue} 对象
|
||||
* 用于初始化 {@link Configuration} 中的每个 {@link ConfigValue} 对象
|
||||
*
|
||||
* @param <T> {@link ConfigurationProvider} 配置文件的数据来源
|
||||
* @author CarmJos
|
||||
@ -30,21 +30,21 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
|
||||
/**
|
||||
* 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。
|
||||
*
|
||||
* @param clazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
|
||||
* @param clazz 配置文件类,须继承于 {@link Configuration} 。
|
||||
* @param saveDefaults 是否写入默认值(默认为 true)。
|
||||
*/
|
||||
public void initialize(@NotNull Class<? extends ConfigurationRoot> clazz, boolean saveDefaults) {
|
||||
public void initialize(@NotNull Class<? extends Configuration> clazz, boolean saveDefaults) {
|
||||
initialize(clazz, saveDefaults, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化指定类的所有 {@link ConfigValue} 对象。
|
||||
*
|
||||
* @param clazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
|
||||
* @param clazz 配置文件类,须继承于 {@link Configuration} 。
|
||||
* @param saveDefaults 是否写入默认值(默认为 true)。
|
||||
* @param loadSubClasses 是否加载内部子类(默认为 true)。
|
||||
*/
|
||||
public void initialize(@NotNull Class<? extends ConfigurationRoot> clazz,
|
||||
public void initialize(@NotNull Class<? extends Configuration> clazz,
|
||||
boolean saveDefaults, boolean loadSubClasses) {
|
||||
initializeStaticClass(
|
||||
clazz, null, null,
|
||||
@ -61,21 +61,21 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link ConfigurationRoot} 对象。
|
||||
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。
|
||||
*
|
||||
* @param config 配置文件实例类,须实现 {@link ConfigurationRoot} 。
|
||||
* @param config 配置文件实例类,须实现 {@link Configuration} 。
|
||||
*/
|
||||
public void initialize(@NotNull ConfigurationRoot config) {
|
||||
public void initialize(@NotNull Configuration config) {
|
||||
initialize(config, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link ConfigurationRoot} 对象。
|
||||
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。
|
||||
*
|
||||
* @param config 配置文件实例类,须实现 {@link ConfigurationRoot} 。
|
||||
* @param config 配置文件实例类,须实现 {@link Configuration} 。
|
||||
* @param saveDefaults 是否写入默认值(默认为 true)。
|
||||
*/
|
||||
public void initialize(@NotNull ConfigurationRoot config, boolean saveDefaults) {
|
||||
public void initialize(@NotNull Configuration config, boolean saveDefaults) {
|
||||
initializeInstance(
|
||||
config, null, null,
|
||||
null, null, null,
|
||||
@ -92,7 +92,7 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
|
||||
|
||||
|
||||
// 针对实例类的初始化方法
|
||||
private void initializeInstance(@NotNull ConfigurationRoot root,
|
||||
private void initializeInstance(@NotNull Configuration root,
|
||||
@Nullable String parentPath, @Nullable String fieldName,
|
||||
@Nullable ConfigPath fieldPath,
|
||||
@Nullable HeaderComment fieldHeaderComments,
|
||||
@ -114,7 +114,7 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
|
||||
@Nullable HeaderComment fieldHeaderComments,
|
||||
@Nullable InlineComment fieldInlineComments,
|
||||
boolean saveDefaults, boolean loadSubClasses) {
|
||||
if (!ConfigurationRoot.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类
|
||||
if (!Configuration.class.isAssignableFrom(clazz)) return; // 只解析继承了 ConfigurationRoot 的类
|
||||
String path = getClassPath(clazz, parentPath, fieldName, fieldPath);
|
||||
this.provider.setHeaderComment(path, getClassHeaderComments(clazz, fieldHeaderComments));
|
||||
if (path != null) this.provider.setInlineComment(path, readInlineComments(fieldInlineComments));
|
||||
@ -147,10 +147,10 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
|
||||
field.getAnnotation(InlineComment.class),
|
||||
saveDefaults
|
||||
);
|
||||
} else if (source instanceof ConfigurationRoot && object instanceof ConfigurationRoot) {
|
||||
} else if (source instanceof Configuration && object instanceof Configuration) {
|
||||
// 当且仅当 源字段与字段 均为ConfigurationRoot实例时,才对目标字段进行下一步初始化加载。
|
||||
initializeInstance(
|
||||
(ConfigurationRoot) object, parent, field.getName(),
|
||||
(Configuration) object, parent, field.getName(),
|
||||
field.getAnnotation(ConfigPath.class),
|
||||
field.getAnnotation(HeaderComment.class),
|
||||
field.getAnnotation(InlineComment.class),
|
||||
|
@ -0,0 +1,8 @@
|
||||
package cc.carm.lib.configuration.core;
|
||||
|
||||
/**
|
||||
* The root interface of the configuration file interfaces,
|
||||
* which is used to label and record the configuration information.
|
||||
*/
|
||||
public interface Configuration {
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
package cc.carm.lib.configuration.core;
|
||||
|
||||
/**
|
||||
* 配置文件类的根节点,用于标注该类用于记录配置文件中的配置信息。
|
||||
* The root node of the configuration file class,
|
||||
* which is used to label and record the configuration information.
|
||||
*/
|
||||
public abstract class ConfigurationRoot {
|
||||
public abstract class ConfigurationRoot implements Configuration {
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
package cc.carm.lib.configuration.core.source;
|
||||
|
||||
import cc.carm.lib.configuration.core.ConfigInitializer;
|
||||
import cc.carm.lib.configuration.core.ConfigurationRoot;
|
||||
import cc.carm.lib.configuration.core.Configuration;
|
||||
import cc.carm.lib.configuration.core.Configuration;
|
||||
import cc.carm.lib.configuration.core.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -101,49 +102,49 @@ public abstract class ConfigurationProvider<W extends ConfigurationWrapper<?>> {
|
||||
/**
|
||||
* 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。
|
||||
*
|
||||
* @param configClazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
|
||||
* @param configClazz 配置文件类,须继承于 {@link Configuration} 。
|
||||
*/
|
||||
public void initialize(Class<? extends ConfigurationRoot> configClazz) {
|
||||
public void initialize(Class<? extends Configuration> configClazz) {
|
||||
initialize(configClazz, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化指定类以及其子类的所有 {@link ConfigValue} 对象。
|
||||
*
|
||||
* @param configClazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
|
||||
* @param configClazz 配置文件类,须继承于 {@link Configuration} 。
|
||||
* @param saveDefaults 是否写入默认值(默认为 true)。
|
||||
*/
|
||||
public void initialize(Class<? extends ConfigurationRoot> configClazz, boolean saveDefaults) {
|
||||
public void initialize(Class<? extends Configuration> configClazz, boolean saveDefaults) {
|
||||
this.getInitializer().initialize(configClazz, saveDefaults);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化指定类的所有 {@link ConfigValue} 对象。
|
||||
*
|
||||
* @param configClazz 配置文件类,须继承于 {@link ConfigurationRoot} 。
|
||||
* @param configClazz 配置文件类,须继承于 {@link Configuration} 。
|
||||
* @param saveDefaults 是否写入默认值(默认为 true)。
|
||||
* @param loadSubClasses 是否加载内部子类(默认为 true)。
|
||||
*/
|
||||
public void initialize(Class<? extends ConfigurationRoot> configClazz, boolean saveDefaults, boolean loadSubClasses) {
|
||||
public void initialize(Class<? extends Configuration> configClazz, boolean saveDefaults, boolean loadSubClasses) {
|
||||
this.getInitializer().initialize(configClazz, saveDefaults, loadSubClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link ConfigurationRoot} 对象。
|
||||
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。
|
||||
*
|
||||
* @param config 配置文件实例类,须实现 {@link ConfigurationRoot} 。
|
||||
* @param config 配置文件实例类,须实现 {@link Configuration} 。
|
||||
*/
|
||||
public void initialize(@NotNull ConfigurationRoot config) {
|
||||
public void initialize(@NotNull Configuration config) {
|
||||
this.getInitializer().initialize(config, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link ConfigurationRoot} 对象。
|
||||
* 初始化指定实例的所有 {@link ConfigValue} 与内部 {@link Configuration} 对象。
|
||||
*
|
||||
* @param config 配置文件实例类,须实现 {@link ConfigurationRoot} 。
|
||||
* @param config 配置文件实例类,须实现 {@link Configuration} 。
|
||||
* @param saveDefaults 是否写入默认值(默认为 true)。
|
||||
*/
|
||||
public void initialize(@NotNull ConfigurationRoot config, boolean saveDefaults) {
|
||||
public void initialize(@NotNull Configuration config, boolean saveDefaults) {
|
||||
this.getInitializer().initialize(config, saveDefaults);
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,7 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements Lis
|
||||
@Override
|
||||
public @NotNull List<V> get() {
|
||||
if (!isExpired()) return getCachedOrDefault(new ArrayList<>());
|
||||
|
||||
// 已过时的数据,需要重新解析一次。
|
||||
// Data that is outdated and needs to be parsed again.
|
||||
List<V> list = new ArrayList<>();
|
||||
List<?> data = getConfiguration().contains(getConfigPath()) ?
|
||||
getConfiguration().getList(getConfigPath()) : null;
|
||||
|
@ -31,37 +31,55 @@ public class ConfiguredSection<V> extends CachedConfigValue<V> {
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's type class
|
||||
*/
|
||||
public @NotNull Class<V> getValueClass() {
|
||||
return valueClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's parser, cast value from section.
|
||||
*/
|
||||
public @NotNull ConfigValueParser<ConfigurationWrapper<?>, V> getParser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's serializer, serialize value to section.
|
||||
*/
|
||||
public @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> getSerializer() {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Get the value that parsed from the configuration section.
|
||||
*/
|
||||
@Override
|
||||
public @Nullable V get() {
|
||||
if (!isExpired()) return getCachedOrDefault();
|
||||
// 已过时的数据,需要重新解析一次。
|
||||
// Data that is outdated and needs to be parsed again.
|
||||
|
||||
ConfigurationWrapper<?> section = getConfiguration().getConfigurationSection(getConfigPath());
|
||||
if (section == null) return getDefaultValue();
|
||||
|
||||
try {
|
||||
// 若未出现错误,则直接更新缓存并返回。
|
||||
// If there are no errors, update the cache and return.
|
||||
return updateCache(this.parser.parse(section, this.defaultValue));
|
||||
} catch (Exception e) {
|
||||
// 出现了解析错误,提示并返回默认值。
|
||||
// There was a parsing error, prompted and returned the default value.
|
||||
e.printStackTrace();
|
||||
return getDefaultValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the specified value to update the configuration section.
|
||||
* Will use {@link #getSerializer()} to serialize the value to section.
|
||||
*
|
||||
* @param value The value that needs to be set in the configuration.
|
||||
*/
|
||||
@Override
|
||||
public void set(V value) {
|
||||
updateCache(value);
|
||||
|
@ -14,6 +14,11 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
||||
return builder().asValue(valueClass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <V> ConfiguredValue<V> of(@NotNull V defaultValue) {
|
||||
return of((Class<V>) defaultValue.getClass(), defaultValue);
|
||||
}
|
||||
|
||||
public static <V> ConfiguredValue<V> of(Class<V> valueClass) {
|
||||
return of(valueClass, null);
|
||||
}
|
||||
@ -36,32 +41,51 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
|
||||
this.serializer = serializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's type class
|
||||
*/
|
||||
public @NotNull Class<V> getValueClass() {
|
||||
return valueClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's parser, cast value from base object.
|
||||
*/
|
||||
public @NotNull ConfigValueParser<Object, V> getParser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value's serializer, serialize value to base object.
|
||||
*/
|
||||
public @NotNull ConfigDataFunction<V, Object> getSerializer() {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get() {
|
||||
if (!isExpired()) return getCachedOrDefault();
|
||||
// 已过时的数据,需要重新解析一次。
|
||||
// Data that is outdated and needs to be parsed again.
|
||||
|
||||
Object value = getValue();
|
||||
if (value == null) return getDefaultValue(); // 获取的值不存在,直接使用默认值。
|
||||
try {
|
||||
// 若未出现错误,则直接更新缓存并返回。
|
||||
// If there are no errors, update the cache and return.
|
||||
return updateCache(this.parser.parse(value, this.defaultValue));
|
||||
} catch (Exception e) {
|
||||
// 出现了解析错误,提示并返回默认值。
|
||||
// There was a parsing error, prompted and returned the default value.
|
||||
e.printStackTrace();
|
||||
return getDefaultValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the configuration path.
|
||||
* Will use {@link #getSerializer()} to serialize the value.
|
||||
*
|
||||
* @param value The value to be set
|
||||
*/
|
||||
@Override
|
||||
public void set(V value) {
|
||||
updateCache(value);
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cc.carm.lib.configuration.demo.tests.conf;
|
||||
|
||||
import cc.carm.lib.configuration.core.ConfigInitializer;
|
||||
import cc.carm.lib.configuration.core.Configuration;
|
||||
import cc.carm.lib.configuration.core.ConfigurationRoot;
|
||||
import cc.carm.lib.configuration.core.annotation.ConfigPath;
|
||||
import cc.carm.lib.configuration.core.annotation.HeaderComment;
|
||||
@ -18,35 +19,33 @@ import java.util.UUID;
|
||||
|
||||
|
||||
@HeaderComment({"此处内容将显示在配置文件的最上方"})
|
||||
public class DemoConfiguration extends ConfigurationRoot {
|
||||
public interface DemoConfiguration extends Configuration {
|
||||
|
||||
@ConfigPath(root = true)
|
||||
protected static final ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 1.0D);
|
||||
ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 1.0D);
|
||||
|
||||
@ConfigPath(root = true)
|
||||
public static final ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(Long.class, 1000000L);
|
||||
ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(1000000L);
|
||||
|
||||
public static final ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
|
||||
ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
|
||||
|
||||
// 支持通过 Class<?> 变量标注子配置,一并注册。
|
||||
// 注意: 若对应类也有注解,则优先使用类的注解。
|
||||
@ConfigPath("other-class-config") //支持通过注解修改子配置的主路径,若不修改则以变量名自动生成。
|
||||
@HeaderComment({"", "Something..."}) // 支持给子路径直接打注释
|
||||
@InlineComment("InlineComments for class path")
|
||||
public static final Class<?> OTHER = OtherConfiguration.class;
|
||||
Class<?> OTHER = OtherConfiguration.class;
|
||||
|
||||
@ConfigPath("user") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
|
||||
@HeaderComment({"Section类型数据测试"}) // 通过注解给配置添加注释。
|
||||
@InlineComment("Section数据也支持InlineComment注释")
|
||||
public static final ConfigValue<TestModel> MODEL_TEST = ConfiguredSection
|
||||
.builderOf(TestModel.class)
|
||||
ConfigValue<TestModel> MODEL_TEST = ConfiguredSection.builderOf(TestModel.class)
|
||||
.defaults(new TestModel("Carm", UUID.randomUUID()))
|
||||
.parseValue((section, defaultValue) -> TestModel.deserialize(section))
|
||||
.serializeValue(TestModel::serialize).build();
|
||||
|
||||
@HeaderComment({"[ID - UUID]对照表", "", "用于测试Map类型的解析与序列化保存"})
|
||||
public static final ConfiguredMap<Integer, UUID> USERS = ConfiguredMap
|
||||
.builderOf(Integer.class, UUID.class)
|
||||
ConfiguredMap<Integer, UUID> USERS = ConfiguredMap.builderOf(Integer.class, UUID.class)
|
||||
.asLinkedMap().fromString()
|
||||
.parseKey(Integer::parseInt)
|
||||
.parseValue(v -> Objects.requireNonNull(UUID.fromString(v)))
|
||||
@ -57,7 +56,7 @@ public class DemoConfiguration extends ConfigurationRoot {
|
||||
* 支持内部类的直接注册。
|
||||
* 注意,需要使用 {@link ConfigInitializer#initialize(Class, boolean, boolean)} 方法,并设定第三个参数为 true。
|
||||
*/
|
||||
public static class Sub extends ConfigurationRoot {
|
||||
class Sub extends ConfigurationRoot {
|
||||
|
||||
@ConfigPath(value = "uuid-value", root = true)
|
||||
@InlineComment("This is an inline comment")
|
||||
|
@ -1,10 +1,8 @@
|
||||
package online.flowerinsnow.test.easyconfiguration;
|
||||
|
||||
import cc.carm.lib.configuration.EasyConfiguration;
|
||||
//import cc.carm.lib.configuration.demo.DatabaseConfiguration;
|
||||
//import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration;
|
||||
import cc.carm.lib.configuration.hocon.HOCONFileConfigProvider;
|
||||
import online.flowerinsnow.test.easyconfiguration.config.Config;
|
||||
import online.flowerinsnow.test.easyconfiguration.config.SimpleConfig;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
@ -13,9 +11,15 @@ public class HOCONTest {
|
||||
@Test
|
||||
public void onTest() {
|
||||
HOCONFileConfigProvider provider = EasyConfiguration.from(new File("target/hocon.conf"));
|
||||
provider.initialize(Config.class);
|
||||
provider.initialize(SimpleConfig.class);
|
||||
// provider.initialize(DatabaseConfiguration.class);
|
||||
|
||||
System.out.println(SimpleConfig.TEST_INT.getNotNull());
|
||||
SimpleConfig.TEST_INT.set((int) (Math.random() * 100 * 5));
|
||||
System.out.println(SimpleConfig.TEST_INT.getNotNull());
|
||||
|
||||
try {
|
||||
provider.save();
|
||||
provider.reload();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -1,25 +1,28 @@
|
||||
package online.flowerinsnow.test.easyconfiguration.config;
|
||||
|
||||
import cc.carm.lib.configuration.core.ConfigurationRoot;
|
||||
import cc.carm.lib.configuration.core.Configuration;
|
||||
import cc.carm.lib.configuration.core.annotation.HeaderComment;
|
||||
import cc.carm.lib.configuration.core.value.type.ConfiguredList;
|
||||
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
|
||||
|
||||
public class Config extends ConfigurationRoot {
|
||||
public interface SimpleConfig extends Configuration {
|
||||
@HeaderComment("测试字段 int")
|
||||
public static final ConfiguredValue<Integer> TEST_INT = ConfiguredValue.of(Integer.class, 15);
|
||||
ConfiguredValue<Integer> TEST_INT = ConfiguredValue.of(Integer.class, 15);
|
||||
|
||||
@HeaderComment("测试字段 List<String>")
|
||||
public static final ConfiguredList<String> TEST_LIST_STRING = ConfiguredList.of(String.class, "li", "li", "li1");
|
||||
ConfiguredList<String> TEST_LIST_STRING = ConfiguredList.of(String.class, "li", "li", "li1");
|
||||
|
||||
@HeaderComment("测试对象")
|
||||
public static class TestObject extends ConfigurationRoot {
|
||||
interface TestObject extends Configuration {
|
||||
|
||||
@HeaderComment("测试字段 Boolean")
|
||||
public static final ConfiguredValue<Boolean> TEST_BOOLEAN = ConfiguredValue.of(Boolean.class, true);
|
||||
ConfiguredValue<Boolean> TEST_BOOLEAN = ConfiguredValue.of(Boolean.class, true);
|
||||
|
||||
@HeaderComment("inner")
|
||||
public static class InnerObject extends ConfigurationRoot {
|
||||
interface InnerObject extends Configuration {
|
||||
@HeaderComment("测试字段")
|
||||
public static final ConfiguredValue<Boolean> TEST_BOOLEAN_1 = ConfiguredValue.of(Boolean.class, true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user