1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-04 18:48:20 +08:00

Compare commits

...

6 Commits

28 changed files with 581 additions and 138 deletions
+39 -15
View File
@@ -49,41 +49,58 @@ Check out all code demonstrations [HERE](demo/src/main/java/cc/carm/lib/configur
For more examples, see the [Development Guide](.doc/README.md). For more examples, see the [Development Guide](.doc/README.md).
```java ```java
@HeaderComment("Configurations for sample") @ConfigPath(root = true)
interface SampleConfig extends Configuration { @HeaderComments("Configurations for sample")
public interface SampleConfig extends Configuration {
@InlineComment("Enabled?") // Inline comment @InlineComment("Enabled?") // Inline comment
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true); ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
@HeaderComments("Server configurations") // Header comment
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class);
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
@FooterComments("[ UUID >-----------------------------------")
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString() ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
.parseValue(UUID::fromString).serializeValue(UUID::toString) .parse(UUID::fromString).serialize(UUID::toString)
.defaults( .defaults(
UUID.fromString("00000000-0000-0000-0000-000000000000"), UUID.fromString("00000000-0000-0000-0000-000000000000"),
UUID.fromString("00000000-0000-0000-0000-000000000001") UUID.fromString("00000000-0000-0000-0000-000000000001")
).build(); ).build();
@ConfigPath("info") // Custom path
interface INFO extends Configuration { interface INFO extends Configuration {
@HeaderComment("Configure your name!") // Header comment @HeaderComments("Configure your name!") // Header comment
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker"); ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
@ConfigPath("year") // Custom path @ConfigPath("how-old-are-you") // Custom path
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24); ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
} }
} }
``` ```
```java ```java
public class Sample { public class Sample {
public static void main(String[] args) { public static void main(String[] args) {
// 1. Make a configuration provider from a file. // 1. Make a configuration provider from a file.
ConfigurationProvider<?> provider = EasyConfiguration.from("config.yml"); ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml")
.resourcePath("configs/sample.yml")
.indent(4) // Optional: Set the indentation of the configuration file.
.build();
// 2. Initialize the configuration classes or instances. // 2. Initialize the configuration classes or instances.
provider.initialize(SampleConfig.class); holder.initialize(SampleConfig.class);
// 3. Enjoy using the configuration! // 3. Enjoy using the configuration!
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve());
SampleConfig.ENABLED.set(false); SampleConfig.ENABLED.set(false);
System.out.println("Your name is " + SampleConfig.INFO.NAME.getNotNull() + " !"); System.out.println("And now? -> " + SampleConfig.ENABLED.resolve());
// p.s. Changes not save so enable value will still be true in the next run.
System.out.println("Your name is " + SampleConfig.INFO.NAME.resolve() + " (age=" + SampleConfig.INFO.AGE.resolve() + ")!");
} }
} }
@@ -92,16 +109,22 @@ public class Sample {
```yaml ```yaml
# Configurations for sample # Configurations for sample
enabled: true # Enabled? enabled: true #Enabled?
# Server configurations
port:
# [ UUID >-----------------------------------
# A lot of UUIDs
uuids: uuids:
- 00000000-0000-0000-0000-000000000000 - 00000000-0000-0000-0000-000000000000
- 00000000-0000-0000-0000-000000000001 - 00000000-0000-0000-0000-000000000001
# [ UUID >-----------------------------------
info: info:
# Configure your name! # Configure your name!
name: Joker name: Joker
year: 24 how-old-are-you: 24
``` ```
### Dependencies ### Dependencies
@@ -159,10 +182,10 @@ info:
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<!-- JSON file-based implementation, compatible with all Java environments. Note: JSON does not support file comments. --> <!-- JSON file-based implementation, compatible with all Java environments. -->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-json</artifactId> <artifactId>easyconfiguration-gson</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -205,8 +228,8 @@ dependencies {
// YAML file-based implementation, compatible with all Java environments. // YAML file-based implementation, compatible with all Java environments.
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]" api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
// JSON file-based implementation, compatible with all Java environments. Note: JSON does not support file comments. // JSON file-based implementation, compatible with all Java environments.
api "cc.carm.lib:easyconfiguration-json:[LATEST RELEASE]" api "cc.carm.lib:easyconfiguration-gson:[LATEST RELEASE]"
} }
``` ```
@@ -220,7 +243,8 @@ dependencies {
EasyConfiguration for MineCraft! EasyConfiguration for MineCraft!
Easily manage configurations on MineCraft-related server platforms. Easily manage configurations on MineCraft-related server platforms.
Currently supports BungeeCord, Bukkit (Spigot) servers, with more platforms to be supported soon. Currently, it supports BungeeCord, Velocity, Bukkit (Spigot) servers,
with more platforms to be supported soon.
## Support and Donation ## Support and Donation
+37 -16
View File
@@ -43,15 +43,22 @@ README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
您可以 [点击这里](demo/src/main/java/cc/carm/lib/configuration/demo) 直接查看现有的代码演示,更多复杂情况演示详见 [开发介绍](.doc/README.md) 。 您可以 [点击这里](demo/src/main/java/cc/carm/lib/configuration/demo) 直接查看现有的代码演示,更多复杂情况演示详见 [开发介绍](.doc/README.md) 。
```java
@HeaderComment("Configurations for sample")
interface SampleConfig extends Configuration {
@InlineComment("Enabled?") // 行内注释 ```java
@ConfigPath(root = true)
@HeaderComments("Configurations for sample")
public interface SampleConfig extends Configuration {
@InlineComment("Enabled?") // 行后注释
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true); ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
@HeaderComments("Server configurations") // 头部注释
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class);
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
@FooterComments("[ UUID >-----------------------------------")
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString() ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
.parseValue(UUID::fromString).serializeValue(UUID::toString) .parse(UUID::fromString).serialize(UUID::toString)
.defaults( .defaults(
UUID.fromString("00000000-0000-0000-0000-000000000000"), UUID.fromString("00000000-0000-0000-0000-000000000000"),
UUID.fromString("00000000-0000-0000-0000-000000000001") UUID.fromString("00000000-0000-0000-0000-000000000001")
@@ -59,26 +66,34 @@ interface SampleConfig extends Configuration {
interface INFO extends Configuration { interface INFO extends Configuration {
@HeaderComment("Configure your name!") // 头部注释 @HeaderComments("Configure your name!") // Header comment
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker"); ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
@ConfigPath("year") // 自定义配置路径,若不定义,则按照默认规则生成 @ConfigPath("how-old-are-you") // 自定义路径
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24); ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
} }
} }
``` ```
```java ```java
public class Sample { public class Sample {
public static void main(String[] args) { public static void main(String[] args) {
// 1. 生成一个 “Provider” 用于给配置类提供源配置的文件。 // 1. 生成一个 “holder” 用于给配置类提供源配置的文件。
ConfigurationProvider<?> provider = EasyConfiguration.from("config.yml"); ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml")
// 2. 通过 “Provider” 初始化配置类或配置实例。 .resourcePath("configs/sample.yml")
provider.initialize(SampleConfig.class); .indent(4) // Optional: Set the indentation of the configuration file.
.build();
// 2. 通过 “holder” 初始化配置类或配置实例。
holder.initialize(SampleConfig.class);
// 3. 现在可以享受快捷方便的配置文件使用方式了~ // 3. 现在可以享受快捷方便的配置文件使用方式了~
System.out.println("Enabled? -> " + SampleConfig.ENABLED.resolve());
SampleConfig.ENABLED.set(false); SampleConfig.ENABLED.set(false);
System.out.println("Your name is " + SampleConfig.INFO.NAME.getNotNull() + " !"); System.out.println("And now? -> " + SampleConfig.ENABLED.resolve());
// p.s. 在本示例里的更改未保存,因此启用值在下次运行中仍将为 true。
} }
} }
``` ```
@@ -86,16 +101,22 @@ public class Sample {
```yaml ```yaml
# Configurations for sample # Configurations for sample
enabled: true # Enabled? enabled: true #Enabled?
# Server configurations
port:
# [ UUID >-----------------------------------
# A lot of UUIDs
uuids: uuids:
- 00000000-0000-0000-0000-000000000000 - 00000000-0000-0000-0000-000000000000
- 00000000-0000-0000-0000-000000000001 - 00000000-0000-0000-0000-000000000001
# [ UUID >-----------------------------------
info: info:
# Configure your name! # Configure your name!
name: Joker name: Joker
year: 24 how-old-are-you: 24
``` ```
### 依赖方式 ### 依赖方式
@@ -164,7 +185,7 @@ info:
<!--需要注意的是,JSON不支持文件注释。--> <!--需要注意的是,JSON不支持文件注释。-->
<dependency> <dependency>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-json</artifactId> <artifactId>easyconfiguration-gson</artifactId>
<version>[LATEST RELEASE]</version> <version>[LATEST RELEASE]</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -225,7 +246,7 @@ dependencies {
//基于JSON文件的实现版本,可用于全部Java环境。 //基于JSON文件的实现版本,可用于全部Java环境。
//需要注意的是,JSON不支持文件注释。 //需要注意的是,JSON不支持文件注释。
api "cc.carm.lib:easyconfiguration-json:[LATEST RELEASE]" api "cc.carm.lib:easyconfiguration-gson:[LATEST RELEASE]"
api "cc.carm.lib:easyconfiguration-hocon:[LATEST RELEASE]" api "cc.carm.lib:easyconfiguration-hocon:[LATEST RELEASE]"
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.1</version> <version>4.0.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>
@@ -20,6 +20,13 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
/**
* ConfigurationFactory, used to create configuration holder.
*
* @param <SOURCE> The {@link ConfigureSource} type
* @param <HOLDER> The {@link ConfigurationHolder} type.
* @param <SELF> Self builder, for further implement support.
*/
public abstract class ConfigurationFactory< public abstract class ConfigurationFactory<
SOURCE extends ConfigureSource<?, ?, SOURCE>, SOURCE extends ConfigureSource<?, ?, SOURCE>,
HOLDER extends ConfigurationHolder<SOURCE>, HOLDER extends ConfigurationHolder<SOURCE>,
@@ -139,18 +146,39 @@ public abstract class ConfigurationFactory<
return self(); return self();
} }
/**
* Supply the base path generator for this configuration holder
*
* @param generator {@link PathGenerator}
* @return this
*/
public SELF pathGenerator(PathGenerator generator) { public SELF pathGenerator(PathGenerator generator) {
return initializer(loader -> { return initializer(loader -> {
loader.pathGenerator(generator); loader.pathGenerator(generator);
}); });
} }
/**
* Register a new annotation for metadata to the configuration loader
*
* @param annotation The {@link Annotation}
* @param metadata The {@link ConfigurationMetadata} type
* @param extractor The {@link Function} to extract the metadata from the annotation
* @param <M> The metadata type
* @param <A> The annotation type
* @return this
*/
public <M, A extends Annotation> SELF metaAnnotation(@NotNull Class<A> annotation, public <M, A extends Annotation> SELF metaAnnotation(@NotNull Class<A> annotation,
@NotNull ConfigurationMetadata<M> metadata, @NotNull ConfigurationMetadata<M> metadata,
@NotNull Function<A, M> extractor) { @NotNull Function<A, M> extractor) {
return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor)); return initializer(loader -> loader.registerAnnotation(annotation, metadata, extractor));
} }
/**
* Build the configuration holder.
*
* @return The configuration holder
*/
public abstract @NotNull HOLDER build(); public abstract @NotNull HOLDER build();
} }
@@ -6,6 +6,7 @@ import cc.carm.lib.configuration.adapter.ValueType;
import cc.carm.lib.configuration.source.loader.ConfigurationInitializer; import cc.carm.lib.configuration.source.loader.ConfigurationInitializer;
import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder; import cc.carm.lib.configuration.source.meta.ConfigurationMetaHolder;
import cc.carm.lib.configuration.source.meta.ConfigurationMetadata; import cc.carm.lib.configuration.source.meta.ConfigurationMetadata;
import cc.carm.lib.configuration.source.option.ConfigurationOption;
import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder; import cc.carm.lib.configuration.source.option.ConfigurationOptionHolder;
import cc.carm.lib.configuration.source.section.ConfigureSource; import cc.carm.lib.configuration.source.section.ConfigureSource;
import cc.carm.lib.configuration.value.ValueManifest; import cc.carm.lib.configuration.value.ValueManifest;
@@ -50,6 +51,10 @@ public abstract class ConfigurationHolder<SOURCE extends ConfigureSource<?, ?, S
return options; return options;
} }
public <O> O option(@NotNull ConfigurationOption<O> option) {
return options().get(option);
}
public @NotNull Map<String, ConfigurationMetaHolder> metadata() { public @NotNull Map<String, ConfigurationMetaHolder> metadata() {
return this.metadata; return this.metadata;
} }
@@ -108,13 +108,13 @@ public class ConfigurationInitializer {
public void initialize(@NotNull ConfigurationHolder<?> holder, public void initialize(@NotNull ConfigurationHolder<?> holder,
@NotNull Configuration config) throws Exception { @NotNull Configuration config) throws Exception {
initializeInstance(holder, config, null, null); initializeInstance(holder, config, null, null);
if (holder.options().get(StandardOptions.SET_DEFAULTS)) holder.save(); if (holder.option(StandardOptions.SET_DEFAULTS)) holder.save();
} }
public void initialize(@NotNull ConfigurationHolder<?> holder, public void initialize(@NotNull ConfigurationHolder<?> holder,
@NotNull Class<? extends Configuration> clazz) throws Exception { @NotNull Class<? extends Configuration> clazz) throws Exception {
initializeStaticClass(holder, clazz, null, null); initializeStaticClass(holder, clazz, null, null);
if (holder.options().get(StandardOptions.SET_DEFAULTS)) holder.save(); if (holder.option(StandardOptions.SET_DEFAULTS)) holder.save();
} }
@@ -149,7 +149,7 @@ public class ConfigurationInitializer {
initializeField(holder, clazz, field, path); initializeField(holder, clazz, field, path);
} }
if (holder.options().get(StandardOptions.LOAD_SUB_CLASSES)) { if (holder.option(StandardOptions.LOAD_SUB_CLASSES)) {
Class<?>[] classes = clazz.getDeclaredClasses(); Class<?>[] classes = clazz.getDeclaredClasses();
for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。 for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载,保持顺序。
initializeStaticClass(holder, classes[i], path, null); initializeStaticClass(holder, classes[i], path, null);
@@ -175,8 +175,11 @@ public class ConfigurationInitializer {
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
if (holder.options().get(StandardOptions.SET_DEFAULTS)) { if (holder.option(StandardOptions.SET_DEFAULTS)) {
value.setDefault(); value.setDefault(); // Set default value.
}
if (holder.option(StandardOptions.PRELOAD)) {
value.get(); // Preload the value by calling #get method.
} }
} else if (source instanceof Configuration && object instanceof Configuration) { } else if (source instanceof Configuration && object instanceof Configuration) {
// 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。 // 当且仅当 源字段与字段 均为Configuration实例时,才对目标字段进行下一步初始化加载。
@@ -9,6 +9,12 @@ import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.function.UnaryOperator; import java.util.function.UnaryOperator;
/**
* Path generator for configuration.
* <p>
* Path generator is a utility class that helps to generate the path of the configuration.
* It can be used to generate the path of the field or class.
*/
public class PathGenerator { public class PathGenerator {
public static PathGenerator of() { public static PathGenerator of() {
@@ -80,7 +86,7 @@ public class PathGenerator {
} }
public static char pathSeparator(ConfigurationHolder<?> holder) { public static char pathSeparator(ConfigurationHolder<?> holder) {
return holder.options().get(StandardOptions.PATH_SEPARATOR); return holder.option(StandardOptions.PATH_SEPARATOR);
} }
/** /**
@@ -6,32 +6,20 @@ import java.util.function.Supplier;
public class ConfigurationOption<V> { public class ConfigurationOption<V> {
@SuppressWarnings("unchecked")
public static <T> ConfigurationOption<T> of(@NotNull T defaultValue) { public static <T> ConfigurationOption<T> of(@NotNull T defaultValue) {
return of((Class<T>) defaultValue.getClass(), defaultValue); return new ConfigurationOption<>(defaultValue);
}
public static <T> ConfigurationOption<T> of(@NotNull Class<T> valueClazz, @NotNull T defaultValue) {
return new ConfigurationOption<>(valueClazz, defaultValue);
} }
public static <T> ConfigurationOption<T> of(@NotNull Supplier<T> defaultValue) { public static <T> ConfigurationOption<T> of(@NotNull Supplier<T> defaultValue) {
return of(defaultValue.get()); return of(defaultValue.get());
} }
private final @NotNull Class<V> valueClazz;
private @NotNull V defaultValue; private @NotNull V defaultValue;
public ConfigurationOption(@NotNull Class<V> valueClazz, @NotNull V defaultValue) { public ConfigurationOption(@NotNull V defaultValue) {
this.valueClazz = valueClazz;
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
} }
@NotNull
public Class<V> valueClass() {
return this.valueClazz;
}
public @NotNull V defaults() { public @NotNull V defaults() {
return defaultValue; return defaultValue;
} }
@@ -1,7 +1,6 @@
package cc.carm.lib.configuration.source.section; package cc.carm.lib.configuration.source.section;
import cc.carm.lib.configuration.function.DataFunction; import cc.carm.lib.configuration.function.DataFunction;
import cc.carm.lib.configuration.source.option.StandardOptions;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -12,62 +11,199 @@ import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
/**
* Represents a section of a configuration.
*
* @author Carm
* @since 4.0.0
*/
public interface ConfigureSection { public interface ConfigureSection {
@NotNull ConfigureSource<?, ?, ?> source(); /**
* Gets the parent section of this section.
* <p>
* For root sections, this will return null.
*
* @return Parent section, or null if this is a root section.
*/
@Contract(pure = true)
@Nullable ConfigureSection parent(); @Nullable ConfigureSection parent();
default char separator() { /**
return source().holder().options().get(StandardOptions.PATH_SEPARATOR); * Gets a set containing all keys in this section.
} * <p>
* If deep is set to true, then this will contain all the keys within any
* child {@link ConfigureSection}s (and their children paths).
* <p>
* If deep is set to false, then this will contain only the keys of any
* direct children, and not their own children.
*
* @param deep Whether to get a deep list.
* @return Set of keys contained within this Section.
*/
@NotNull @NotNull
@UnmodifiableView @UnmodifiableView
default Set<String> getKeys(boolean deep) { default Set<String> getKeys(boolean deep) {
return getValues(deep).keySet(); return getValues(deep).keySet();
} }
/**
* Gets a set containing all values in this section.
* <p>
* If deep is set to true, then this will contain all the keys within any
* child {@link ConfigureSection}s (and their children paths).
* <p>
* If deep is set to false, then this will contain only the keys of any
* direct children, and not their own children.
*
* @param deep Whether to get a deep list.
* @return Map of data values contained within this Section.
*/
@NotNull @NotNull
@UnmodifiableView @UnmodifiableView
Map<String, Object> getValues(boolean deep); Map<String, Object> getValues(boolean deep);
/**
* Sets the value at the given path.
* <p>
* Null values will be kept, if you want to remove a value use {@link #remove(String)}
* Path separator depends on holder's
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
*
* @param path The path to set the value at.
* @param value The value to set.
*/
void set(@NotNull String path, @Nullable Object value); void set(@NotNull String path, @Nullable Object value);
/**
* Removes the value at the given path.
* <p>
* Path separator depends on holder's
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
*
* @param path The path to remove the value at.
*/
void remove(@NotNull String path);
/**
* Check if the value of given path is present.
* <p>
* Path separator depends on holder's
* {@link cc.carm.lib.configuration.source.option.StandardOptions#PATH_SEPARATOR}
*
* @param path The path to check.
* @return True if the value is present, false otherwise.
*/
boolean contains(@NotNull String path); boolean contains(@NotNull String path);
/**
* Predicate the value of given path is specific type.
*
* @param path The path to check.
* @param typeClass The type's class
* @param <T> The type to check.
* @return True if the value is present and is the correct type, false otherwise.
*/
default <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) { default <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) {
return typeClass.isInstance(get(path)); return typeClass.isInstance(get(path));
} }
/**
* Predicate the value of given path is a {@link List}.
*
* @param path The path to check.
* @return True if the value is present and is a list, false otherwise.
*/
default boolean isList(@NotNull String path) { default boolean isList(@NotNull String path) {
return isType(path, List.class); return isType(path, List.class);
} }
/**
* Get the value as a {@link List} from the specified path.
*
* @param path The path to get the {@link List}.
* @return The list if the path exists and is a list, otherwise null.
*/
@Nullable List<?> getList(@NotNull String path); @Nullable List<?> getList(@NotNull String path);
/**
* Predicate the value of given path is a {@link ConfigureSection}.
*
* @param path The path to check.
* @return True if the value is present and is a section, false otherwise.
*/
default boolean isSection(@NotNull String path) { default boolean isSection(@NotNull String path) {
return isType(path, ConfigureSection.class); return isType(path, ConfigureSection.class);
} }
/**
* Get the value as a {@link ConfigureSection} from the specified path.
*
* @param path The path to get the section.
* @return The section if the path exists and is a section, otherwise null.
*/
@Nullable @Nullable
ConfigureSection getSection(@NotNull String path); ConfigureSection getSection(@NotNull String path);
/**
* Get the origin value of the path.
*
* @param path The path to get the value from.
* @return The value at the path, or null if not found.
*/
@Nullable Object get(@NotNull String path); @Nullable Object get(@NotNull String path);
default @Nullable <T> T get(@NotNull String path, @NotNull Class<T> clazz) { /**
return get(path, null, clazz); * Get the value of the path for specific type,
* if the path does not exist, return null.
*
* @param path The path to get the value from.
* @param type The type class of the value
* @param <T> The type of the value
* @return The value at the path, or the default value if not found.
*/
default @Nullable <T> T get(@NotNull String path, @NotNull Class<T> type) {
return get(path, null, type);
} }
default @Nullable <T> T get(@NotNull String path, @NotNull DataFunction<Object, T> parser) { /**
* Get the value of the path using a parser function,
* if the path does not exist, return NULL.
*
* @param path The path to get the value from.
* @param parser The function to parse the value
* @param <T> The type of the value
* @return The value at the path, or null if not found.
*/
default @Nullable <T> T get(@NotNull String path, @NotNull DataFunction<@Nullable Object, T> parser) {
return get(path, null, parser); return get(path, null, parser);
} }
/**
* Get the value of the path for specific type,
* if the path does not exist, return the default value.
*
* @param path The path to get the value from.
* @param defaults The default value to return if the path does not exist.
* @param clazz The type class of the value
* @param <T> The type of the value
* @return The value at the path, or the default value if not found.
*/
@Contract("_,!null,_->!null") @Contract("_,!null,_->!null")
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue, @NotNull Class<T> clazz) { default @Nullable <T> T get(@NotNull String path, @Nullable T defaults, @NotNull Class<T> clazz) {
return get(path, defaultValue, DataFunction.castObject(clazz)); return get(path, defaults, DataFunction.castObject(clazz));
} }
/**
* Get the value of the path using a parser function,
* if the path does not exist, return the default value.
*
* @param path The path to get the value from.
* @param defaultValue The default value to return if the path does not exist.
* @param parser The function to parse the value
* @param <T> The type of the value
* @return The value at the path, or the default value if not found.
*/
@Contract("_,!null,_->!null") @Contract("_,!null,_->!null")
default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue, default @Nullable <T> T get(@NotNull String path, @Nullable T defaultValue,
@NotNull DataFunction<Object, T> parser) { @NotNull DataFunction<Object, T> parser) {
@@ -82,125 +218,290 @@ public interface ConfigureSection {
return defaultValue; return defaultValue;
} }
/**
* Predicate the value of given path is a {@link Boolean}.
*
* @param path The path to check.
* @return True if the value is present and is a boolean, false otherwise.
*/
default boolean isBoolean(@NotNull String path) { default boolean isBoolean(@NotNull String path) {
return isType(path, Boolean.class); return isType(path, Boolean.class);
} }
/**
* Get the value as a {@link Boolean} from the specified path.
*
* @param path The path to get the boolean.
* @return The boolean if the path exists and is a boolean, otherwise false.
*/
default boolean getBoolean(@NotNull String path) { default boolean getBoolean(@NotNull String path) {
return getBoolean(path, false); return getBoolean(path, false);
} }
/**
* Get the value as a {@link Boolean} from the specified path.
*
* @param path The path to get the boolean.
* @param def The default value to return if the path does not exist.
* @return The boolean if the path exists and is a boolean, otherwise the default value.
*/
@Contract("_, !null -> !null") @Contract("_, !null -> !null")
default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) { default @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
return get(path, def, DataFunction.booleanValue()); return get(path, def, DataFunction.booleanValue());
} }
/**
* Predicate the value of given path is a {@link Byte}.
*
* @param path The path to check.
* @return True if the value is present and is a byte, false otherwise.
*/
default @Nullable Boolean isByte(@NotNull String path) { default @Nullable Boolean isByte(@NotNull String path) {
return isType(path, Byte.class); return isType(path, Byte.class);
} }
/**
* Get the value as a {@link Byte} from the specified path.
*
* @param path The path to get the byte.
* @return The byte if the path exists and is a byte, otherwise 0.
*/
default @Nullable Byte getByte(@NotNull String path) { default @Nullable Byte getByte(@NotNull String path) {
return getByte(path, (byte) 0); return getByte(path, (byte) 0);
} }
/**
* Get the value as a {@link Byte} from the specified path.
*
* @param path The path to get the byte.
* @param def The default value to return if the path does not exist.
* @return The byte if the path exists and is a byte, otherwise the default value.
*/
@Contract("_, !null -> !null") @Contract("_, !null -> !null")
default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) { default @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
return get(path, def, DataFunction.byteValue()); return get(path, def, DataFunction.byteValue());
} }
/**
* Predicate the value of given path is a {@link Short}.
*
* @param path The path to check.
* @return True if the value is present and is a short, false otherwise.
*/
default boolean isShort(@NotNull String path) { default boolean isShort(@NotNull String path) {
return isType(path, Short.class); return isType(path, Short.class);
} }
/**
* Get the value as a {@link Short} from the specified path.
*
* @param path The path to get the short.
* @return The short if the path exists and is a short, otherwise 0.
*/
default @Nullable Short getShort(@NotNull String path) { default @Nullable Short getShort(@NotNull String path) {
return getShort(path, (short) 0); return getShort(path, (short) 0);
} }
/**
* Get the value as a {@link Short} from the specified path.
*
* @param path The path to get the short.
* @param def The default value to return if the path does not exist.
* @return The short if the path exists and is a short, otherwise the default value.
*/
@Contract("_, !null -> !null") @Contract("_, !null -> !null")
default @Nullable Short getShort(@NotNull String path, @Nullable Short def) { default @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
return get(path, def, DataFunction.shortValue()); return get(path, def, DataFunction.shortValue());
} }
/**
* Predicate the value of given path is a {@link Integer}.
*
* @param path The path to check.
* @return True if the value is present and is a int, false otherwise.
*/
default boolean isInt(@NotNull String path) { default boolean isInt(@NotNull String path) {
return isType(path, Integer.class); return isType(path, Integer.class);
} }
/**
* Get the value as a {@link Integer} from the specified path.
*
* @param path The path to get the int.
* @return The int if the path exists and is a int, otherwise 0.
*/
default @Nullable Integer getInt(@NotNull String path) { default @Nullable Integer getInt(@NotNull String path) {
return getInt(path, 0); return getInt(path, 0);
} }
/**
* Get the value as a {@link Integer} from the specified path.
*
* @param path The path to get the int.
* @param def The default value to return if the path does not exist.
* @return The int if the path exists and is a int, otherwise the default value.
*/
@Contract("_, !null -> !null") @Contract("_, !null -> !null")
default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) { default @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
return get(path, def, DataFunction.intValue()); return get(path, def, DataFunction.intValue());
} }
/**
* Predicate the value of given path is a {@link Long}.F
*
* @param path The path to check.
* @return True if the value is present and is a long, false otherwise.
*/
default boolean isLong(@NotNull String path) { default boolean isLong(@NotNull String path) {
return isType(path, Long.class); return isType(path, Long.class);
} }
/**
* Get the value as a {@link Long} from the specified path.
*
* @param path The path to get the long.
* @return The long if the path exists and is a long, otherwise 0.
*/
default @Nullable Long getLong(@NotNull String path) { default @Nullable Long getLong(@NotNull String path) {
return getLong(path, 0L); return getLong(path, 0L);
} }
/**
* Get the value as a {@link Long} from the specified path.
*
* @param path The path to get the long.
* @param def The default value to return if the path does not exist.
* @return The long if the path exists and is a long, otherwise the default value.
*/
@Contract("_, !null -> !null") @Contract("_, !null -> !null")
default @Nullable Long getLong(@NotNull String path, @Nullable Long def) { default @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
return get(path, def, DataFunction.longValue()); return get(path, def, DataFunction.longValue());
} }
/**
* Predicate the value of given path is a {@link Float}.
*
* @param path The path to check.
* @return True if the value is present and is a float, false otherwise.
*/
default boolean isFloat(@NotNull String path) { default boolean isFloat(@NotNull String path) {
return isType(path, Float.class); return isType(path, Float.class);
} }
/**
* Get the value as a {@link Float} from the specified path.
*
* @param path The path to get the float.
* @return The float if the path exists and is a float, otherwise 0.
*/
default @Nullable Float getFloat(@NotNull String path) { default @Nullable Float getFloat(@NotNull String path) {
return getFloat(path, 0.0F); return getFloat(path, 0.0F);
} }
/**
* Get the value as a {@link Float} from the specified path.
*
* @param path The path to get the float.
* @param def The default value to return if the path does not exist.
* @return The float if the path exists and is a float, otherwise the default value.
*/
@Contract("_, !null -> !null") @Contract("_, !null -> !null")
default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) { default @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
return get(path, def, DataFunction.floatValue()); return get(path, def, DataFunction.floatValue());
} }
/**
* Predicate the value of given path is a {@link Double}.
*
* @param path The path to check.
* @return True if the value is present and is a double, false otherwise.
*/
default boolean isDouble(@NotNull String path) { default boolean isDouble(@NotNull String path) {
return isType(path, Double.class); return isType(path, Double.class);
} }
/**
* Get the value as a {@link Double} from the specified path.
*
* @param path The path to get the double.
* @return The double if the path exists and is a double, otherwise 0.
*/
default @Nullable Double getDouble(@NotNull String path) { default @Nullable Double getDouble(@NotNull String path) {
return getDouble(path, 0.0D); return getDouble(path, 0.0D);
} }
/**
* Get the value as a {@link Double} from the specified path.
*
* @param path The path to get the double.
* @param def The default value to return if the path does not exist.
* @return The double if the path exists and is a double, otherwise the default value.
*/
@Contract("_, !null -> !null") @Contract("_, !null -> !null")
default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) { default @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
return get(path, def, DataFunction.doubleValue()); return get(path, def, DataFunction.doubleValue());
} }
/**
* Predicate the value of given path is a {@link Character}.
*
* @param path The path to check.
* @return True if the value is present and is a char, false otherwise.
*/
default boolean isChar(@NotNull String path) { default boolean isChar(@NotNull String path) {
return isType(path, Boolean.class); return isType(path, Boolean.class);
} }
/**
* Get the value as a {@link Character} from the specified path.
*
* @param path The path to get the char.
* @return The char if the path exists and is a char, otherwise null.
*/
default @Nullable Character getChar(@NotNull String path) { default @Nullable Character getChar(@NotNull String path) {
return getChar(path, null); return getChar(path, null);
} }
/**
* Get the value as a {@link Character} from the specified path.
*
* @param path The path to get the char.
* @param def The default value to return if the path does not exist.
* @return The char if the path exists and is a char, otherwise the default value.
*/
@Contract("_, !null -> !null") @Contract("_, !null -> !null")
default @Nullable Character getChar(@NotNull String path, @Nullable Character def) { default @Nullable Character getChar(@NotNull String path, @Nullable Character def) {
return get(path, def, Character.class); return get(path, def, Character.class);
} }
/**
* Predicate the value of given path is a {@link String}.
*
* @param path The path to check.
* @return True if the value is present and is a string, false otherwise.
*/
default boolean isString(@NotNull String path) { default boolean isString(@NotNull String path) {
return isType(path, String.class); return isType(path, String.class);
} }
/**
* Get the value as a {@link String} from the specified path.
*
* @param path The path to get the string.
* @return The string if the path exists and is a string, otherwise null.
*/
default @Nullable String getString(@NotNull String path) { default @Nullable String getString(@NotNull String path) {
return getString(path, null); return getString(path, null);
} }
/**
* Get the value as a {@link String} from the specified path.
*
* @param path The path to get the string.
* @param def The default value to return if the path does not exist.
* @return The string if the path exists and is a string, otherwise the default value.
*/
@Contract("_, !null -> !null") @Contract("_, !null -> !null")
default @Nullable String getString(@NotNull String path, @Nullable String def) { default @Nullable String getString(@NotNull String path, @Nullable String def) {
return get(path, def, String.class); return get(path, def, String.class);
@@ -298,17 +599,41 @@ public interface ConfigureSection {
return getList(path, DataFunction.castObject(Character.class)); return getList(path, DataFunction.castObject(Character.class));
} }
/**
* Get the specific type of collection from the section.
*
* @param path The path to get the collection from
* @param constructor The constructor of the collection
* @param parser The function to parse the values
* @param <T> The type of the values
* @param <C> The type of the collection
* @return The collection of values
*/
default <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path, default <T, C extends Collection<T>> @NotNull C getCollection(@NotNull String path,
@NotNull Supplier<C> constructor, @NotNull Supplier<C> constructor,
@NotNull DataFunction<Object, T> parser) { @NotNull DataFunction<Object, T> parser) {
return parseCollection(getList(path), constructor, parser); return parseCollection(getList(path), constructor, parser);
} }
/**
* Get the specific type of steam from the section.
*
* @param path The path to get the stream from
* @return The stream of values
*/
default @NotNull Stream<?> stream(@NotNull String path) { default @NotNull Stream<?> stream(@NotNull String path) {
List<?> values = getList(path); List<?> values = getList(path);
return values == null ? Stream.empty() : values.stream(); return values == null ? Stream.empty() : values.stream();
} }
/**
* Get the specific type of steam from the section.
*
* @param path The path to get the stream from
* @param parser The function to parse the values
* @param <T> The type of the values
* @return The stream of values
*/
default <T> @NotNull Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) { default <T> @NotNull Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) {
return stream(path).map(parser); return stream(path).map(parser);
} }
@@ -1,12 +1,23 @@
package cc.carm.lib.configuration.source.section; package cc.carm.lib.configuration.source.section;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.option.StandardOptions;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
/**
* ConfigureSource represents the source of configuration,
* which can be a file, a database, or any other source.
*
* @param <SECTION> The type of the root section.
* @param <ORIGINAL> The original configuration object.
* @param <SELF> The type of the source itself, for further implement support.
*/
public abstract class ConfigureSource< public abstract class ConfigureSource<
SECTION extends ConfigureSection, ORIGINAL, SECTION extends ConfigureSection, ORIGINAL,
SELF extends ConfigureSource<SECTION, ORIGINAL, SELF>> SELF extends ConfigureSource<SECTION, ORIGINAL, SELF>>
@@ -24,28 +35,46 @@ public abstract class ConfigureSource<
return holder; return holder;
} }
public void reload() throws Exception { public void reload() throws Exception {
onReload(); // 调用重写的Reload方法 onReload(); // 调用重写的Reload方法
this.lastUpdateMillis = System.currentTimeMillis(); this.lastUpdateMillis = System.currentTimeMillis();
} }
protected abstract SELF self(); @Contract(pure = true)
@ApiStatus.Internal
protected abstract @NotNull SELF self();
/** /**
* @return Original configuration object * @return The original configuration object.
*/ */
@Contract(pure = true)
public abstract @NotNull ORIGINAL original(); public abstract @NotNull ORIGINAL original();
/** /**
* @return The root {@link ConfigureSection} * @return The root {@link ConfigureSection}, which represents the entire configuration.
*/ */
public abstract @NotNull SECTION section(); public abstract @NotNull SECTION section();
/**
* Save the whole configuration.
*
* @throws Exception If any error occurs while saving.
*/
public abstract void save() throws Exception; public abstract void save() throws Exception;
/**
* Reload the configuration.
* <br>This used for implementation, for external usage, use {@link #reload()}
*
* @throws Exception If any error occurs while reloading.
*/
@ApiStatus.OverrideOnly
protected abstract void onReload() throws Exception; protected abstract void onReload() throws Exception;
public char pathSeparator() {
return holder().options().get(StandardOptions.PATH_SEPARATOR);
}
public long getLastUpdateMillis() { public long getLastUpdateMillis() {
return this.lastUpdateMillis; return this.lastUpdateMillis;
} }
@@ -54,14 +83,15 @@ public abstract class ConfigureSource<
return getLastUpdateMillis() > parsedTime; return getLastUpdateMillis() > parsedTime;
} }
/**
* Source also represents the root section, so it has no parent
*
* @return null
*/
@Override @Override
@Contract(pure = true, value = "->null")
public @Nullable ConfigureSection parent() { public @Nullable ConfigureSection parent() {
return null; // Source also represents the root section, so it has no parent return null;
}
@Override
public @NotNull ConfigureSource<?, ?, ?> source() {
return self();
} }
@Override @Override
@@ -80,8 +110,8 @@ public abstract class ConfigureSource<
} }
@Override @Override
public boolean isList(@NotNull String path) { public void remove(@NotNull String path) {
return section().isList(path); section().remove(path);
} }
@Override @Override
@@ -89,11 +119,6 @@ public abstract class ConfigureSource<
return section().getList(path); return section().getList(path);
} }
@Override
public boolean isSection(@NotNull String path) {
return section().isSection(path);
}
@Override @Override
public @Nullable ConfigureSection getSection(@NotNull String path) { public @Nullable ConfigureSection getSection(@NotNull String path) {
return section().getSection(path); return section().getSection(path);
@@ -113,7 +113,7 @@ public abstract class ConfigValue<T> extends ValueManifest<T> {
* @param override Whether to overwrite existing configured value * @param override Whether to overwrite existing configured value
*/ */
public void setDefault(boolean override) { public void setDefault(boolean override) {
if (!override && config().contains(path())) return; if (config().contains(path()) && !override) return; // Skip if the value is already set
set(defaults()); // Set the default value set(defaults()); // Set the default value
} }
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.1</version> <version>4.0.2</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>easyconfiguration-parent</artifactId>
<version>4.0.1</version> <version>4.0.2</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -44,6 +44,9 @@ public @interface InlineComment {
* bar: "foobar" # Comment Contents * bar: "foobar" # Comment Contents
* </pre></blockquote> * </pre></blockquote>
* *
* <p><i>Some implements may not support this feature
* in list values or other complex structures.</i>
*
* @return The path regexes of this comment * @return The path regexes of this comment
*/ */
@NotNull @NotNull
@@ -9,7 +9,12 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface InlineComments { public @interface InlineComments {
/**
* Multiple inline comments support.
*
* @return inline comment contents.
* @see InlineComment
*/
InlineComment[] value(); InlineComment[] value();
} }
@@ -26,7 +26,7 @@ public class Commentable {
String comment = getInlineComment(holder, path, null); String comment = getInlineComment(holder, path, null);
if (comment != null) return comment; if (comment != null) return comment;
String sep = String.valueOf(holder.options().get(StandardOptions.PATH_SEPARATOR)); String sep = String.valueOf(holder.option(StandardOptions.PATH_SEPARATOR));
// If the comment is not found, try to get the comment from the parent section // If the comment is not found, try to get the comment from the parent section
String[] keys = path.split(Pattern.quote(sep)); String[] keys = path.split(Pattern.quote(sep));
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>easyconfiguration-parent</artifactId>
<version>4.0.1</version> <version>4.0.2</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>easyconfiguration-parent</artifactId>
<version>4.0.1</version> <version>4.0.2</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -53,7 +53,6 @@ public class MemorySection implements ConfigureSection {
return createChild(new LinkedHashMap<>()); return createChild(new LinkedHashMap<>());
} }
@Override
public @NotNull ConfigureSource<? extends MemorySection, ?, ?> source() { public @NotNull ConfigureSource<? extends MemorySection, ?, ?> source() {
return this.source; return this.source;
} }
@@ -66,6 +65,10 @@ public class MemorySection implements ConfigureSection {
return this.parent; return this.parent;
} }
public char pathSeparator() {
return source.pathSeparator();
}
@Override @Override
public @NotNull Map<String, Object> getValues(boolean deep) { public @NotNull Map<String, Object> getValues(boolean deep) {
return Collections.unmodifiableMap(deep ? mapChildrenValues(this, null, true) : data()); return Collections.unmodifiableMap(deep ? mapChildrenValues(this, null, true) : data());
@@ -85,6 +88,16 @@ public class MemorySection implements ConfigureSection {
} }
} }
@Override
public void remove(@NotNull String path) {
MemorySection section = getSectionFor(path);
if (section != this) {
section.remove(childPath(path));
} else {
this.data.remove(path);
}
}
@Override @Override
public boolean contains(@NotNull String path) { public boolean contains(@NotNull String path) {
return get(path) != null; return get(path) != null;
@@ -109,7 +122,7 @@ public class MemorySection implements ConfigureSection {
} }
private MemorySection getSectionFor(String path) { private MemorySection getSectionFor(String path) {
int index = path.indexOf(separator()); int index = path.indexOf(pathSeparator());
if (index == -1) return this; if (index == -1) return this;
String root = path.substring(0, index); String root = path.substring(0, index);
@@ -123,7 +136,7 @@ public class MemorySection implements ConfigureSection {
} }
private String childPath(String path) { private String childPath(String path) {
int index = path.indexOf(separator()); int index = path.indexOf(pathSeparator());
return (index == -1) ? path : path.substring(index + 1); return (index == -1) ? path : path.substring(index + 1);
} }
@@ -138,7 +151,7 @@ public class MemorySection implements ConfigureSection {
@Nullable String parent, boolean deep) { @Nullable String parent, boolean deep) {
Map<String, Object> output = new LinkedHashMap<>(); Map<String, Object> output = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : section.data().entrySet()) { for (Map.Entry<String, Object> entry : section.data().entrySet()) {
String path = (parent == null ? "" : parent + separator()) + entry.getKey(); String path = (parent == null ? "" : parent + pathSeparator()) + entry.getKey();
output.remove(path); output.remove(path);
output.put(path, entry.getValue()); output.put(path, entry.getValue());
if (deep && entry.getValue() instanceof MemorySection) { if (deep && entry.getValue() instanceof MemorySection) {
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>easyconfiguration-parent</artifactId>
<version>4.0.1</version> <version>4.0.2</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>easyconfiguration-parent</artifactId>
<version>4.0.1</version> <version>4.0.2</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
+1 -1
View File
@@ -15,7 +15,7 @@
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>easyconfiguration-parent</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>4.0.1</version> <version>4.0.2</version>
<modules> <modules>
<module>core</module> <module>core</module>
<module>features/section</module> <module>features/section</module>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.1</version> <version>4.0.2</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -48,7 +48,7 @@ public class JSONSource extends FileConfigSource<MemorySection, Map<String, Obje
} }
@Override @Override
protected JSONSource self() { protected @NotNull JSONSource self() {
return this; return this;
} }
+1 -1
View File
@@ -6,7 +6,7 @@
<parent> <parent>
<artifactId>easyconfiguration-parent</artifactId> <artifactId>easyconfiguration-parent</artifactId>
<groupId>cc.carm.lib</groupId> <groupId>cc.carm.lib</groupId>
<version>4.0.1</version> <version>4.0.2</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -4,7 +4,6 @@ import cc.carm.lib.configuration.commentable.Commentable;
import cc.carm.lib.configuration.commentable.CommentableOptions; import cc.carm.lib.configuration.commentable.CommentableOptions;
import cc.carm.lib.configuration.source.ConfigurationHolder; import cc.carm.lib.configuration.source.ConfigurationHolder;
import cc.carm.lib.configuration.source.file.FileConfigSource; import cc.carm.lib.configuration.source.file.FileConfigSource;
import cc.carm.lib.configuration.source.option.StandardOptions;
import cc.carm.lib.configuration.source.section.ConfigureSection; import cc.carm.lib.configuration.source.section.ConfigureSection;
import cc.carm.lib.configuration.source.section.MemorySection; import cc.carm.lib.configuration.source.section.MemorySection;
import cc.carm.lib.yamlcommentupdater.CommentedSection; import cc.carm.lib.yamlcommentupdater.CommentedSection;
@@ -56,7 +55,7 @@ public class YAMLSource
} }
@Override @Override
protected YAMLSource self() { protected @NotNull YAMLSource self() {
return null; return null;
} }
@@ -70,11 +69,6 @@ public class YAMLSource
return Objects.requireNonNull(this.rootSection, "Root section is not initialized."); return Objects.requireNonNull(this.rootSection, "Root section is not initialized.");
} }
@Override
public char separator() {
return holder().options().get(StandardOptions.PATH_SEPARATOR);
}
public @NotNull LoaderOptions loaderOptions() { public @NotNull LoaderOptions loaderOptions() {
return holder().options().get(YAMLOptions.LOADER); return holder().options().get(YAMLOptions.LOADER);
} }
@@ -115,9 +109,9 @@ public class YAMLSource
@Override @Override
public void save() throws Exception { public void save() throws Exception {
CommentedYAMLWriter writer = new CommentedYAMLWriter( CommentedYAMLWriter writer = new CommentedYAMLWriter(
String.valueOf(this.separator()), String.valueOf(this.pathSeparator()),
dumperOptions().getIndent(), dumperOptions().getIndent(),
holder.options().get(CommentableOptions.COMMENT_EMPTY_VALUE) holder.option(CommentableOptions.COMMENT_EMPTY_VALUE)
); );
try { try {
fileWriter(w -> w.write(writer.saveToString(this))); fileWriter(w -> w.write(writer.saveToString(this)));
@@ -2,6 +2,7 @@ package sample;
import cc.carm.lib.configuration.Configuration; import cc.carm.lib.configuration.Configuration;
import cc.carm.lib.configuration.annotation.ConfigPath; 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.HeaderComments;
import cc.carm.lib.configuration.annotation.InlineComment; import cc.carm.lib.configuration.annotation.InlineComment;
import cc.carm.lib.configuration.value.standard.ConfiguredList; import cc.carm.lib.configuration.value.standard.ConfiguredList;
@@ -19,6 +20,8 @@ public interface SampleConfig extends Configuration {
@HeaderComments("Server configurations") // Header comment @HeaderComments("Server configurations") // Header comment
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class); ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class);
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
@FooterComments("[ UUID >-----------------------------------")
ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString() ConfiguredList<UUID> UUIDS = ConfiguredList.builderOf(UUID.class).fromString()
.parse(UUID::fromString).serialize(UUID::toString) .parse(UUID::fromString).serialize(UUID::toString)
.defaults( .defaults(
@@ -11,7 +11,7 @@ public class SampleTest {
// 1. Make a configuration provider from a file. // 1. Make a configuration provider from a file.
ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml") ConfigurationHolder<?> holder = YAMLConfigFactory.from("target/config.yml")
.resourcePath("configs/sample.yml") .resourcePath("configs/sample.yml")
.indent(4) // Optional: Set the indentation of the configuration file. .indent(2) // Optional: Set the indentation of the configuration file.
.build(); .build();
// 2. Initialize the configuration classes or instances. // 2. Initialize the configuration classes or instances.