mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-05 02:58:20 +08:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bc3e4b3e6f | |||
| c2a9e2254c | |||
| 251dd208af | |||
| afd1bbfc0f | |||
| a699f6c164 | |||
| 844cbfab53 | |||
| f74d5d29f9 |
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.7</version>
|
||||
<version>4.0.9</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<properties>
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -157,7 +158,7 @@ public abstract class ValueType<T> {
|
||||
ParameterizedType pt = (ParameterizedType) type;
|
||||
Type raw = pt.getRawType();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(raw.getTypeName());
|
||||
sb.append(raw.getClass().getName());
|
||||
sb.append('<');
|
||||
Type[] args = pt.getActualTypeArguments();
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
@@ -166,6 +167,7 @@ public abstract class ValueType<T> {
|
||||
}
|
||||
sb.append(args[i].getTypeName());
|
||||
}
|
||||
sb.append('>');
|
||||
return sb.toString();
|
||||
}
|
||||
return type.getTypeName();
|
||||
|
||||
@@ -6,9 +6,11 @@ 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.meta.ConfigurationMetadata;
|
||||
import cc.carm.lib.configuration.source.meta.StandardMeta;
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOption;
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
|
||||
import cc.carm.lib.configuration.source.section.ConfigureSource;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.value.ValueManifest;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -18,6 +20,8 @@ import org.jetbrains.annotations.UnmodifiableView;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, SOURCE>> {
|
||||
|
||||
@@ -51,7 +55,7 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
||||
return options;
|
||||
}
|
||||
|
||||
public <O> O option(@NotNull ConfigurationOption<O> option) {
|
||||
public <O> @NotNull O option(@NotNull ConfigurationOption<O> option) {
|
||||
return options().get(option);
|
||||
}
|
||||
|
||||
@@ -66,14 +70,26 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
|
||||
@NotNull
|
||||
@UnmodifiableView
|
||||
public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type) {
|
||||
return extractMetadata(type, Objects::nonNull);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@UnmodifiableView
|
||||
public <M> Map<String, M> extractMetadata(@NotNull ConfigurationMetadata<M> type, @NotNull Predicate<M> filter) {
|
||||
Map<String, M> metas = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, ConfigurationMetaHolder> entry : this.metadata.entrySet()) {
|
||||
M data = entry.getValue().get(type);
|
||||
if (data != null) metas.put(entry.getKey(), data);
|
||||
if (filter.test(data)) metas.put(entry.getKey(), data);
|
||||
}
|
||||
return Collections.unmodifiableMap(metas);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@UnmodifiableView
|
||||
public Map<String, ConfigValue<?>> registeredValues() {
|
||||
return extractMetadata(StandardMeta.VALUE);
|
||||
}
|
||||
|
||||
public ValueAdapterRegistry adapters() {
|
||||
return this.adapters;
|
||||
}
|
||||
|
||||
+13
-12
@@ -5,26 +5,27 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ConfigInitializeHandler<T> {
|
||||
public interface ConfigInitializeHandler<T, V> {
|
||||
|
||||
static <T> ConfigInitializeHandler<T> start() {
|
||||
return (provider, path, value) -> {
|
||||
static <T, V> ConfigInitializeHandler<T, V> start() {
|
||||
return (provider, path, value, instace) -> {
|
||||
};
|
||||
}
|
||||
|
||||
void whenInitialize(@NotNull ConfigurationHolder<?> holder, @Nullable String path, @NotNull T value) throws Exception;
|
||||
void whenInitialize(@NotNull ConfigurationHolder<?> holder, @Nullable String path,
|
||||
@NotNull T value, @Nullable V instance) throws Exception;
|
||||
|
||||
default ConfigInitializeHandler<T> andThen(ConfigInitializeHandler<T> after) {
|
||||
return (provider, path, value) -> {
|
||||
whenInitialize(provider, path, value);
|
||||
after.whenInitialize(provider, path, value);
|
||||
default ConfigInitializeHandler<T, V> andThen(ConfigInitializeHandler<T, V> after) {
|
||||
return (provider, path, value, instance) -> {
|
||||
whenInitialize(provider, path, value, instance);
|
||||
after.whenInitialize(provider, path, value, instance);
|
||||
};
|
||||
}
|
||||
|
||||
default ConfigInitializeHandler<T> compose(ConfigInitializeHandler<T> before) {
|
||||
return (provider, path, value) -> {
|
||||
before.whenInitialize(provider, path, value);
|
||||
whenInitialize(provider, path, value);
|
||||
default ConfigInitializeHandler<T, V> compose(ConfigInitializeHandler<T, V> before) {
|
||||
return (provider, path, value, instance) -> {
|
||||
before.whenInitialize(provider, path, value, instance);
|
||||
whenInitialize(provider, path, value, instance);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+24
-24
@@ -21,18 +21,18 @@ import java.util.function.Function;
|
||||
public class ConfigurationInitializer {
|
||||
|
||||
protected @NotNull PathGenerator pathGenerator;
|
||||
protected @NotNull ConfigInitializeHandler<Field> fieldInitializer;
|
||||
protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>> classInitializer;
|
||||
protected @NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer;
|
||||
protected @NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer;
|
||||
|
||||
public ConfigurationInitializer() {
|
||||
this(PathGenerator.of(), ConfigInitializeHandler.start(), ConfigInitializeHandler.start());
|
||||
}
|
||||
|
||||
public ConfigurationInitializer(@NotNull PathGenerator pathGenerator,
|
||||
@NotNull ConfigInitializeHandler<Field> fieldInitializer,
|
||||
@NotNull ConfigInitializeHandler<Class<? extends Configuration>> classInitializer) {
|
||||
@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> valueInitializer,
|
||||
@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
|
||||
this.pathGenerator = pathGenerator;
|
||||
this.fieldInitializer = fieldInitializer;
|
||||
this.valueInitializer = valueInitializer;
|
||||
this.classInitializer = classInitializer;
|
||||
}
|
||||
|
||||
@@ -44,34 +44,34 @@ public class ConfigurationInitializer {
|
||||
return pathGenerator;
|
||||
}
|
||||
|
||||
public ConfigInitializeHandler<Field> fieldInitializer() {
|
||||
return fieldInitializer;
|
||||
public ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer() {
|
||||
return valueInitializer;
|
||||
}
|
||||
|
||||
public void fieldInitializer(@NotNull ConfigInitializeHandler<Field> fieldInitializer) {
|
||||
this.fieldInitializer = fieldInitializer;
|
||||
public void fieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) {
|
||||
this.valueInitializer = fieldInitializer;
|
||||
}
|
||||
|
||||
public ConfigInitializeHandler<Class<? extends Configuration>> classInitializer() {
|
||||
public ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer() {
|
||||
return classInitializer;
|
||||
}
|
||||
|
||||
public void classInitializer(@NotNull ConfigInitializeHandler<Class<? extends Configuration>> classInitializer) {
|
||||
public void classInitializer(@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
|
||||
this.classInitializer = classInitializer;
|
||||
}
|
||||
|
||||
public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field> fieldInitializer) {
|
||||
this.fieldInitializer = this.fieldInitializer.andThen(fieldInitializer);
|
||||
public void appendFieldInitializer(@NotNull ConfigInitializeHandler<Field, ConfigValue<?>> fieldInitializer) {
|
||||
this.valueInitializer = this.valueInitializer.andThen(fieldInitializer);
|
||||
}
|
||||
|
||||
public void appendClassInitializer(@NotNull ConfigInitializeHandler<Class<? extends Configuration>> classInitializer) {
|
||||
public void appendClassInitializer(@NotNull ConfigInitializeHandler<Class<? extends Configuration>, Object> classInitializer) {
|
||||
this.classInitializer = this.classInitializer.andThen(classInitializer);
|
||||
}
|
||||
|
||||
public <T, A extends Annotation> void registerClassAnnotation(@NotNull Class<A> annotation,
|
||||
@NotNull ConfigurationMetadata<T> metadata,
|
||||
@NotNull Function<A, T> extractor) {
|
||||
appendClassInitializer((holder, path, clazz) -> {
|
||||
appendClassInitializer((holder, path, clazz, instance) -> {
|
||||
A data = clazz.getAnnotation(annotation);
|
||||
if (data == null) return;
|
||||
holder.metadata(path).setIfAbsent(metadata, extractor.apply(data));
|
||||
@@ -81,7 +81,7 @@ public class ConfigurationInitializer {
|
||||
public <T, A extends Annotation> void registerFieldAnnotation(@NotNull Class<A> annotation,
|
||||
@NotNull ConfigurationMetadata<T> metadata,
|
||||
@NotNull Function<A, T> extractor) {
|
||||
appendFieldInitializer((holder, path, field) -> {
|
||||
appendFieldInitializer((holder, path, field, instance) -> {
|
||||
A data = field.getAnnotation(annotation);
|
||||
if (data == null) return;
|
||||
holder.metadata(path).setIfAbsent(metadata, extractor.apply(data));
|
||||
@@ -123,7 +123,7 @@ public class ConfigurationInitializer {
|
||||
@Nullable String parentPath, @Nullable Field configField) {
|
||||
String path = getClassPath(holder, parentPath, root.getClass(), configField);
|
||||
try {
|
||||
this.classInitializer.whenInitialize(holder, path, root.getClass());
|
||||
this.classInitializer.whenInitialize(holder, path, root.getClass(), root);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public class ConfigurationInitializer {
|
||||
String path = getClassPath(holder, parentPath, clazz, configField);
|
||||
|
||||
try {
|
||||
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz);
|
||||
this.classInitializer.whenInitialize(holder, path, (Class<? extends Configuration>) clazz, configField);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -169,15 +169,15 @@ public class ConfigurationInitializer {
|
||||
String path = getFieldPath(holder, parent, field);
|
||||
if (path == null) return;
|
||||
value.initialize(holder, path);
|
||||
holder.metadata(path).set(StandardMeta.UNIT, true); // Mark the minimal config value unit.
|
||||
try {
|
||||
this.fieldInitializer.whenInitialize(holder, path, field);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
holder.metadata(path).set(StandardMeta.VALUE, value); // Mark the minimal config value unit.
|
||||
if (holder.option(StandardOptions.SET_DEFAULTS)) {
|
||||
value.setDefault(); // Set default value.
|
||||
}
|
||||
try {
|
||||
this.valueInitializer.whenInitialize(holder, path, field, value);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (holder.option(StandardOptions.PRELOAD)) {
|
||||
value.get(); // Preload the value by calling #get method.
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package cc.carm.lib.configuration.source.meta;
|
||||
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
|
||||
public interface StandardMeta {
|
||||
|
||||
/**
|
||||
* To mark the {@link cc.carm.lib.configuration.value.ConfigValue} as a minimal unit path.
|
||||
* To mark the {@link ConfigValue} instance of specific path.
|
||||
*/
|
||||
ConfigurationMetadata<Boolean> UNIT = ConfigurationMetadata.of(false);
|
||||
ConfigurationMetadata<ConfigValue<?>> VALUE = ConfigurationMetadata.of();
|
||||
|
||||
}
|
||||
|
||||
@@ -23,12 +23,13 @@ public interface StandardOptions {
|
||||
ConfigurationOption<Boolean> LOAD_SUB_CLASSES = of(true);
|
||||
|
||||
/**
|
||||
* Whether to pre parse the config values.
|
||||
* <br> if false, the values will be parsed when calling
|
||||
* {@link cc.carm.lib.configuration.value.ConfigValue#get()}
|
||||
* Whether to pre parse the config values,
|
||||
* may good to set true if you want to keep the config format.
|
||||
* <br> if true, the values will be parsed when
|
||||
* {@link ConfigurationHolder#initialize(Configuration)}.
|
||||
* <br> if false, the values will be parsed when calling
|
||||
* {@link cc.carm.lib.configuration.value.ConfigValue#get()}
|
||||
*/
|
||||
ConfigurationOption<Boolean> PRELOAD = of(false);
|
||||
ConfigurationOption<Boolean> PRELOAD = of(true);
|
||||
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ public interface ConfigureSection {
|
||||
return (parent().isRoot() ? "" : parent().fullPath() + pathSeparator()) + path();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the path separator for the section.
|
||||
*
|
||||
@@ -143,6 +142,17 @@ public interface ConfigureSection {
|
||||
return getValues(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this section as a map.
|
||||
* <p>
|
||||
* In this map, child {@link ConfigureSection}s will also be represented as {@link Map}s.
|
||||
*
|
||||
* @return Map of data values contained within this Section.
|
||||
*/
|
||||
@NotNull
|
||||
@UnmodifiableView
|
||||
Map<String, Object> asMap();
|
||||
|
||||
/**
|
||||
* Create a stream of all values in this section.
|
||||
*
|
||||
@@ -153,7 +163,7 @@ public interface ConfigureSection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all keys in this section.
|
||||
* Iterates over all key-values in this section (include child sections)
|
||||
*
|
||||
* @param action The action to apply to each key.
|
||||
*/
|
||||
|
||||
@@ -107,6 +107,11 @@ public abstract class ConfigureSource<
|
||||
return section().getKeys(deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull @UnmodifiableView Map<String, Object> asMap() {
|
||||
return section().asMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||
return section().createSection(path, data);
|
||||
|
||||
@@ -4,6 +4,7 @@ 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.ConfigureSource;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -20,7 +21,6 @@ public class ValueManifest<T> {
|
||||
|
||||
protected @NotNull Supplier<@Nullable T> defaultSupplier;
|
||||
|
||||
|
||||
public ValueManifest(@NotNull ValueType<T> type) {
|
||||
this(type, () -> null, EMPTY_INITIALIZER, null, null);
|
||||
}
|
||||
@@ -93,12 +93,12 @@ public class ValueManifest<T> {
|
||||
|
||||
public @NotNull String path() {
|
||||
if (path != null) return path;
|
||||
else throw new IllegalStateException("No section path provided.");
|
||||
else throw new IllegalStateException("No section path provided for Value(" + type() + ").");
|
||||
}
|
||||
|
||||
public @NotNull ConfigurationHolder<?> holder() {
|
||||
if (this.holder != null) return this.holder;
|
||||
throw new IllegalStateException("Value does not have a provider.");
|
||||
throw new IllegalStateException("Value(" + type() + ") does not have a provider.");
|
||||
}
|
||||
|
||||
public @NotNull ConfigureSource<?, ?, ?> config() {
|
||||
@@ -109,16 +109,17 @@ public class ValueManifest<T> {
|
||||
return holder().metadata(path());
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
protected Object getData() {
|
||||
return config().get(path());
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
protected void setData(@Nullable Object value) {
|
||||
config().set(path(), value);
|
||||
}
|
||||
|
||||
|
||||
private static final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> EMPTY_INITIALIZER = (provider, path) -> {
|
||||
private static final @NotNull BiConsumer<@NotNull ConfigurationHolder<?>, @NotNull String> EMPTY_INITIALIZER = (provider, valuePath) -> {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
+14
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.7</version>
|
||||
<version>4.0.9</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<properties>
|
||||
@@ -33,6 +33,19 @@
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-feature-versioned</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-feature-versioned</artifactId>
|
||||
<version>4.0.8</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -7,7 +7,7 @@ import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
|
||||
@HeaderComments({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"})
|
||||
public class DatabaseConfiguration implements Configuration {
|
||||
public interface DatabaseConfiguration extends Configuration {
|
||||
|
||||
@ConfigPath("driver")
|
||||
@HeaderComments({
|
||||
@@ -16,18 +16,19 @@ public class DatabaseConfiguration implements Configuration {
|
||||
"- MySQL(新): com.mysql.cj.jdbc.Driver",
|
||||
"- MariaDB(推荐): org.mariadb.jdbc.Driver",
|
||||
})
|
||||
protected static final ConfigValue<String> DRIVER_NAME = ConfiguredValue.of(
|
||||
ConfigValue<String> DRIVER_NAME = ConfiguredValue.of(
|
||||
String.class, "com.mysql.cj.jdbc.Driver"
|
||||
);
|
||||
|
||||
protected static final ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
|
||||
protected static final ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
|
||||
protected static final ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
|
||||
protected static final ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
|
||||
protected static final ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
|
||||
protected static final ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
|
||||
ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
|
||||
ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
|
||||
ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
|
||||
ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
|
||||
ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
|
||||
|
||||
protected static String buildJDBC() {
|
||||
ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
|
||||
|
||||
static String buildJDBC() {
|
||||
return String.format("jdbc:mysql://%s:%s/%s%s", HOST.get(), PORT.get(), DATABASE.get(), EXTRA.get());
|
||||
}
|
||||
|
||||
|
||||
@@ -69,14 +69,14 @@ public class ConfigurationTest {
|
||||
provider.initialize(TEST);
|
||||
|
||||
System.out.println("> Test Inner value before:");
|
||||
System.out.println(TEST.INSTANCE.INNER_VALUE.resolve());
|
||||
System.out.println(TEST.INSTANCE.STATUS.resolve());
|
||||
|
||||
double after = Math.random() * 200D;
|
||||
System.out.println("> Test Inner value -> " + after);
|
||||
TEST.INSTANCE.INNER_VALUE.set(after);
|
||||
TEST.INSTANCE.STATUS.set(after);
|
||||
|
||||
System.out.println("> Test Inner value after:");
|
||||
System.out.println(TEST.INSTANCE.INNER_VALUE.resolve());
|
||||
System.out.println(TEST.INSTANCE.STATUS.resolve());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
package cc.carm.lib.configuration.demo.tests.conf;
|
||||
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
import cc.carm.lib.configuration.annotation.ConfigPath;
|
||||
import cc.carm.lib.configuration.annotation.FooterComments;
|
||||
import cc.carm.lib.configuration.annotation.HeaderComments;
|
||||
import cc.carm.lib.configuration.annotation.InlineComment;
|
||||
import cc.carm.lib.configuration.demo.DatabaseConfiguration;
|
||||
import cc.carm.lib.configuration.annotation.*;
|
||||
import cc.carm.lib.configuration.demo.tests.model.ItemStack;
|
||||
import cc.carm.lib.configuration.demo.tests.model.UserRecord;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
@@ -29,7 +25,8 @@ import java.util.UUID;
|
||||
public interface DemoConfiguration extends Configuration {
|
||||
|
||||
@ConfigPath(root = true)
|
||||
ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 1.0D);
|
||||
@ConfigVersion(2)
|
||||
ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 2.0D);
|
||||
|
||||
@ConfigPath(root = true)
|
||||
@FooterComments({"此处内容将显示在配置条目的下方", "可用于补充说明,但一般不建议使用"})
|
||||
@@ -39,9 +36,11 @@ public interface DemoConfiguration extends Configuration {
|
||||
@FooterComments({"上述的枚举内容本质上是通过STRING解析的"})
|
||||
ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
|
||||
|
||||
// 支持通过 Class<?> 变量标注子配置,一并注册。
|
||||
// 注意: 若对应类也有注解,则优先使用类的注解。
|
||||
Class<?> DATABASE = DatabaseConfiguration.class;
|
||||
@HeaderComments({"空值测试"})
|
||||
@InlineComment("空值Inline注释")
|
||||
ConfiguredMap<String, String> EMPTY = ConfiguredMap.builderOf(String.class, String.class)
|
||||
.asLinkedMap().fromString()
|
||||
.build();
|
||||
|
||||
@ConfigPath("registered_users") // 通过注解规定配置文件中的路径,若不进行注解则以变量名自动生成。
|
||||
@HeaderComments({"Section类型数据测试"}) // 通过注解给配置添加注释。
|
||||
|
||||
@@ -8,6 +8,6 @@ import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
@HeaderComments("Inner Test")
|
||||
public class InstanceConfig implements Configuration {
|
||||
|
||||
public final ConfigValue<Double> INNER_VALUE = ConfiguredValue.of(1.0D);
|
||||
public final ConfigValue<Double> STATUS = ConfiguredValue.of(1.0D);
|
||||
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public class RegistryConfig implements Configuration {
|
||||
@FooterComments({"12313213212"})
|
||||
@InlineComment(value = "用户名(匹配注释)", regex = "name") // 通过注解给配置添加注释。
|
||||
@InlineComment(value = "信息", regex = {"info.*", "info.game.*"}) // 通过注解给配置添加注释。
|
||||
public final ConfigValue<UserRecord> TEST_MODEL = ConfiguredValue.builderOf(UserRecord.class).fromSection()
|
||||
public final ConfigValue<UserRecord> OWNER = ConfiguredValue.builderOf(UserRecord.class).fromSection()
|
||||
.defaults(new UserRecord("Carm", UUID.randomUUID()))
|
||||
.parse((holder, section) -> UserRecord.deserialize(section))
|
||||
.serialize((holder, data) -> data.serialize()).build();
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.7</version>
|
||||
<version>4.0.9</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
|
||||
+11
@@ -49,6 +49,17 @@ public interface CommentableMeta {
|
||||
FooterComments.class, FOOTER,
|
||||
a -> Arrays.asList(a.value())
|
||||
);
|
||||
initializer.registerAnnotation(InlineComment.class, INLINE, a -> {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
if (a.regex().length == 0) { // for current path
|
||||
map.put(null, a.value());
|
||||
return map;
|
||||
}
|
||||
for (String regex : a.regex()) { // for specified path
|
||||
map.put(regex, a.value());
|
||||
}
|
||||
return map;
|
||||
});
|
||||
initializer.registerAnnotation(InlineComments.class, INLINE, a -> {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for (InlineComment comment : a.value()) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.7</version>
|
||||
<version>4.0.9</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.7</version>
|
||||
<version>4.0.9</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
|
||||
+30
-2
@@ -75,12 +75,23 @@ public abstract class AbstractMapSection<R extends AbstractMapSection<R>> implem
|
||||
return deep ? getKeys(true).size() : this.data.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@UnmodifiableView
|
||||
public @NotNull Map<String, Object> rawMap() {
|
||||
public @NotNull Map<String, Object> asMap() {
|
||||
Map<String, Object> output = new LinkedHashMap<>();
|
||||
for (Map.Entry<String, Object> entry : this.data.entrySet()) {
|
||||
if (entry.getValue() instanceof AbstractMapSection<?>) {
|
||||
output.put(entry.getKey(), ((AbstractMapSection<?>) entry.getValue()).rawMap());
|
||||
output.put(entry.getKey(), ((AbstractMapSection<?>) entry.getValue()).asMap());
|
||||
} else if (entry.getValue() instanceof List<?>) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
for (Object obj : (List<?>) entry.getValue()) {
|
||||
if (obj instanceof AbstractMapSection<?>) {
|
||||
list.add(((AbstractMapSection<?>) obj).asMap());
|
||||
} else {
|
||||
list.add(obj);
|
||||
}
|
||||
}
|
||||
output.put(entry.getKey(), list);
|
||||
} else {
|
||||
output.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
@@ -98,6 +109,11 @@ public abstract class AbstractMapSection<R extends AbstractMapSection<R>> implem
|
||||
return Collections.unmodifiableMap(deep ? mappingValues(this, null, true, String.valueOf(pathSeparator())) : data());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
|
||||
return Collections.unmodifiableSet(deep ? mappingKeys(this, null, true, String.valueOf(pathSeparator())) : data().keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(@NotNull String path, @Nullable Object value) {
|
||||
if (value instanceof Map) value = createSection(path, (Map<?, ?>) value);
|
||||
@@ -157,5 +173,17 @@ public abstract class AbstractMapSection<R extends AbstractMapSection<R>> implem
|
||||
return output;
|
||||
}
|
||||
|
||||
protected static Set<String> mappingKeys(@NotNull AbstractMapSection<?> section, @Nullable String parent, boolean deep, String pathSeparator) {
|
||||
Set<String> keys = new LinkedHashSet<>();
|
||||
for (Map.Entry<String, Object> entry : section.data().entrySet()) {
|
||||
String path = (parent == null ? "" : parent + pathSeparator) + entry.getKey();
|
||||
keys.add(path);
|
||||
if (deep && entry.getValue() instanceof AbstractMapSection<?>) {
|
||||
keys.addAll(mappingKeys((AbstractMapSection<?>) entry.getValue(), path, true, pathSeparator));
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+77
-71
@@ -20,13 +20,18 @@ public class ImmutableSection implements ConfigureSection {
|
||||
}
|
||||
|
||||
protected final @Nullable ImmutableSection parent;
|
||||
protected final @NotNull ConfigureSection section;
|
||||
protected final @NotNull ConfigureSection raw;
|
||||
|
||||
private ImmutableSection(@Nullable ImmutableSection parent, @NotNull ConfigureSection section) {
|
||||
private ImmutableSection(@Nullable ImmutableSection parent, @NotNull ConfigureSection raw) {
|
||||
this.parent = parent;
|
||||
this.section = section;
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
private @NotNull ConfigureSection raw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public @Nullable ImmutableSection parent() {
|
||||
return this.parent;
|
||||
@@ -34,16 +39,12 @@ public class ImmutableSection implements ConfigureSection {
|
||||
|
||||
@Override
|
||||
public @NotNull String path() {
|
||||
return section().path();
|
||||
}
|
||||
|
||||
private @NotNull ConfigureSection section() {
|
||||
return section;
|
||||
return raw().path();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull @UnmodifiableView Map<String, Object> getValues(boolean deep) {
|
||||
return section().getValues(deep);
|
||||
return raw().getValues(deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,12 +59,12 @@ public class ImmutableSection implements ConfigureSection {
|
||||
|
||||
@Override
|
||||
public @NotNull ImmutableSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||
return new ImmutableSection(this, section().createSection(path, data));
|
||||
return new ImmutableSection(this, raw().createSection(path, data));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Object get(@NotNull String path) {
|
||||
Object value = section().get(path);
|
||||
Object value = raw().get(path);
|
||||
if (value instanceof ConfigureSection && !(value instanceof ImmutableSection)) {
|
||||
return new ImmutableSection(this, (ConfigureSection) value);
|
||||
}
|
||||
@@ -72,7 +73,7 @@ public class ImmutableSection implements ConfigureSection {
|
||||
|
||||
@Override
|
||||
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
||||
ConfigureSection get = section().getSection(path);
|
||||
ConfigureSection get = raw().getSection(path);
|
||||
if (get != null && !(get instanceof ImmutableSection)) {
|
||||
return new ImmutableSection(this, get);
|
||||
}
|
||||
@@ -81,297 +82,302 @@ public class ImmutableSection implements ConfigureSection {
|
||||
|
||||
@Override
|
||||
public char pathSeparator() {
|
||||
return section().pathSeparator();
|
||||
return raw().pathSeparator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRoot() {
|
||||
return section().isRoot();
|
||||
return raw().isRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return section().isEmpty();
|
||||
return raw().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
|
||||
return section().getKeys(deep);
|
||||
return raw().getKeys(deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull @UnmodifiableView Set<String> keys() {
|
||||
return section().keys();
|
||||
return raw().keys();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull @UnmodifiableView Map<String, Object> values() {
|
||||
return section().values();
|
||||
return raw().values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull @UnmodifiableView Map<String, Object> asMap() {
|
||||
return raw().asMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<Map.Entry<String, Object>> stream() {
|
||||
return section().stream();
|
||||
return raw().stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(@NotNull BiConsumer<String, Object> action) {
|
||||
section().forEach(action);
|
||||
raw().forEach(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(@NotNull String path) {
|
||||
return section().contains(path);
|
||||
return raw().contains(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(@NotNull String path) {
|
||||
return section().containsValue(path);
|
||||
return raw().containsValue(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) {
|
||||
return section().isType(path, typeClass);
|
||||
return raw().isType(path, typeClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isList(@NotNull String path) {
|
||||
return section().isList(path);
|
||||
return raw().isList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable List<?> getList(@NotNull String path) {
|
||||
return section().getList(path);
|
||||
return raw().getList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSection(@NotNull String path) {
|
||||
return section().isSection(path);
|
||||
return raw().isSection(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @Nullable T get(@NotNull String path, @NotNull Class<T> type) {
|
||||
return section().get(path, type);
|
||||
return raw().get(path, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @Nullable T get(@NotNull String path, @NotNull DataFunction<@Nullable Object, T> parser) {
|
||||
return section().get(path, parser);
|
||||
return raw().get(path, parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @Nullable T get(@NotNull String path, @Nullable T defaults, @NotNull Class<T> clazz) {
|
||||
return section().get(path, defaults, clazz);
|
||||
return raw().get(path, defaults, clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @Nullable T get(@NotNull String path, @Nullable T defaultValue, @NotNull DataFunction<Object, T> parser) {
|
||||
return section().get(path, defaultValue, parser);
|
||||
return raw().get(path, defaultValue, parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBoolean(@NotNull String path) {
|
||||
return section().isBoolean(path);
|
||||
return raw().isBoolean(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(@NotNull String path) {
|
||||
return section().getBoolean(path);
|
||||
return raw().getBoolean(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
|
||||
return section().getBoolean(path, def);
|
||||
return raw().getBoolean(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Boolean isByte(@NotNull String path) {
|
||||
return section().isByte(path);
|
||||
return raw().isByte(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Byte getByte(@NotNull String path) {
|
||||
return section().getByte(path);
|
||||
return raw().getByte(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
|
||||
return section().getByte(path, def);
|
||||
return raw().getByte(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShort(@NotNull String path) {
|
||||
return section().isShort(path);
|
||||
return raw().isShort(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Short getShort(@NotNull String path) {
|
||||
return section().getShort(path);
|
||||
return raw().getShort(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
|
||||
return section().getShort(path, def);
|
||||
return raw().getShort(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInt(@NotNull String path) {
|
||||
return section().isInt(path);
|
||||
return raw().isInt(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Integer getInt(@NotNull String path) {
|
||||
return section().getInt(path);
|
||||
return raw().getInt(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
|
||||
return section().getInt(path, def);
|
||||
return raw().getInt(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLong(@NotNull String path) {
|
||||
return section().isLong(path);
|
||||
return raw().isLong(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Long getLong(@NotNull String path) {
|
||||
return section().getLong(path);
|
||||
return raw().getLong(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
|
||||
return section().getLong(path, def);
|
||||
return raw().getLong(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFloat(@NotNull String path) {
|
||||
return section().isFloat(path);
|
||||
return raw().isFloat(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Float getFloat(@NotNull String path) {
|
||||
return section().getFloat(path);
|
||||
return raw().getFloat(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
|
||||
return section().getFloat(path, def);
|
||||
return raw().getFloat(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDouble(@NotNull String path) {
|
||||
return section().isDouble(path);
|
||||
return raw().isDouble(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Double getDouble(@NotNull String path) {
|
||||
return section().getDouble(path);
|
||||
return raw().getDouble(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
|
||||
return section().getDouble(path, def);
|
||||
return raw().getDouble(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChar(@NotNull String path) {
|
||||
return section().isChar(path);
|
||||
return raw().isChar(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Character getChar(@NotNull String path) {
|
||||
return section().getChar(path);
|
||||
return raw().getChar(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Character getChar(@NotNull String path, @Nullable Character def) {
|
||||
return section().getChar(path, def);
|
||||
return raw().getChar(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isString(@NotNull String path) {
|
||||
return section().isString(path);
|
||||
return raw().isString(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getString(@NotNull String path) {
|
||||
return section().getString(path);
|
||||
return raw().getString(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getString(@NotNull String path, @Nullable String def) {
|
||||
return section().getString(path, def);
|
||||
return raw().getString(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <V> List<V> getList(@NotNull String path, @NotNull DataFunction<Object, V> parser) {
|
||||
return section().getList(path, parser);
|
||||
return raw().getList(path, parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<String> getStringList(@NotNull String path) {
|
||||
return section().getStringList(path);
|
||||
return raw().getStringList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Integer> getIntegerList(@NotNull String path) {
|
||||
return section().getIntegerList(path);
|
||||
return raw().getIntegerList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Long> getLongList(@NotNull String path) {
|
||||
return section().getLongList(path);
|
||||
return raw().getLongList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Double> getDoubleList(@NotNull String path) {
|
||||
return section().getDoubleList(path);
|
||||
return raw().getDoubleList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Float> getFloatList(@NotNull String path) {
|
||||
return section().getFloatList(path);
|
||||
return raw().getFloatList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Byte> getByteList(@NotNull String path) {
|
||||
return section().getByteList(path);
|
||||
return raw().getByteList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull List<Character> getCharList(@NotNull String path) {
|
||||
return section().getCharList(path);
|
||||
return raw().getCharList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path, @NotNull Supplier<C> constructor, @NotNull DataFunction<Object, T> parser) {
|
||||
return section().getCollection(path, constructor, parser);
|
||||
return raw().getCollection(path, constructor, parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Stream<?> stream(@NotNull String path) {
|
||||
return section().stream(path);
|
||||
return raw().stream(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull <T> Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) {
|
||||
return section().stream(path, parser);
|
||||
return raw().stream(path, parser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String childPath(String path) {
|
||||
return section().childPath(path);
|
||||
return raw().childPath(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return section.hashCode();
|
||||
return raw.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return Objects.equals(section, obj);
|
||||
return Objects.equals(raw, obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
@@ -40,6 +40,12 @@ public class ShadedSection implements ConfigureSection {
|
||||
return merge(template, source).getValues(deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull @UnmodifiableView Map<String, Object> asMap() {
|
||||
if (source == null) return template.asMap();
|
||||
return merge(template, source).asMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
|
||||
Set<String> keys = new HashSet<>(template.getKeys(deep));
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.7</version>
|
||||
<version>4.0.9</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<version>4.0.7</version>
|
||||
<version>4.0.9</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
package cc.carm.lib.configuration.annotation;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
@@ -22,7 +21,7 @@ public @interface ConfigVersion {
|
||||
*
|
||||
* @return the version of the configuration field
|
||||
*/
|
||||
@Range(from = 0, to = Integer.MAX_VALUE)
|
||||
@Range(from = 0, to = 65535)
|
||||
int value() default 0;
|
||||
|
||||
}
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
package cc.carm.lib.configuration.option;
|
||||
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOption;
|
||||
|
||||
public interface VersionedOptions {
|
||||
|
||||
/**
|
||||
* Whether to set newer defaults when a {@link cc.carm.lib.configuration.value.ConfigValue}'s marked version
|
||||
* is newer than the current in storage.
|
||||
*/
|
||||
ConfigurationOption<Boolean> RESET_NEWER_DEFAULTS = ConfigurationOption.of(true);
|
||||
|
||||
}
|
||||
+13
-2
@@ -1,4 +1,4 @@
|
||||
package cc.carm.lib.configuration.commentable;
|
||||
package cc.carm.lib.configuration.versioned;
|
||||
|
||||
import cc.carm.lib.configuration.annotation.ConfigVersion;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
@@ -19,7 +19,18 @@ public interface VersionedMetaTypes {
|
||||
}
|
||||
|
||||
static void register(@NotNull ConfigurationInitializer initializer) {
|
||||
initializer.registerFieldAnnotation(ConfigVersion.class, VERSION, ConfigVersion::value);
|
||||
initializer.appendFieldInitializer((holder, path, field, value) -> {
|
||||
ConfigVersion annotation = field.getAnnotation(ConfigVersion.class);
|
||||
if (annotation == null || value == null) return;
|
||||
int currentVersion = annotation.value();
|
||||
int savedVersion = holder.metadata(path).get(VERSION, 0);
|
||||
if (currentVersion == savedVersion) return;
|
||||
|
||||
if (currentVersion > savedVersion) { // This values updated.
|
||||
value.setDefault(true); // Mark as default value, force write.
|
||||
}
|
||||
holder.metadata(path).set(VERSION, currentVersion);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>4.0.7</version>
|
||||
<version>4.0.9</version>
|
||||
<modules>
|
||||
<module>core</module>
|
||||
<module>features/section</module>
|
||||
@@ -27,8 +27,8 @@
|
||||
<module>providers/yaml</module>
|
||||
<module>providers/gson</module>
|
||||
<!-- <module>providers/hocon</module>-->
|
||||
<!-- <module>providers/sql</module>-->
|
||||
<!-- <module>providers/mongodb</module>-->
|
||||
<module>providers/sql</module>
|
||||
<module>providers/mongodb</module>
|
||||
|
||||
<module>demo</module>
|
||||
</modules>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.7</version>
|
||||
<version>4.0.9</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
+18
-10
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.0</version>
|
||||
<version>4.0.9</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
@@ -15,6 +15,7 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
|
||||
<deps.mongodb.version>5.3.1</deps.mongodb.version>
|
||||
<log4j.version>2.24.3</log4j.version>
|
||||
</properties>
|
||||
<artifactId>easyconfiguration-mongodb</artifactId>
|
||||
@@ -30,7 +31,7 @@
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-gson</artifactId>
|
||||
<artifactId>easyconfiguration-feature-section</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
@@ -38,14 +39,7 @@
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongodb-driver-sync</artifactId>
|
||||
<version>5.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-demo</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
<version>${deps.mongodb.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -69,6 +63,20 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-demo</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-gson</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package cc.carm.lib.configuration.source.mongodb;
|
||||
|
||||
import cc.carm.lib.configuration.source.ConfigurationFactory;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
import org.bson.Document;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class MongoConfigFactory extends ConfigurationFactory<MongoSource, ConfigurationHolder<MongoSource>, MongoConfigFactory> {
|
||||
|
||||
public static MongoConfigFactory from(@NotNull Supplier<MongoCollection<Document>> collectionSupplier) {
|
||||
return new MongoConfigFactory(collectionSupplier);
|
||||
}
|
||||
|
||||
public static MongoConfigFactory from(@NotNull MongoCollection<Document> collection) {
|
||||
return from(() -> collection);
|
||||
}
|
||||
|
||||
public static MongoConfigFactory from(@NotNull MongoDatabase database, @NotNull String collectionName) {
|
||||
return from(() -> database.getCollection(collectionName));
|
||||
}
|
||||
|
||||
protected @NotNull Supplier<MongoCollection<Document>> collectionSupplier;
|
||||
protected @NotNull String namespace = "config";
|
||||
|
||||
public MongoConfigFactory(@NotNull Supplier<MongoCollection<Document>> collectionSupplier) {
|
||||
super();
|
||||
this.collectionSupplier = collectionSupplier;
|
||||
}
|
||||
|
||||
public MongoConfigFactory collection(@NotNull Supplier<MongoCollection<Document>> collectionSupplier) {
|
||||
this.collectionSupplier = collectionSupplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MongoConfigFactory collection(@NotNull MongoCollection<Document> collection) {
|
||||
return collection(() -> collection);
|
||||
}
|
||||
|
||||
public MongoConfigFactory namespace(@NotNull String namespace) {
|
||||
this.namespace = namespace;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MongoConfigFactory namespace(@NotNull Supplier<String> namespace) {
|
||||
return namespace(namespace.get());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected MongoConfigFactory self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfigurationHolder<MongoSource> build() {
|
||||
MongoCollection<Document> collection = this.collectionSupplier.get();
|
||||
if (collection == null) {
|
||||
throw new IllegalStateException("Failed to get MongoCollection<Document> from supplier");
|
||||
}
|
||||
|
||||
return new ConfigurationHolder<MongoSource>(this.adapters, this.options, this.metadata, this.initializer) {
|
||||
final @NotNull MongoSource source = new MongoSource(this, System.currentTimeMillis(), collection, namespace);
|
||||
|
||||
@Override
|
||||
public @NotNull MongoSource config() {
|
||||
return this.source;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
+73
-1
@@ -1,4 +1,76 @@
|
||||
package cc.carm.lib.configuration.source.mongodb;
|
||||
|
||||
public class MongoSource {
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.source.section.ConfigureSource;
|
||||
import cc.carm.lib.configuration.source.section.SourcedSection;
|
||||
import com.mongodb.client.MongoCollection;
|
||||
import com.mongodb.client.model.ReplaceOptions;
|
||||
import org.bson.Document;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class MongoSource extends ConfigureSource<SourcedSection, Map<String, Object>, MongoSource> {
|
||||
|
||||
protected final @NotNull MongoCollection<Document> collection;
|
||||
protected final @NotNull String namespace;
|
||||
|
||||
protected SourcedSection rootSection;
|
||||
|
||||
protected MongoSource(@NotNull ConfigurationHolder<? extends MongoSource> holder, long lastUpdateMillis,
|
||||
@NotNull MongoCollection<Document> collection, @NotNull String namespace) {
|
||||
super(holder, lastUpdateMillis);
|
||||
this.collection = collection;
|
||||
this.namespace = namespace;
|
||||
try {
|
||||
onReload();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull MongoSource self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Map<String, Object> original() {
|
||||
return section().data();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull SourcedSection section() {
|
||||
return Objects.requireNonNull(rootSection, "RootSection is not initialized");
|
||||
}
|
||||
|
||||
public @NotNull String namespace() {
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
public @NotNull MongoCollection<Document> collection() {
|
||||
return this.collection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() throws Exception {
|
||||
Map<String, Object> data = this.rootSection.asMap();
|
||||
if (data.isEmpty()) return; // Skip saving if empty
|
||||
if (data.containsKey("_id") && data.size() == 1) return; // Skip saving if only contains _id
|
||||
|
||||
ReplaceOptions options = new ReplaceOptions().upsert(true);
|
||||
Document storage = new Document(data).append("_id", this.namespace);
|
||||
this.collection.replaceOne(new Document("_id", this.namespace), storage, options);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReload() throws Exception {
|
||||
Document storage = this.collection.find(new Document("_id", this.namespace)).first();
|
||||
if (storage == null) storage = new Document();
|
||||
else storage.remove("_id"); // Remove _id
|
||||
this.rootSection = SourcedSection.root(this, storage);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package config;
|
||||
|
||||
import cc.carm.lib.configuration.Configuration;
|
||||
import cc.carm.lib.configuration.value.standard.ConfiguredValue;
|
||||
|
||||
interface MongoConfig extends Configuration {
|
||||
ConfiguredValue<String> HOST = ConfiguredValue.of("127.0.0.1");
|
||||
ConfiguredValue<Integer> PORT = ConfiguredValue.of(27017);
|
||||
ConfiguredValue<String> USERNAME = ConfiguredValue.of("minecraft");
|
||||
ConfiguredValue<String> PASSWORD = ConfiguredValue.of("minecraft");
|
||||
ConfiguredValue<String> DATABASE = ConfiguredValue.of("minecraft");
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package config;
|
||||
|
||||
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
|
||||
import cc.carm.lib.configuration.source.mongodb.MongoConfigFactory;
|
||||
import com.mongodb.ConnectionString;
|
||||
import com.mongodb.MongoClientSettings;
|
||||
import com.mongodb.MongoCredential;
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.MongoClients;
|
||||
import com.mongodb.client.MongoDatabase;
|
||||
import org.bson.UuidRepresentation;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class MongoTest {
|
||||
|
||||
boolean local = false;
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
if (!local) return;
|
||||
|
||||
ConfigurationHolder<?> gsonHolder = JSONConfigFactory.from(new File("target/mongo.json")).build();
|
||||
gsonHolder.initialize(MongoConfig.class);
|
||||
|
||||
MongoClientSettings settings = MongoClientSettings.builder()
|
||||
.applyConnectionString(new ConnectionString(
|
||||
"mongodb://" + MongoConfig.HOST.resolve() + ":" + MongoConfig.PORT.resolve()
|
||||
))
|
||||
.credential(MongoCredential.createCredential(
|
||||
MongoConfig.USERNAME.resolve(), MongoConfig.DATABASE.resolve(),
|
||||
MongoConfig.PASSWORD.resolve().toCharArray()
|
||||
))
|
||||
.uuidRepresentation(UuidRepresentation.STANDARD)
|
||||
.build();
|
||||
MongoClient mongoClient = MongoClients.create(settings);
|
||||
MongoDatabase mongoDatabase = mongoClient.getDatabase(MongoConfig.DATABASE.resolve());
|
||||
|
||||
ConfigurationHolder<?> mongoHolder = MongoConfigFactory
|
||||
.from(mongoDatabase, "configs")
|
||||
.namespace("my_plugin")
|
||||
.build();
|
||||
|
||||
// Test the configuration
|
||||
ConfigurationTest.testDemo(mongoHolder);
|
||||
ConfigurationTest.testInner(mongoHolder);
|
||||
|
||||
ConfigurationTest.save(mongoHolder);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+10
-10
@@ -6,16 +6,16 @@ SQL database implementation, support for MySQL or MariaDB.
|
||||
```mysql
|
||||
CREATE TABLE IF NOT EXISTS conf
|
||||
(
|
||||
`namespace` VARCHAR(32) NOT NULL, # 命名空间 (代表其属于谁,类似于单个配置文件地址的概念)
|
||||
`path` VARCHAR(96) NOT NULL, # 配置路径 (ConfigPath)
|
||||
`type` TINYINT UNSIGNED NOT NULL DEFAULT 0, # 数据类型 (Integer/Byte/List/Map/...)
|
||||
`value` MEDIUMTEXT, # 配置项的值 (可能为JSON格式)
|
||||
`inline_comment` TEXT, # 配置项的用法,本质是行内注释
|
||||
`header_comment` MEDIUMTEXT, # 配置项的描述,本质是顶部注释
|
||||
`footer_comment` MEDIUMTEXT, # 配置项的描述,本质是顶部注释
|
||||
`version` INT UNSIGNED NOT NULL DEFAULT 0, # 配置项的版本
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, # 创建时间
|
||||
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`namespace` VARCHAR(32) NOT NULL, # 命名空间 (代表其属于谁,类似于单个配置文件地址的概念)
|
||||
`path` VARCHAR(96) NOT NULL, # 配置路径 (ConfigPath)
|
||||
`type` TINYINT UNSIGNED NOT NULL DEFAULT 0, # 数据类型 (Integer/Byte/List/Map/...)
|
||||
`value` MEDIUMTEXT, # 配置项的值 (可能为JSON格式)
|
||||
`inline_comment` TEXT comment 'usage', # 配置项的用法,本质是行内注释
|
||||
`header_comment` MEDIUMTEXT comment 'description', # 配置项的描述,本质是顶部注释
|
||||
`footer_comment` MEDIUMTEXT comment 'example', # 配置项的参考,本质是底部注释
|
||||
`version` MEDIUMINT UNSIGNED NOT NULL DEFAULT 0, # 配置项的版本
|
||||
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, # 创建时间
|
||||
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`namespace`, `path`)
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4;
|
||||
|
||||
+20
-5
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.0</version>
|
||||
<version>4.0.9</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -15,7 +15,8 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
|
||||
<log4j.version>2.24.3</log4j.version>
|
||||
<deps.mysql-driver.version>8.0.33</deps.mysql-driver.version>
|
||||
<deps.log4j.version>2.24.3</deps.log4j.version>
|
||||
</properties>
|
||||
<artifactId>easyconfiguration-sql</artifactId>
|
||||
|
||||
@@ -77,21 +78,35 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<version>${deps.log4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<version>${deps.log4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<version>${log4j.version}</version>
|
||||
<version>${deps.log4j.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>easyconfiguration-gson</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>${deps.mysql-driver.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package cc.carm.lib.configuration.source.sql;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.commentable.Commentable;
|
||||
import cc.carm.lib.configuration.function.DataFunction;
|
||||
import cc.carm.lib.configuration.source.ConfigurationFactory;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.versioned.VersionedMetaTypes;
|
||||
import cc.carm.lib.easysql.api.SQLManager;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Range;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class SQLConfigFactory extends ConfigurationFactory<SQLSource, ConfigurationHolder<SQLSource>, SQLConfigFactory> {
|
||||
|
||||
public static SQLConfigFactory from(@NotNull Supplier<@NotNull SQLManager> managerSupplier) {
|
||||
return new SQLConfigFactory(managerSupplier);
|
||||
}
|
||||
|
||||
public static SQLConfigFactory from(@NotNull SQLManager manager) {
|
||||
return from(() -> manager);
|
||||
}
|
||||
|
||||
protected @NotNull Supplier<SQLManager> managerSupplier;
|
||||
protected Supplier<Gson> gsonSupplier = () -> SQLSource.DEFAULT_GSON;
|
||||
|
||||
protected HashMap<Integer, SQLValueResolver<?>> resolvers = new HashMap<>(SQLValueResolver.STANDARD_RESOLVERS);
|
||||
protected String tableName = "configs";
|
||||
protected String namespace = "default";
|
||||
|
||||
public SQLConfigFactory(@NotNull Supplier<SQLManager> managerSupplier) {
|
||||
this.managerSupplier = managerSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLConfigFactory self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public SQLConfigFactory manager(@NotNull Supplier<SQLManager> managerSupplier) {
|
||||
this.managerSupplier = managerSupplier;
|
||||
return self();
|
||||
}
|
||||
|
||||
public SQLConfigFactory manager(@NotNull SQLManager manager) {
|
||||
return manager(() -> manager);
|
||||
}
|
||||
|
||||
public SQLConfigFactory gson(@NotNull Supplier<Gson> gsonSupplier) {
|
||||
this.gsonSupplier = gsonSupplier;
|
||||
return self();
|
||||
}
|
||||
|
||||
public SQLConfigFactory gson(@NotNull Consumer<GsonBuilder> builder) {
|
||||
return gson(() -> {
|
||||
GsonBuilder gsonBuilder = new GsonBuilder();
|
||||
builder.accept(gsonBuilder);
|
||||
return gsonBuilder.create();
|
||||
});
|
||||
}
|
||||
|
||||
public SQLConfigFactory gson(@NotNull Gson gson) {
|
||||
return gson(() -> gson);
|
||||
}
|
||||
|
||||
public SQLConfigFactory resolver(@Range(from = 0, to = 255) int type, @NotNull SQLValueResolver<?> resolver) {
|
||||
this.resolvers.put(type, resolver);
|
||||
return self();
|
||||
}
|
||||
|
||||
public <T> SQLConfigFactory resolver(@Range(from = 0, to = 255) int id, @NotNull Class<T> clazz,
|
||||
@NotNull DataFunction<String, T> parser) {
|
||||
return resolver(id, ValueType.of(clazz), parser);
|
||||
}
|
||||
|
||||
public <T> SQLConfigFactory resolver(@Range(from = 0, to = 255) int id, @NotNull ValueType<T> type,
|
||||
@NotNull DataFunction<String, T> parser) {
|
||||
return resolver(id, SQLValueResolver.of(type, parser));
|
||||
}
|
||||
|
||||
public <T> SQLConfigFactory resolver(@Range(from = 0, to = 255) int id, @NotNull Class<T> clazz,
|
||||
@NotNull DataFunction<String, T> parser,
|
||||
@NotNull DataFunction<T, String> serializer) {
|
||||
return resolver(id, ValueType.of(clazz), parser, serializer);
|
||||
}
|
||||
|
||||
public <T> SQLConfigFactory resolver(@Range(from = 0, to = 255) int id, @NotNull ValueType<T> type,
|
||||
@NotNull DataFunction<String, T> parser,
|
||||
@NotNull DataFunction<T, String> serializer) {
|
||||
return resolver(id, SQLValueResolver.of(type, parser, serializer));
|
||||
}
|
||||
|
||||
public SQLConfigFactory tableName(@NotNull String tableName) {
|
||||
this.tableName = tableName;
|
||||
return self();
|
||||
}
|
||||
|
||||
public SQLConfigFactory namespace(@NotNull String namespace) {
|
||||
this.namespace = namespace;
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ConfigurationHolder<SQLSource> build() {
|
||||
Gson gson = gsonSupplier.get();
|
||||
if (gson == null) throw new NullPointerException("No Gson instance provided.");
|
||||
|
||||
SQLManager manager = this.managerSupplier.get();
|
||||
if (manager == null) throw new NullPointerException("No SQLManager instance provided.");
|
||||
|
||||
Commentable.registerMeta(this.initializer);
|
||||
VersionedMetaTypes.register(this.initializer);
|
||||
|
||||
return new ConfigurationHolder<SQLSource>(this.adapters, this.options, this.metadata, this.initializer) {
|
||||
final SQLSource source = new SQLSource(
|
||||
this, System.currentTimeMillis(),
|
||||
gson, manager, resolvers, tableName, namespace
|
||||
);
|
||||
|
||||
@Override
|
||||
public @NotNull SQLSource config() {
|
||||
return source;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,12 @@
|
||||
package cc.carm.lib.configuration.source.sql;
|
||||
|
||||
import cc.carm.lib.configuration.source.option.ConfigurationOption;
|
||||
|
||||
public interface SQLOptions {
|
||||
|
||||
/**
|
||||
* Whether to purge the configuration's in-database data when saving.
|
||||
*/
|
||||
ConfigurationOption<Boolean> PURGE = ConfigurationOption.of( true);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,53 +1,62 @@
|
||||
package cc.carm.lib.configuration.source.sql;
|
||||
|
||||
import cc.carm.lib.configuration.commentable.Commentable;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.source.section.ConfigureSource;
|
||||
import cc.carm.lib.configuration.source.section.MemorySection;
|
||||
import cc.carm.lib.configuration.source.section.SourcedSection;
|
||||
import cc.carm.lib.configuration.value.ConfigValue;
|
||||
import cc.carm.lib.configuration.versioned.VersionedMetaTypes;
|
||||
import cc.carm.lib.easysql.api.SQLManager;
|
||||
import cc.carm.lib.easysql.api.SQLQuery;
|
||||
import cc.carm.lib.easysql.api.SQLTable;
|
||||
import cc.carm.lib.easysql.api.enums.IndexType;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
public class SQLSource extends ConfigureSource<MemorySection, Map<?, ?>, SQLSource> {
|
||||
public class SQLSource extends ConfigureSource<SourcedSection, Map<String, Object>, SQLSource> {
|
||||
|
||||
protected static final @NotNull Gson DEFAULT_GSON = new GsonBuilder()
|
||||
.serializeNulls().disableHtmlEscaping().setPrettyPrinting()
|
||||
.create();
|
||||
.serializeNulls().disableHtmlEscaping().create();
|
||||
|
||||
protected final @NotNull Gson gson;
|
||||
protected final @NotNull SQLManager sqlManager;
|
||||
protected final @NotNull String namespace;
|
||||
protected final @NotNull SQLTable table;
|
||||
|
||||
protected final @NotNull Set<String> updated = new HashSet<>();
|
||||
protected MemorySection rootSection;
|
||||
protected final @NotNull Map<Integer, SQLValueResolver<?>> resolvers;
|
||||
protected SourcedSection rootSection;
|
||||
|
||||
public SQLSource(@NotNull ConfigurationHolder<? extends SQLSource> holder, long lastUpdateMillis,
|
||||
@NotNull Gson gson, @NotNull SQLManager sqlManager, @NotNull String tableName, @NotNull String namespace) {
|
||||
@NotNull Gson gson, @NotNull SQLManager sqlManager,
|
||||
@NotNull Map<Integer, SQLValueResolver<?>> resolvers,
|
||||
@NotNull String tableName, @NotNull String namespace) {
|
||||
super(holder, lastUpdateMillis);
|
||||
this.gson = gson;
|
||||
this.sqlManager = sqlManager;
|
||||
this.resolvers = resolvers;
|
||||
this.namespace = namespace;
|
||||
this.table = SQLTable.of(tableName, builder -> {
|
||||
|
||||
builder.addColumn("namespace", "VARCHAR(32) NOT NULL");
|
||||
builder.addColumn("path", "VARCHAR(96) NOT NULL");
|
||||
|
||||
builder.addColumn("type", "TINYINT NOT NULL DEFAULT 0");
|
||||
builder.addColumn("value", "TEXT");
|
||||
|
||||
builder.addColumn("inline_comment", "TEXT");
|
||||
builder.addColumn("header_comments", "MEDIUMTEXT");
|
||||
builder.addColumn("footer_comments", "MEDIUMTEXT");
|
||||
|
||||
builder.addColumn("type", "TINYINT NOT NULL DEFAULT 0");
|
||||
builder.addColumn("version", "MEDIUMINT UNSIGNED NOT NULL DEFAULT 0");
|
||||
|
||||
builder.addColumn("create_time", "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
|
||||
builder.addColumn("update_time", "TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
|
||||
builder.addColumn("create_time", "TIMESTAMP NOT NULL");
|
||||
builder.addColumn("update_time", "TIMESTAMP NOT NULL");
|
||||
|
||||
builder.setIndex(
|
||||
IndexType.PRIMARY_KEY, "pk_" + tableName.toLowerCase(),
|
||||
@@ -55,82 +64,134 @@ public class SQLSource extends ConfigureSource<MemorySection, Map<?, ?>, SQLSour
|
||||
);
|
||||
builder.setTableSettings("ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
|
||||
});
|
||||
|
||||
try {
|
||||
this.table.create(this.sqlManager);
|
||||
onReload();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLSource self() {
|
||||
protected @NotNull SQLSource self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Gson gson() {
|
||||
return gson;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Map<?, ?> original() {
|
||||
public @NotNull Map<String, Object> original() {
|
||||
return section().data();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull MemorySection section() {
|
||||
public @NotNull SourcedSection section() {
|
||||
return Objects.requireNonNull(this.rootSection, "Root section is not initialized.");
|
||||
}
|
||||
|
||||
public int purge() throws Exception {
|
||||
return this.table.createDelete().addCondition("namespace", namespace).build().execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() throws Exception {
|
||||
if (this.updated.isEmpty()) return; // Nothing to save
|
||||
LocalDateTime time = LocalDateTime.now(); // Update time
|
||||
List<Object[]> dataValues = new ArrayList<>();
|
||||
|
||||
Date date = new Date(); // Update time
|
||||
List<Object[]> values = new ArrayList<>();
|
||||
SourcedSection section = section();
|
||||
Map<String, ConfigValue<?>> values = holder().registeredValues();
|
||||
for (Map.Entry<String, ConfigValue<?>> entry : values.entrySet()) {
|
||||
@NotNull String path = entry.getKey();
|
||||
@NotNull ConfigValue<?> config = entry.getValue();
|
||||
@Nullable Object value = section.get(path);
|
||||
|
||||
for (String path : this.updated) {
|
||||
Object value = get(path);
|
||||
if (value instanceof SourcedSection) {
|
||||
value = ((SourcedSection) value).asMap();
|
||||
} else if (value instanceof List<?>) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
for (Object obj : (List<?>) value) {
|
||||
if (obj instanceof SourcedSection) {
|
||||
list.add(((SourcedSection) obj).asMap());
|
||||
} else {
|
||||
list.add(obj);
|
||||
}
|
||||
}
|
||||
value = list;
|
||||
}
|
||||
|
||||
// if (value instanceof SQLConfigWrapper) {
|
||||
// value = getSourceMap(((SQLConfigWrapper) value).getSource());
|
||||
// }
|
||||
//
|
||||
// SQLValueResolver<?> type = SQLValueTypes.get(value.getClass());
|
||||
// if (type != null) {
|
||||
// values.add(new Object[]{
|
||||
// this.namespace, path, date,
|
||||
// type.getID(), type.serializeObject(value),
|
||||
// getComments().getInlineComment(path),
|
||||
// GSON.toJson(getComments().getHeaderComment(path))
|
||||
// });
|
||||
// }
|
||||
if (value == null) continue;
|
||||
|
||||
try {
|
||||
int typeID = typeIdOf(value);
|
||||
String data = serialize(typeID, value);
|
||||
if (data == null) continue;
|
||||
|
||||
int version = holder().metadata(path).get(VersionedMetaTypes.VERSION, 0);
|
||||
dataValues.add(new Object[]{
|
||||
namespace, path, time, version, typeID, data,
|
||||
Commentable.getInlineComment(holder(), path),
|
||||
gson.toJson(Commentable.getHeaderComments(holder(), path)),
|
||||
gson.toJson(Commentable.getFooterComments(holder(), path))
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
this.updated.clear();
|
||||
|
||||
if (holder.option(SQLOptions.PURGE)) {
|
||||
purge();
|
||||
}
|
||||
this.table.createReplaceBatch()
|
||||
.setColumnNames("namespace", "path", "update_time", "type", "value", "inline_comment", "header_comments")
|
||||
.setAllParams(values)
|
||||
.execute();
|
||||
.setColumnNames(
|
||||
"namespace", "path", "update_time", "version", "type", "value",
|
||||
"inline_comment", "header_comments", "footer_comments"
|
||||
).setAllParams(dataValues).execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReload() throws Exception {
|
||||
LinkedHashMap<String, Object> values = new LinkedHashMap<>();
|
||||
|
||||
// try (SQLQuery query = this.table.createQuery()
|
||||
// .addCondition("namespace", namespace)
|
||||
// .build().execute()) {
|
||||
// ResultSet rs = query.getResultSet();
|
||||
// while (rs.next()) {
|
||||
// String path = rs.getString("path");
|
||||
// int type = rs.getInt("type");
|
||||
// try {
|
||||
// SQLValueResolver<?> resolver = SQLValueTypes.get(type);
|
||||
// if (resolver == null) throw new IllegalStateException("No resolver for type #" + type);
|
||||
// String value = rs.getString("value");
|
||||
// values.put(path, resolver.resolve(value));
|
||||
//
|
||||
// loadInlineComment(path, rs.getString("inline_comment"));
|
||||
// loadHeaderComment(path, rs.getString("header_comments"));
|
||||
// } catch (Exception ex) {
|
||||
// ex.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// this.rootConfiguration = new SQLConfigWrapper(this, values);
|
||||
Map<String, Object> loaded = new LinkedHashMap<>();
|
||||
try (SQLQuery query = this.table.createQuery()
|
||||
.addCondition("namespace", namespace)
|
||||
.build().execute()) {
|
||||
ResultSet rs = query.getResultSet();
|
||||
while (rs.next()) {
|
||||
String path = rs.getString("path");
|
||||
if (path == null) continue; // Path should be not null
|
||||
int ver = rs.getInt("version");
|
||||
try {
|
||||
loaded.put(path, parse(rs.getInt("type"), rs.getString("value")));
|
||||
if (ver != 0) holder().metadata(path).set(VersionedMetaTypes.VERSION, ver);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
this.rootSection = SourcedSection.root(this, loaded);
|
||||
}
|
||||
|
||||
|
||||
protected @Nullable Object parse(int type, String value) throws Exception {
|
||||
SQLValueResolver<?> function = this.resolvers.get(type);
|
||||
if (function == null) throw new IllegalStateException("No resolvers for type #" + type);
|
||||
return function.resolve(this, value);
|
||||
}
|
||||
|
||||
protected @Nullable String serialize(int type, @NotNull Object value) throws Exception {
|
||||
SQLValueResolver<?> function = this.resolvers.get(type);
|
||||
if (function == null) throw new IllegalStateException("No resolvers for type #" + type);
|
||||
return function.serialize(this, value);
|
||||
}
|
||||
|
||||
protected int typeIdOf(@NotNull Object value) {
|
||||
return this.resolvers.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().isInstance(value))
|
||||
.findFirst().map(Map.Entry::getKey)
|
||||
.orElseThrow(() -> new IllegalStateException("No resolvers for value " + value.getClass().getName()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
package cc.carm.lib.configuration.source.sql;
|
||||
|
||||
import cc.carm.lib.configuration.adapter.ValueType;
|
||||
import cc.carm.lib.configuration.function.DataFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class SQLValueResolver<T> {
|
||||
|
||||
public static final @NotNull SQLValueResolver<String> STRING = SQLValueResolver.of(ValueType.STRING, s -> s);
|
||||
public static final @NotNull SQLValueResolver<Byte> BYTE = SQLValueResolver.of(ValueType.BYTE, Byte::parseByte);
|
||||
public static final @NotNull SQLValueResolver<Short> SHORT = SQLValueResolver.of(ValueType.SHORT, Short::parseShort);
|
||||
public static final @NotNull SQLValueResolver<Integer> INTEGER = SQLValueResolver.of(ValueType.INTEGER, Integer::parseInt);
|
||||
public static final @NotNull SQLValueResolver<Long> LONG = SQLValueResolver.of(ValueType.LONG, Long::parseLong);
|
||||
public static final @NotNull SQLValueResolver<Float> FLOAT = SQLValueResolver.of(ValueType.FLOAT, Float::parseFloat);
|
||||
public static final @NotNull SQLValueResolver<Double> DOUBLE = SQLValueResolver.of(ValueType.DOUBLE, Double::parseDouble);
|
||||
public static final @NotNull SQLValueResolver<Boolean> BOOLEAN = SQLValueResolver.of(ValueType.BOOLEAN, Boolean::parseBoolean);
|
||||
public static final @NotNull SQLValueResolver<Character> CHAR = SQLValueResolver.of(ValueType.CHAR, s -> s.charAt(0));
|
||||
|
||||
public static final @NotNull SQLValueResolver<List<?>> LIST = new SQLValueResolver<List<?>>(new ValueType<List<?>>() {
|
||||
}) {
|
||||
@Override
|
||||
public @Nullable List<?> resolve(@NotNull SQLSource source, String data) throws Exception {
|
||||
return source.gson().fromJson(data, List.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String serialize(@NotNull SQLSource source, Object value) {
|
||||
return source.gson().toJson(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final @NotNull SQLValueResolver<Map<?, ?>> MAP = new SQLValueResolver<Map<?, ?>>(new ValueType<Map<?, ?>>() {
|
||||
}) {
|
||||
@Override
|
||||
public @Nullable Map<?, ?> resolve(@NotNull SQLSource source, String data) throws Exception {
|
||||
return source.gson().fromJson(data, LinkedHashMap.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String serialize(@NotNull SQLSource source, Object value) {
|
||||
return source.gson().toJson(value);
|
||||
}
|
||||
};
|
||||
|
||||
public static final @NotNull Map<Integer, SQLValueResolver<?>> STANDARD_RESOLVERS = Collections.unmodifiableMap(standards());
|
||||
|
||||
static Map<Integer, SQLValueResolver<?>> standards() {
|
||||
Map<Integer, SQLValueResolver<?>> map = new LinkedHashMap<>();
|
||||
map.put(0, STRING);
|
||||
map.put(1, BYTE);
|
||||
map.put(2, SHORT);
|
||||
map.put(3, INTEGER);
|
||||
map.put(4, LONG);
|
||||
map.put(5, FLOAT);
|
||||
map.put(6, DOUBLE);
|
||||
map.put(7, BOOLEAN);
|
||||
map.put(8, CHAR);
|
||||
map.put(10, LIST);
|
||||
map.put(11, MAP);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <V> SQLValueResolver<V> of(@NotNull ValueType<V> type, @NotNull DataFunction<String, V> resolver) {
|
||||
return new SQLValueResolver<V>(type) {
|
||||
@Override
|
||||
public @NotNull V resolve(@NotNull SQLSource source, String data) throws Exception {
|
||||
return resolver.handle(data);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <V> SQLValueResolver<V> of(@NotNull ValueType<V> type,
|
||||
@NotNull DataFunction<String, V> resolver,
|
||||
@NotNull DataFunction<V, String> serializer) {
|
||||
return new SQLValueResolver<V>(type) {
|
||||
@Override
|
||||
public @NotNull V resolve(@NotNull SQLSource source, String data) throws Exception {
|
||||
return resolver.handle(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String serialize(@NotNull SQLSource source, Object value) throws Exception {
|
||||
return serializer.handle(type.cast(value));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
protected final @NotNull ValueType<T> type;
|
||||
|
||||
protected SQLValueResolver(@NotNull ValueType<T> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public @NotNull ValueType<T> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public boolean isInstance(@NotNull Object obj) {
|
||||
return getType().isInstance(obj);
|
||||
}
|
||||
|
||||
public abstract @Nullable T resolve(@NotNull SQLSource source, String data) throws Exception;
|
||||
|
||||
public @Nullable String serialize(@NotNull SQLSource source, Object value) throws Exception {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,27 +1,48 @@
|
||||
package config;
|
||||
|
||||
import cc.carm.lib.configuration.demo.DatabaseConfiguration;
|
||||
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
import cc.carm.lib.configuration.source.json.JSONConfigFactory;
|
||||
import cc.carm.lib.configuration.source.sql.SQLConfigFactory;
|
||||
import cc.carm.lib.easysql.EasySQL;
|
||||
import cc.carm.lib.easysql.api.SQLManager;
|
||||
import cc.carm.lib.easysql.beecp.BeeDataSourceConfig;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class SQLConfigTest {
|
||||
|
||||
boolean local = false;
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
if (!local) return;
|
||||
|
||||
ConfigurationHolder<?> gsonHolder = JSONConfigFactory.from(new File("target/sql.json")).build();
|
||||
gsonHolder.initialize(DatabaseConfiguration.class);
|
||||
|
||||
BeeDataSourceConfig config = new BeeDataSourceConfig();
|
||||
config.setDriverClassName("org.h2.Driver");
|
||||
config.setJdbcUrl("jdbc:h2:file:target/test;DB_CLOSE_DELAY=-1;MODE=MySQL;");
|
||||
config.setDriverClassName(DatabaseConfiguration.DRIVER_NAME.resolve());
|
||||
config.setJdbcUrl(DatabaseConfiguration.buildJDBC());
|
||||
config.setUsername(DatabaseConfiguration.USERNAME.resolve());
|
||||
config.setPassword(DatabaseConfiguration.PASSWORD.resolve());
|
||||
|
||||
SQLManager manager = EasySQL.createManager(config);
|
||||
manager.setDebugMode(true);
|
||||
|
||||
// SQLConfigProvider provider = EasyConfiguration.from(manager, "conf_test", "TESTING");
|
||||
//
|
||||
// ConfigurationTest.testDemo(provider);
|
||||
// ConfigurationTest.testInner(provider);
|
||||
//
|
||||
// ConfigurationTest.save(provider);
|
||||
//
|
||||
// EasySQL.shutdownManager(manager);
|
||||
ConfigurationHolder<?> holder = SQLConfigFactory.from(manager)
|
||||
.tableName("test_configs")
|
||||
.namespace("testing")
|
||||
.build();
|
||||
|
||||
ConfigurationTest.testDemo(holder);
|
||||
ConfigurationTest.testInner(holder);
|
||||
|
||||
ConfigurationTest.save(holder);
|
||||
|
||||
EasySQL.shutdownManager(manager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<artifactId>easyconfiguration-parent</artifactId>
|
||||
<groupId>cc.carm.lib</groupId>
|
||||
<version>4.0.7</version>
|
||||
<version>4.0.9</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<properties>
|
||||
@@ -14,7 +14,7 @@
|
||||
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
|
||||
<deps.yamlcommentwriter.version>1.2.0</deps.yamlcommentwriter.version>
|
||||
<deps.yamlcommentwriter.version>1.2.1</deps.yamlcommentwriter.version>
|
||||
</properties>
|
||||
|
||||
<artifactId>easyconfiguration-yaml</artifactId>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package yaml.test;
|
||||
|
||||
import cc.carm.lib.configuration.commentable.Commentable;
|
||||
import cc.carm.lib.configuration.commentable.CommentableMeta;
|
||||
import cc.carm.lib.configuration.demo.tests.ConfigurationTest;
|
||||
import cc.carm.lib.configuration.source.ConfigurationHolder;
|
||||
@@ -21,7 +22,6 @@ public class YamlTests {
|
||||
ConfigurationTest.testDemo(holder);
|
||||
ConfigurationTest.testInner(holder);
|
||||
|
||||
|
||||
Map<String, List<String>> headers = holder.extractMetadata(CommentableMeta.HEADER);
|
||||
System.out.println("Header comments: ");
|
||||
headers.forEach((k, v) -> {
|
||||
|
||||
Reference in New Issue
Block a user