mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-04 18:48:20 +08:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f28abebb9 | |||
| 842cd78ce3 | |||
| 11f1f36a15 | |||
| ee9f29ba30 | |||
| f5bccdaad5 | |||
| f5f70ff69b | |||
| 3e221740bc | |||
| 96d09be977 | |||
| 5d7c946db5 | |||
| 9e008ff4cd | |||
| df19da170b | |||
| 3473ef2247 | |||
| d543530305 | |||
| d81855697c | |||
| 5c16e98f30 | |||
| 3f1ffadeff | |||
| d8191b7c6d | |||
| ba66220f92 | |||
| 730d6d7e9c | |||
| 4523190cb0 | |||
| 2a49e2ee6b | |||
| 77b223b2cb | |||
| 8e7ac263e7 | |||
| 80f03ec501 | |||
| 1c002ae535 | |||
| a4659c5c9f |
@@ -256,6 +256,11 @@ Many thanks to Jetbrains for kindly providing a license for us to work on this a
|
|||||||
|
|
||||||
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration)
|
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration)
|
||||||
|
|
||||||
|
Many thanks to [ArtformGames](https://github.com/ArtformGames) for their
|
||||||
|
strong support and active contribution to this project!
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/ArtformGames/.github/master/logo/logo_full.svg" width="317px" height="117px" alt="ArtformGames">
|
||||||
|
|
||||||
## Open Source License
|
## Open Source License
|
||||||
|
|
||||||
This project's source code is licensed under
|
This project's source code is licensed under
|
||||||
|
|||||||
+10
-4
@@ -32,19 +32,21 @@ README LANGUAGES [ [English](README.md) | [**中文**](README_CN.md) ]
|
|||||||
|
|
||||||
## 开发
|
## 开发
|
||||||
|
|
||||||
详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release) 请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。
|
详细开发介绍请 [点击这里](.doc/README.md) , JavaDoc(最新Release)
|
||||||
|
请 [点击这里](https://CarmJos.github.io/EasyConfiguration) 。
|
||||||
|
|
||||||
### 示例代码
|
### 示例代码
|
||||||
|
|
||||||
为快速的展示该项目的适用性,这里有几个实际演示:
|
为快速的展示该项目的适用性,这里有几个实际演示:
|
||||||
|
|
||||||
- [数据库配置文件实例](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
|
- [数据库配置文件实例](demo/src/main/java/cc/carm/lib/configuration/demo/DatabaseConfiguration.java)
|
||||||
- [全种类配置实例类演示](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
|
- [全种类配置实例类演示](demo/src/main/java/cc/carm/lib/configuration/demo/tests/conf/DemoConfiguration.java)
|
||||||
|
|
||||||
您可以 [点击这里](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
|
```java
|
||||||
|
|
||||||
@ConfigPath(root = true)
|
@ConfigPath(root = true)
|
||||||
@HeaderComments("Configurations for sample")
|
@HeaderComments("Configurations for sample")
|
||||||
public interface SampleConfig extends Configuration {
|
public interface SampleConfig extends Configuration {
|
||||||
@@ -276,6 +278,10 @@ EasyConfiguration for MineCraft!
|
|||||||
|
|
||||||
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration)
|
[](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration)
|
||||||
|
|
||||||
|
万分感谢来自 [ArtformGames](https://github.com/ArtformGames) 对本项目的大力支持与积极贡献!
|
||||||
|
|
||||||
|
<img src="https://raw.githubusercontent.com/ArtformGames/.github/master/logo/logo_full.svg" width="317px" height="117px" alt="ArtformGames">
|
||||||
|
|
||||||
## 开源协议
|
## 开源协议
|
||||||
|
|
||||||
本项目源码采用 [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html) 开源协议。
|
本项目源码采用 [GNU LESSER GENERAL PUBLIC LICENSE](https://www.gnu.org/licenses/lgpl-3.0.html) 开源协议。
|
||||||
|
|||||||
+1
-1
@@ -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.2</version>
|
<version>4.0.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.jetbrains.annotations.UnmodifiableView;
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
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;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@@ -29,6 +31,61 @@ public interface ConfigureSection {
|
|||||||
@Contract(pure = true)
|
@Contract(pure = true)
|
||||||
@Nullable ConfigureSection parent();
|
@Nullable ConfigureSection parent();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current section's path from {@link #parent()} of this section.
|
||||||
|
*
|
||||||
|
* @return The current path of this section, if {@link #isRoot()}, return empty string.
|
||||||
|
*/
|
||||||
|
@NotNull String path();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the full path of this section.
|
||||||
|
*
|
||||||
|
* @return The full path of this section, if {@link #isRoot()}, return empty string.
|
||||||
|
*/
|
||||||
|
default @NotNull String fullPath() {
|
||||||
|
if (parent() == null) return "";
|
||||||
|
return (parent().isRoot() ? "" : parent().fullPath() + pathSeparator()) + path();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path separator for the section.
|
||||||
|
*
|
||||||
|
* @return The path separator
|
||||||
|
*/
|
||||||
|
default char pathSeparator() {
|
||||||
|
return '.';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if this section is a root section.
|
||||||
|
*
|
||||||
|
* @return True if this section is a root section, false otherwise.
|
||||||
|
*/
|
||||||
|
@Contract(pure = true)
|
||||||
|
default boolean isRoot() {
|
||||||
|
return parent() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if this section is empty.
|
||||||
|
*
|
||||||
|
* @return True if this section is empty, false otherwise.
|
||||||
|
*/
|
||||||
|
default boolean isEmpty() {
|
||||||
|
return getValues(false).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of keys in this section.
|
||||||
|
*
|
||||||
|
* @return Number of keys in this section.
|
||||||
|
*/
|
||||||
|
default int size(boolean deep) {
|
||||||
|
return getKeys(deep).size();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a set containing all keys in this section.
|
* Gets a set containing all keys in this section.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -47,6 +104,17 @@ public interface ConfigureSection {
|
|||||||
return getValues(deep).keySet();
|
return getValues(deep).keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a set containing all primary keys in this section.
|
||||||
|
*
|
||||||
|
* @return Set of keys contained within this Section.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@UnmodifiableView
|
||||||
|
default Set<String> keys() {
|
||||||
|
return getKeys(false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a set containing all values in this section.
|
* Gets a set containing all values in this section.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -63,6 +131,36 @@ public interface ConfigureSection {
|
|||||||
@UnmodifiableView
|
@UnmodifiableView
|
||||||
Map<String, Object> getValues(boolean deep);
|
Map<String, Object> getValues(boolean deep);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a set containing all key-values in this section.
|
||||||
|
*
|
||||||
|
* @return Map of data values contained within this Section.
|
||||||
|
* @see #getValues(boolean)
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@UnmodifiableView
|
||||||
|
default Map<String, Object> values() {
|
||||||
|
return getValues(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a stream of all values in this section.
|
||||||
|
*
|
||||||
|
* @return Stream of all values in this section.
|
||||||
|
*/
|
||||||
|
default Stream<Map.Entry<String, Object>> stream() {
|
||||||
|
return values().entrySet().stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates over all keys in this section.
|
||||||
|
*
|
||||||
|
* @param action The action to apply to each key.
|
||||||
|
*/
|
||||||
|
default void forEach(@NotNull BiConsumer<String, Object> action) {
|
||||||
|
values().forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value at the given path.
|
* Sets the value at the given path.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -85,6 +183,19 @@ public interface ConfigureSection {
|
|||||||
*/
|
*/
|
||||||
void remove(@NotNull String path);
|
void remove(@NotNull String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the 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.
|
||||||
|
*/
|
||||||
|
default boolean contains(@NotNull String path) {
|
||||||
|
return getKeys(true).contains(path);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the value of given path is present.
|
* Check if the value of given path is present.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -94,7 +205,9 @@ public interface ConfigureSection {
|
|||||||
* @param path The path to check.
|
* @param path The path to check.
|
||||||
* @return True if the value is present, false otherwise.
|
* @return True if the value is present, false otherwise.
|
||||||
*/
|
*/
|
||||||
boolean contains(@NotNull String path);
|
default boolean containsValue(@NotNull String path) {
|
||||||
|
return get(path) != null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Predicate the value of given path is specific type.
|
* Predicate the value of given path is specific type.
|
||||||
@@ -124,7 +237,10 @@ public interface ConfigureSection {
|
|||||||
* @param path The path to get the {@link List}.
|
* @param path The path to get the {@link List}.
|
||||||
* @return The list if the path exists and is a list, otherwise null.
|
* @return The list if the path exists and is a list, otherwise null.
|
||||||
*/
|
*/
|
||||||
@Nullable List<?> getList(@NotNull String path);
|
default @Nullable List<?> getList(@NotNull String path) {
|
||||||
|
Object val = get(path);
|
||||||
|
return (val instanceof List<?>) ? (List<?>) val : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Predicate the value of given path is a {@link ConfigureSection}.
|
* Predicate the value of given path is a {@link ConfigureSection}.
|
||||||
@@ -143,7 +259,123 @@ public interface ConfigureSection {
|
|||||||
* @return The section if the path exists and is a section, otherwise null.
|
* @return The section if the path exists and is a section, otherwise null.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
ConfigureSection getSection(@NotNull String path);
|
default ConfigureSection getSection(@NotNull String path) {
|
||||||
|
Object val = get(path);
|
||||||
|
return (val instanceof ConfigureSection) ? (ConfigureSection) val : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ConfigureSection} with specified values.
|
||||||
|
* <p> The {@link #parent()} of the new section will be this section.
|
||||||
|
* <p> This section will not be saved until {@link #set(String, Object)} is called.
|
||||||
|
* <p> If you want to create and use a section and set it to this section, use {@link #computeSection(String)}.
|
||||||
|
*
|
||||||
|
* @param data The data to be used to create section.
|
||||||
|
* @return Newly created section
|
||||||
|
*/
|
||||||
|
@NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ConfigureSection} with specified values.
|
||||||
|
* <p> The {@link #parent()} of the new section will be this section.
|
||||||
|
*
|
||||||
|
* @param data The data to be used to create section.
|
||||||
|
* @return Newly created section
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Consumer<Map<String, Object>> data) {
|
||||||
|
return createSection(path, () -> {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
data.accept(map);
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link ConfigureSection} with specified values.
|
||||||
|
* <p> The {@link #parent()} of the new section will be this section.
|
||||||
|
*
|
||||||
|
* @param data The data to be used to create section.
|
||||||
|
* @return Newly created section
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Supplier<Map<String, Object>> data) {
|
||||||
|
return createSection(path, data.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new empty {@link ConfigureSection}.
|
||||||
|
* <p> The {@link #parent()} of the new section will be this section.
|
||||||
|
*
|
||||||
|
* @return Newly created section
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection createSection(@NotNull String path) {
|
||||||
|
return createSection(path, new LinkedHashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a section at the given path.
|
||||||
|
* <p>
|
||||||
|
* Any value previously set at this path will be replaced if it is not a section
|
||||||
|
* or will be returned if it is an exists {@link ConfigureSection}.
|
||||||
|
*
|
||||||
|
* @param path The path to get the section from.
|
||||||
|
* @return The section at the path, or a new section if it does not exist.
|
||||||
|
* @see #createSection(String, Map)
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection computeSection(@NotNull String path) {
|
||||||
|
return computeSection(path, new LinkedHashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a section at the given path.
|
||||||
|
* <p>
|
||||||
|
* Any value previously set at this path will be replaced if it is not a section
|
||||||
|
* or will be returned if it is an exists {@link ConfigureSection}.
|
||||||
|
*
|
||||||
|
* @param path The path to get the section from.
|
||||||
|
* @return The section at the path, or a new section if it does not exist.
|
||||||
|
* @see #createSection(String, Map)
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection computeSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
|
ConfigureSection current = getSection(path);
|
||||||
|
if (current == null) {
|
||||||
|
current = createSection(path, data);
|
||||||
|
set(path, current);
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a section at the given path.
|
||||||
|
* <p>
|
||||||
|
* Any value previously set at this path will be replaced if it is not a section
|
||||||
|
* or will be returned if it is an exists {@link ConfigureSection}.
|
||||||
|
*
|
||||||
|
* @param path The path to get the section from.
|
||||||
|
* @return The section at the path, or a new section if it does not exist.
|
||||||
|
* @see #createSection(String, Map)
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection computeSection(@NotNull String path, @NotNull Consumer<Map<String, Object>> data) {
|
||||||
|
return computeSection(path, () -> {
|
||||||
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
data.accept(map);
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get or create a section at the given path.
|
||||||
|
* <p>
|
||||||
|
* Any value previously set at this path will be replaced if it is not a section
|
||||||
|
* or will be returned if it is an exists {@link ConfigureSection}.
|
||||||
|
*
|
||||||
|
* @param path The path to get the section from.
|
||||||
|
* @return The section at the path, or a new section if it does not exist.
|
||||||
|
* @see #createSection(String, Map)
|
||||||
|
*/
|
||||||
|
default @NotNull ConfigureSection computeSection(@NotNull String path, @NotNull Supplier<Map<String, Object>> data) {
|
||||||
|
return computeSection(path, data.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the origin value of the path.
|
* Get the origin value of the path.
|
||||||
@@ -318,7 +550,7 @@ public interface ConfigureSection {
|
|||||||
* Predicate the value of given path is a {@link Integer}.
|
* Predicate the value of given path is a {@link Integer}.
|
||||||
*
|
*
|
||||||
* @param path The path to check.
|
* @param path The path to check.
|
||||||
* @return True if the value is present and is a int, false otherwise.
|
* @return True if the value is present and is an 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);
|
||||||
@@ -328,7 +560,7 @@ public interface ConfigureSection {
|
|||||||
* Get the value as a {@link Integer} from the specified path.
|
* Get the value as a {@link Integer} from the specified path.
|
||||||
*
|
*
|
||||||
* @param path The path to get the int.
|
* @param path The path to get the int.
|
||||||
* @return The int if the path exists and is a int, otherwise 0.
|
* @return The int if the path exists and is an 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);
|
||||||
@@ -339,7 +571,7 @@ public interface ConfigureSection {
|
|||||||
*
|
*
|
||||||
* @param path The path to get the int.
|
* @param path The path to get the int.
|
||||||
* @param def The default value to return if the path does not exist.
|
* @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.
|
* @return The int if the path exists and is an 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) {
|
||||||
@@ -638,8 +870,14 @@ public interface ConfigureSection {
|
|||||||
return stream(path).map(parser);
|
return stream(path).map(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default String childPath(String path) {
|
||||||
|
int index = path.indexOf(pathSeparator());
|
||||||
|
return (index == -1) ? path : path.substring(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
static <T, C extends Collection<T>> @NotNull C parseCollection(
|
static <T, C extends Collection<T>> @NotNull C parseCollection(
|
||||||
@Nullable List<?> data, @NotNull Supplier<C> constructor,
|
@Nullable List<?> data,
|
||||||
|
@NotNull Supplier<C> constructor,
|
||||||
@NotNull DataFunction<Object, T> parser
|
@NotNull DataFunction<Object, T> parser
|
||||||
) {
|
) {
|
||||||
C values = constructor.get();
|
C values = constructor.get();
|
||||||
|
|||||||
@@ -2,13 +2,10 @@ 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 cc.carm.lib.configuration.source.option.StandardOptions;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.*;
|
||||||
import org.jetbrains.annotations.Contract;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ConfigureSource represents the source of configuration,
|
* ConfigureSource represents the source of configuration,
|
||||||
@@ -17,6 +14,7 @@ import java.util.Map;
|
|||||||
* @param <SECTION> The type of the root section.
|
* @param <SECTION> The type of the root section.
|
||||||
* @param <ORIGINAL> The original configuration object.
|
* @param <ORIGINAL> The original configuration object.
|
||||||
* @param <SELF> The type of the source itself, for further implement support.
|
* @param <SELF> The type of the source itself, for further implement support.
|
||||||
|
* @see ConfigureSection
|
||||||
*/
|
*/
|
||||||
public abstract class ConfigureSource<
|
public abstract class ConfigureSource<
|
||||||
SECTION extends ConfigureSection, ORIGINAL,
|
SECTION extends ConfigureSection, ORIGINAL,
|
||||||
@@ -94,36 +92,36 @@ public abstract class ConfigureSource<
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String path() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Map<String, Object> getValues(boolean deep) {
|
public @NotNull Map<String, Object> getValues(boolean deep) {
|
||||||
return section().getValues(deep);
|
return section().getValues(deep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
|
||||||
|
return section().getKeys(deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
|
return section().createSection(path, data);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(@NotNull String path, @Nullable Object value) {
|
public void set(@NotNull String path, @Nullable Object value) {
|
||||||
section().set(path, value);
|
section().set(path, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean contains(@NotNull String path) {
|
|
||||||
return section().contains(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(@NotNull String path) {
|
public void remove(@NotNull String path) {
|
||||||
section().remove(path);
|
section().remove(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable List<?> getList(@NotNull String path) {
|
|
||||||
return section().getList(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
|
||||||
return section().getSection(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Object get(@NotNull String path) {
|
public @Nullable Object get(@NotNull String path) {
|
||||||
return section().get(path);
|
return section().get(path);
|
||||||
|
|||||||
+1
-1
@@ -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.2</version>
|
<version>4.0.7</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public class UserRecord extends AbstractRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static UserRecord deserialize(ConfigureSection section) {
|
public static UserRecord deserialize(ConfigureSection section) {
|
||||||
|
System.out.println("> Deserializing -> " + section.fullPath());
|
||||||
String name = section.getString("name");
|
String name = section.getString("name");
|
||||||
if (name == null) throw new NullPointerException("name is null");
|
if (name == null) throw new NullPointerException("name is null");
|
||||||
String uuidString = section.getString("info.uuid");
|
String uuidString = section.getString("info.uuid");
|
||||||
|
|||||||
@@ -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.2</version>
|
<version>4.0.7</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -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.2</version>
|
<version>4.0.7</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -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.2</version>
|
<version>4.0.7</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
+161
@@ -0,0 +1,161 @@
|
|||||||
|
package cc.carm.lib.configuration.source.section;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public abstract class AbstractMapSection<R extends AbstractMapSection<R>> implements ConfigureSection {
|
||||||
|
|
||||||
|
protected final @NotNull Map<String, Object> data;
|
||||||
|
protected final @Nullable R parent;
|
||||||
|
protected final @NotNull String path;
|
||||||
|
|
||||||
|
protected AbstractMapSection(@Nullable R parent, @NotNull String path) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.path = path;
|
||||||
|
this.data = new LinkedHashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void migrate(Map<?, ?> data) {
|
||||||
|
for (Map.Entry<?, ?> entry : data.entrySet()) {
|
||||||
|
String key = (entry.getKey() == null) ? "" : entry.getKey().toString();
|
||||||
|
if (entry.getValue() instanceof Map) {
|
||||||
|
this.data.put(key, createSection(key, (Map<?, ?>) entry.getValue()));
|
||||||
|
} else if (entry.getValue() instanceof List) {
|
||||||
|
List<Object> list = new ArrayList<>();
|
||||||
|
int index = 0;
|
||||||
|
for (Object obj : (List<?>) entry.getValue()) {
|
||||||
|
if (obj instanceof Map) {
|
||||||
|
list.add(createSection(key + "[" + index + "]", (Map<?, ?>) obj));
|
||||||
|
} else {
|
||||||
|
list.add(obj);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
this.data.put(key, list);
|
||||||
|
} else {
|
||||||
|
this.data.put(key, entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract @NotNull R self();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract @NotNull R createSection(@NotNull String path, @NotNull Map<?, ?> data);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String path() {
|
||||||
|
return this.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(@NotNull String path) {
|
||||||
|
R section = getSectionFor(path);
|
||||||
|
if (section == this) {
|
||||||
|
return this.data().containsKey(path);
|
||||||
|
} else {
|
||||||
|
return section.contains(childPath(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull Map<String, Object> data() {
|
||||||
|
return this.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return this.data.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size(boolean deep) {
|
||||||
|
return deep ? getKeys(true).size() : this.data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@UnmodifiableView
|
||||||
|
public @NotNull Map<String, Object> rawMap() {
|
||||||
|
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());
|
||||||
|
} else {
|
||||||
|
output.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable R parent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Map<String, Object> getValues(boolean deep) {
|
||||||
|
return Collections.unmodifiableMap(deep ? mappingValues(this, null, true, String.valueOf(pathSeparator())) : data());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(@NotNull String path, @Nullable Object value) {
|
||||||
|
if (value instanceof Map) value = createSection(path, (Map<?, ?>) value);
|
||||||
|
|
||||||
|
R section = getSectionFor(path);
|
||||||
|
if (section == this) {
|
||||||
|
// Even this value is null, we still need to put it in the map
|
||||||
|
// to ensure that the path is marked as existing.
|
||||||
|
this.data.put(path, value);
|
||||||
|
} else {
|
||||||
|
section.set(childPath(path), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(@NotNull String path) {
|
||||||
|
R section = getSectionFor(path);
|
||||||
|
if (section != this) {
|
||||||
|
section.remove(childPath(path));
|
||||||
|
} else {
|
||||||
|
this.data.remove(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Object get(@NotNull String path) {
|
||||||
|
R section = getSectionFor(path);
|
||||||
|
return section == this ? data.get(path) : section.get(childPath(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private R getSectionFor(String path) {
|
||||||
|
int index = path.indexOf(pathSeparator());
|
||||||
|
if (index == -1) return self();
|
||||||
|
|
||||||
|
String root = path.substring(0, index);
|
||||||
|
return (R) computeSection(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map the values of the children of the section to the output map.
|
||||||
|
*
|
||||||
|
* @param section The section to map the values from
|
||||||
|
* @param parent The parent path
|
||||||
|
* @param deep If the mapping should be deep
|
||||||
|
*/
|
||||||
|
protected static Map<String, Object> mappingValues(@NotNull AbstractMapSection<?> section, @Nullable String parent, boolean deep, String pathSeparator) {
|
||||||
|
Map<String, Object> output = new LinkedHashMap<>();
|
||||||
|
for (Map.Entry<String, Object> entry : section.data().entrySet()) {
|
||||||
|
String path = (parent == null ? "" : parent + pathSeparator) + entry.getKey();
|
||||||
|
output.remove(path);
|
||||||
|
output.put(path, entry.getValue());
|
||||||
|
if (deep && entry.getValue() instanceof AbstractMapSection<?>) {
|
||||||
|
output.putAll(mappingValues((AbstractMapSection<?>) entry.getValue(), path, true, pathSeparator));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
+377
@@ -0,0 +1,377 @@
|
|||||||
|
package cc.carm.lib.configuration.source.section;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.function.DataFunction;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ImmutableSection implements ConfigureSection {
|
||||||
|
|
||||||
|
public static ImmutableSection of(@NotNull ConfigureSection section) {
|
||||||
|
if (section instanceof ImmutableSection) {
|
||||||
|
return (ImmutableSection) section;
|
||||||
|
} else return new ImmutableSection(null, section);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final @Nullable ImmutableSection parent;
|
||||||
|
protected final @NotNull ConfigureSection section;
|
||||||
|
|
||||||
|
private ImmutableSection(@Nullable ImmutableSection parent, @NotNull ConfigureSection section) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.section = section;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ImmutableSection parent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String path() {
|
||||||
|
return section().path();
|
||||||
|
}
|
||||||
|
|
||||||
|
private @NotNull ConfigureSection section() {
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Map<String, Object> getValues(boolean deep) {
|
||||||
|
return section().getValues(deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(@NotNull String path, @Nullable Object value) {
|
||||||
|
throw new IllegalStateException("This section is not modifiable!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(@NotNull String path) {
|
||||||
|
throw new IllegalStateException("This section is not modifiable!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ImmutableSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
|
return new ImmutableSection(this, section().createSection(path, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Object get(@NotNull String path) {
|
||||||
|
Object value = section().get(path);
|
||||||
|
if (value instanceof ConfigureSection && !(value instanceof ImmutableSection)) {
|
||||||
|
return new ImmutableSection(this, (ConfigureSection) value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
||||||
|
ConfigureSection get = section().getSection(path);
|
||||||
|
if (get != null && !(get instanceof ImmutableSection)) {
|
||||||
|
return new ImmutableSection(this, get);
|
||||||
|
}
|
||||||
|
return get;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char pathSeparator() {
|
||||||
|
return section().pathSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRoot() {
|
||||||
|
return section().isRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return section().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
|
||||||
|
return section().getKeys(deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Set<String> keys() {
|
||||||
|
return section().keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Map<String, Object> values() {
|
||||||
|
return section().values();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Stream<Map.Entry<String, Object>> stream() {
|
||||||
|
return section().stream();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEach(@NotNull BiConsumer<String, Object> action) {
|
||||||
|
section().forEach(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean contains(@NotNull String path) {
|
||||||
|
return section().contains(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean containsValue(@NotNull String path) {
|
||||||
|
return section().containsValue(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> boolean isType(@NotNull String path, @NotNull Class<T> typeClass) {
|
||||||
|
return section().isType(path, typeClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isList(@NotNull String path) {
|
||||||
|
return section().isList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable List<?> getList(@NotNull String path) {
|
||||||
|
return section().getList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSection(@NotNull String path) {
|
||||||
|
return section().isSection(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T get(@NotNull String path, @NotNull Class<T> type) {
|
||||||
|
return section().get(path, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T get(@NotNull String path, @NotNull DataFunction<@Nullable Object, T> parser) {
|
||||||
|
return section().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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> @Nullable T get(@NotNull String path, @Nullable T defaultValue, @NotNull DataFunction<Object, T> parser) {
|
||||||
|
return section().get(path, defaultValue, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBoolean(@NotNull String path) {
|
||||||
|
return section().isBoolean(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getBoolean(@NotNull String path) {
|
||||||
|
return section().getBoolean(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Boolean getBoolean(@NotNull String path, @Nullable Boolean def) {
|
||||||
|
return section().getBoolean(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Boolean isByte(@NotNull String path) {
|
||||||
|
return section().isByte(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Byte getByte(@NotNull String path) {
|
||||||
|
return section().getByte(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Byte getByte(@NotNull String path, @Nullable Byte def) {
|
||||||
|
return section().getByte(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isShort(@NotNull String path) {
|
||||||
|
return section().isShort(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Short getShort(@NotNull String path) {
|
||||||
|
return section().getShort(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Short getShort(@NotNull String path, @Nullable Short def) {
|
||||||
|
return section().getShort(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInt(@NotNull String path) {
|
||||||
|
return section().isInt(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Integer getInt(@NotNull String path) {
|
||||||
|
return section().getInt(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Integer getInt(@NotNull String path, @Nullable Integer def) {
|
||||||
|
return section().getInt(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLong(@NotNull String path) {
|
||||||
|
return section().isLong(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Long getLong(@NotNull String path) {
|
||||||
|
return section().getLong(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Long getLong(@NotNull String path, @Nullable Long def) {
|
||||||
|
return section().getLong(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFloat(@NotNull String path) {
|
||||||
|
return section().isFloat(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Float getFloat(@NotNull String path) {
|
||||||
|
return section().getFloat(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Float getFloat(@NotNull String path, @Nullable Float def) {
|
||||||
|
return section().getFloat(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDouble(@NotNull String path) {
|
||||||
|
return section().isDouble(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Double getDouble(@NotNull String path) {
|
||||||
|
return section().getDouble(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Double getDouble(@NotNull String path, @Nullable Double def) {
|
||||||
|
return section().getDouble(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChar(@NotNull String path) {
|
||||||
|
return section().isChar(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Character getChar(@NotNull String path) {
|
||||||
|
return section().getChar(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Character getChar(@NotNull String path, @Nullable Character def) {
|
||||||
|
return section().getChar(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isString(@NotNull String path) {
|
||||||
|
return section().isString(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String getString(@NotNull String path) {
|
||||||
|
return section().getString(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String getString(@NotNull String path, @Nullable String def) {
|
||||||
|
return section().getString(path, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull <V> List<V> getList(@NotNull String path, @NotNull DataFunction<Object, V> parser) {
|
||||||
|
return section().getList(path, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<String> getStringList(@NotNull String path) {
|
||||||
|
return section().getStringList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Integer> getIntegerList(@NotNull String path) {
|
||||||
|
return section().getIntegerList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Long> getLongList(@NotNull String path) {
|
||||||
|
return section().getLongList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Double> getDoubleList(@NotNull String path) {
|
||||||
|
return section().getDoubleList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Float> getFloatList(@NotNull String path) {
|
||||||
|
return section().getFloatList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Byte> getByteList(@NotNull String path) {
|
||||||
|
return section().getByteList(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<Character> getCharList(@NotNull String path) {
|
||||||
|
return section().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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Stream<?> stream(@NotNull String path) {
|
||||||
|
return section().stream(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull <T> Stream<T> stream(@NotNull String path, @NotNull Function<Object, T> parser) {
|
||||||
|
return section().stream(path, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String childPath(String path) {
|
||||||
|
return section().childPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return section.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return Objects.equals(section, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+28
-135
@@ -3,161 +3,54 @@ package cc.carm.lib.configuration.source.section;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class MemorySection implements ConfigureSection {
|
public class MemorySection extends AbstractMapSection<MemorySection> {
|
||||||
|
|
||||||
public static @NotNull MemorySection root(@NotNull ConfigureSource<? extends MemorySection, ?, ?> source) {
|
public static MemorySection of() {
|
||||||
return new MemorySection(source, new LinkedHashMap<>(), null);
|
return of(new LinkedHashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @NotNull MemorySection root(@NotNull ConfigureSource<? extends MemorySection, ?, ?> source,
|
public static MemorySection of(@NotNull Consumer<Map<String, Object>> data) {
|
||||||
@Nullable Map<?, ?> data) {
|
return of(() -> {
|
||||||
return new MemorySection(source, data == null ? new LinkedHashMap<>() : data, null);
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
|
data.accept(map);
|
||||||
|
return map;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final @NotNull ConfigureSource<? extends MemorySection, ?, ?> source;
|
public static MemorySection of(@NotNull Supplier<Map<?, ?>> data) {
|
||||||
protected final @NotNull Map<String, Object> data;
|
return of(data.get());
|
||||||
protected final @Nullable MemorySection parent;
|
|
||||||
|
|
||||||
public MemorySection(@NotNull ConfigureSource<? extends MemorySection, ?, ?> source,
|
|
||||||
@NotNull Map<?, ?> data, @Nullable MemorySection parent) {
|
|
||||||
this.source = source;
|
|
||||||
this.parent = parent;
|
|
||||||
this.data = new LinkedHashMap<>();
|
|
||||||
for (Map.Entry<?, ?> entry : data.entrySet()) {
|
|
||||||
String key = (entry.getKey() == null) ? "null" : entry.getKey().toString();
|
|
||||||
if (entry.getValue() instanceof Map) {
|
|
||||||
this.data.put(key, createChild((Map<?, ?>) entry.getValue()));
|
|
||||||
} else if (entry.getValue() instanceof List) {
|
|
||||||
List<Object> list = new ArrayList<>();
|
|
||||||
for (Object obj : (List<?>) entry.getValue()) {
|
|
||||||
if (obj instanceof Map) {
|
|
||||||
list.add(createChild((Map<?, ?>) obj));
|
|
||||||
} else {
|
|
||||||
list.add(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.data.put(key, list);
|
|
||||||
} else {
|
|
||||||
this.data.put(key, entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected @NotNull MemorySection createChild(@NotNull Map<?, ?> data) {
|
public static MemorySection of(@NotNull Map<?, ?> data) {
|
||||||
return new MemorySection(source(), data, this);
|
return of(data, null, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected @NotNull MemorySection createChild() {
|
public static MemorySection of(@Nullable MemorySection parent, @NotNull String path) {
|
||||||
return createChild(new LinkedHashMap<>());
|
return of(new LinkedHashMap<>(), parent, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull ConfigureSource<? extends MemorySection, ?, ?> source() {
|
public static MemorySection of(@NotNull Map<?, ?> data, @Nullable MemorySection parent, @NotNull String path) {
|
||||||
return this.source;
|
return new MemorySection(data, parent, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull Map<String, Object> data() {
|
public MemorySection(@NotNull Map<?, ?> raw, @Nullable MemorySection parent, @NotNull String path) {
|
||||||
return this.data;
|
super(parent, path);
|
||||||
}
|
migrate(raw);
|
||||||
|
|
||||||
public @Nullable MemorySection parent() {
|
|
||||||
return this.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public char pathSeparator() {
|
|
||||||
return source.pathSeparator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Map<String, Object> getValues(boolean deep) {
|
public @NotNull MemorySection self() {
|
||||||
return Collections.unmodifiableMap(deep ? mapChildrenValues(this, null, true) : data());
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(@NotNull String path, @Nullable Object value) {
|
public @NotNull MemorySection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
if (value instanceof Map) value = createChild((Map<?, ?>) value);
|
return new MemorySection(data, this, path);
|
||||||
|
|
||||||
MemorySection section = getSectionFor(path);
|
|
||||||
if (section == this) {
|
|
||||||
// Even this value is null, we still need to put it in the map
|
|
||||||
// to ensure that the path is marked as existing.
|
|
||||||
this.data.put(path, value);
|
|
||||||
} else {
|
|
||||||
section.set(childPath(path), value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove(@NotNull String path) {
|
|
||||||
MemorySection section = getSectionFor(path);
|
|
||||||
if (section != this) {
|
|
||||||
section.remove(childPath(path));
|
|
||||||
} else {
|
|
||||||
this.data.remove(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean contains(@NotNull String path) {
|
|
||||||
return get(path) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable Object get(@NotNull String path) {
|
|
||||||
MemorySection section = getSectionFor(path);
|
|
||||||
return section == this ? data.get(path) : section.get(childPath(path));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable List<?> getList(@NotNull String path) {
|
|
||||||
Object val = get(path);
|
|
||||||
return (val instanceof List<?>) ? (List<?>) val : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
|
||||||
Object val = get(path);
|
|
||||||
return (val instanceof ConfigureSection) ? (ConfigureSection) val : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MemorySection getSectionFor(String path) {
|
|
||||||
int index = path.indexOf(pathSeparator());
|
|
||||||
if (index == -1) return this;
|
|
||||||
|
|
||||||
String root = path.substring(0, index);
|
|
||||||
Object section = this.data.get(root);
|
|
||||||
if (section == null) {
|
|
||||||
section = createChild();
|
|
||||||
this.data.put(root, section);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (MemorySection) section;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String childPath(String path) {
|
|
||||||
int index = path.indexOf(pathSeparator());
|
|
||||||
return (index == -1) ? path : path.substring(index + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map the values of the children of the section to the output map.
|
|
||||||
*
|
|
||||||
* @param section The section to map the values from
|
|
||||||
* @param parent The parent path
|
|
||||||
* @param deep If the mapping should be deep
|
|
||||||
*/
|
|
||||||
protected Map<String, Object> mapChildrenValues(@NotNull MemorySection section,
|
|
||||||
@Nullable String parent, boolean deep) {
|
|
||||||
Map<String, Object> output = new LinkedHashMap<>();
|
|
||||||
for (Map.Entry<String, Object> entry : section.data().entrySet()) {
|
|
||||||
String path = (parent == null ? "" : parent + pathSeparator()) + entry.getKey();
|
|
||||||
output.remove(path);
|
|
||||||
output.put(path, entry.getValue());
|
|
||||||
if (deep && entry.getValue() instanceof MemorySection) {
|
|
||||||
output.putAll(mapChildrenValues((MemorySection) entry.getValue(), path, true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+145
@@ -0,0 +1,145 @@
|
|||||||
|
package cc.carm.lib.configuration.source.section;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.annotations.UnmodifiableView;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class ShadedSection implements ConfigureSection {
|
||||||
|
|
||||||
|
public static ShadedSection create(@NotNull ConfigureSection template, @Nullable ConfigureSection source) {
|
||||||
|
return new ShadedSection(null, template, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final @Nullable ShadedSection parent;
|
||||||
|
protected @NotNull ConfigureSection template;
|
||||||
|
protected @Nullable ConfigureSection source;
|
||||||
|
|
||||||
|
public ShadedSection(@Nullable ShadedSection parent,
|
||||||
|
@NotNull ConfigureSection template, @Nullable ConfigureSection source) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.template = template;
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ConfigureSection parent() {
|
||||||
|
return this.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String path() {
|
||||||
|
return this.template.path();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Map<String, Object> getValues(boolean deep) {
|
||||||
|
if (source == null) return template.getValues(deep);
|
||||||
|
// 本函数为,当 getValues 时,递归合并 source 和 template
|
||||||
|
return merge(template, source).getValues(deep);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull @UnmodifiableView Set<String> getKeys(boolean deep) {
|
||||||
|
Set<String> keys = new HashSet<>(template.getKeys(deep));
|
||||||
|
if (source != null) {
|
||||||
|
keys.addAll(source.getKeys(deep));
|
||||||
|
}
|
||||||
|
return Collections.unmodifiableSet(keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConfigureSection merge(ConfigureSection templateSection, ConfigureSection valueSection) {
|
||||||
|
MemorySection merged = MemorySection.of();
|
||||||
|
Set<String> existingKey = new HashSet<>();
|
||||||
|
|
||||||
|
for (Map.Entry<String, Object> entry : valueSection.getValues(false).entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value instanceof ConfigureSection) {
|
||||||
|
ConfigureSection subSectionFromValue = (ConfigureSection) value;
|
||||||
|
ConfigureSection subSectionFromTemplate = (ConfigureSection) templateSection.get(key);
|
||||||
|
if (subSectionFromTemplate == null) {
|
||||||
|
merged.set(key, value);
|
||||||
|
} else {
|
||||||
|
merged.set(key, merge(subSectionFromTemplate, subSectionFromValue));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
merged.set(key, value);
|
||||||
|
}
|
||||||
|
existingKey.add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<String, Object> entry : templateSection.getValues(false).entrySet()) {
|
||||||
|
if (existingKey.contains(entry.getKey())) continue;
|
||||||
|
merged.set(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(@NotNull String path, @Nullable Object value) {
|
||||||
|
if (value instanceof ConfigureSection) {
|
||||||
|
ConfigureSection targetSection = (ConfigureSection) value;
|
||||||
|
for (Map.Entry<String, Object> entry : targetSection.getValues(true).entrySet()) {
|
||||||
|
set(path + pathSeparator() + entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if (Objects.equals(get(path), value)) {
|
||||||
|
remove(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional.ofNullable(source).ifPresent(s -> s.set(path, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void remove(@NotNull String path) {
|
||||||
|
Optional.ofNullable(source).ifPresent(s -> s.remove(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull ConfigureSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
|
if (source == null) {
|
||||||
|
return new ShadedSection(this, template, MemorySection.of(data));
|
||||||
|
} else {
|
||||||
|
ConfigureSection section = source.computeSection(path, data);
|
||||||
|
return new ShadedSection(this, template, section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable Object get(@NotNull String path) {
|
||||||
|
if (source == null) {
|
||||||
|
return getFromTemplate(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = source.get(path);
|
||||||
|
if (value == null) {
|
||||||
|
return getFromTemplate(path);
|
||||||
|
}
|
||||||
|
if (value instanceof ConfigureSection) {
|
||||||
|
ConfigureSection templateSection = (ConfigureSection) template.get(path);
|
||||||
|
if (templateSection == null) {
|
||||||
|
return value;
|
||||||
|
} else {
|
||||||
|
return new ShadedSection(this, templateSection, (ConfigureSection) value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Object getFromTemplate(@NotNull String path) {
|
||||||
|
Object value = template.get(path);
|
||||||
|
if (value instanceof ConfigureSection) {
|
||||||
|
return new ShadedSection(this, (ConfigureSection) value, null);
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable ConfigureSection getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
package cc.carm.lib.configuration.source.section;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SourcedSection extends AbstractMapSection<SourcedSection> {
|
||||||
|
|
||||||
|
public static @NotNull SourcedSection root(@NotNull ConfigureSource<? extends SourcedSection, ?, ?> source) {
|
||||||
|
return new SourcedSection(source, new LinkedHashMap<>(), null, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull SourcedSection root(@NotNull ConfigureSource<? extends SourcedSection, ?, ?> source,
|
||||||
|
@Nullable Map<?, ?> raw) {
|
||||||
|
return new SourcedSection(source, raw == null ? new LinkedHashMap<>() : raw, null, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final @NotNull ConfigureSource<? extends SourcedSection, ?, ?> source;
|
||||||
|
|
||||||
|
public SourcedSection(@NotNull ConfigureSource<? extends SourcedSection, ?, ?> source,
|
||||||
|
@NotNull Map<?, ?> raw, @Nullable SourcedSection parent, @NotNull String path) {
|
||||||
|
super(parent, path);
|
||||||
|
this.source = source;
|
||||||
|
migrate(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull ConfigureSource<? extends SourcedSection, ?, ?> source() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char pathSeparator() {
|
||||||
|
return source().pathSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull SourcedSection self() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull SourcedSection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
|
||||||
|
return new SourcedSection(source(), data, this, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package test.section;
|
||||||
|
|
||||||
|
import cc.carm.lib.configuration.source.section.ConfigureSection;
|
||||||
|
import cc.carm.lib.configuration.source.section.MemorySection;
|
||||||
|
import cc.carm.lib.configuration.source.section.ShadedSection;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Lyzen
|
||||||
|
* @date 21/2/2025 下午2:18
|
||||||
|
*/
|
||||||
|
public class ShadeTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
ConfigureSection template = MemorySection.of(data -> {
|
||||||
|
data.put("name", "GentleMan");
|
||||||
|
data.put("age", 12);
|
||||||
|
data.put("gender", "male");
|
||||||
|
Map<String, Object> address = new LinkedHashMap<>();
|
||||||
|
address.put("Hotel", "Nanjing Road 101");
|
||||||
|
address.put("Store", "Beijing Road 404");
|
||||||
|
Map<String, Object> mapInside = new LinkedHashMap<>();
|
||||||
|
mapInside.put("InsideKeyExample", "InsideValueExample");
|
||||||
|
address.put("Inside", mapInside);
|
||||||
|
data.put("addresses", address);
|
||||||
|
data.put("cards", Arrays.asList("00000", "11111", "22222"));
|
||||||
|
});
|
||||||
|
ConfigureSection source = MemorySection.of(data -> {
|
||||||
|
data.put("age", 25);
|
||||||
|
Map<String, Object> address = new LinkedHashMap<>();
|
||||||
|
address.put("NewOne", "Guangdong Road 505");
|
||||||
|
data.put("addresses", address);
|
||||||
|
Map<String, Object> mapInside = new LinkedHashMap<>();
|
||||||
|
mapInside.put("AnotherInsideKey", "AnotherInsideValue");
|
||||||
|
address.put("Inside", mapInside);
|
||||||
|
data.put("cards", Arrays.asList("33333", "55555")); // 应当直接覆盖原先的List
|
||||||
|
});
|
||||||
|
|
||||||
|
ShadedSection root = new ShadedSection(null, template, source);
|
||||||
|
System.out.println("age: " + root.get("age"));
|
||||||
|
System.out.println("addresses: ");
|
||||||
|
for (Map.Entry<String, Object> entry : root.getSection("addresses").getValues(false).entrySet()) {
|
||||||
|
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
|
||||||
|
if (entry.getValue() instanceof ConfigureSection) {
|
||||||
|
for (Map.Entry<String, Object> inner : ((ConfigureSection) entry.getValue()).getValues(false).entrySet()) {
|
||||||
|
System.out.println(" " + inner.getKey() + ": " + inner.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println("cards: " + root.getList("cards"));
|
||||||
|
|
||||||
|
System.out.println("\n----------------------\n");
|
||||||
|
System.out.println("Deep Search Test");
|
||||||
|
System.out.println("addresses: ");
|
||||||
|
for (Map.Entry<String, Object> entry : root.getSection("addresses").getValues(true).entrySet()) {
|
||||||
|
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("\n----------------------\n");
|
||||||
|
|
||||||
|
root.set("addresses", MemorySection.of(map -> {
|
||||||
|
map.put("Hotel", "Nanjing Road 101");
|
||||||
|
map.put("Store", "Beijing Road banned");
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
for (Map.Entry<String, Object> entry : source.getValues(true).entrySet()) {
|
||||||
|
System.out.println(" " + entry.getKey() + ": " + entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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.2</version>
|
<version>4.0.7</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -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.2</version>
|
<version>4.0.7</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -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.2</version>
|
<version>4.0.7</version>
|
||||||
<modules>
|
<modules>
|
||||||
<module>core</module>
|
<module>core</module>
|
||||||
<module>features/section</module>
|
<module>features/section</module>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<name>EasyConfiguration</name>
|
<name>EasyConfiguration</name>
|
||||||
<description>轻松(做)配置,简单便捷的通用配置文件加载、读取与更新工具,可自定义配置格式。</description>
|
<description>A simple, easy-to-use and universal solution for managing configuration files.</description>
|
||||||
<url>https://github.com/CarmJos/EasyConfiguration</url>
|
<url>https://github.com/CarmJos/EasyConfiguration</url>
|
||||||
|
|
||||||
<developers>
|
<developers>
|
||||||
@@ -89,12 +89,6 @@
|
|||||||
<url>https://repo1.maven.org/maven2/</url>
|
<url>https://repo1.maven.org/maven2/</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
<repository>
|
|
||||||
<id>github</id>
|
|
||||||
<name>GitHub Packages</name>
|
|
||||||
<url>https://maven.pkg.github.com/CarmJos/*</url>
|
|
||||||
</repository>
|
|
||||||
|
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<distributionManagement>
|
<distributionManagement>
|
||||||
@@ -202,7 +196,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<version>3.13.0</version>
|
<version>3.14.0</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>${project.jdk.version}</source>
|
<source>${project.jdk.version}</source>
|
||||||
<target>${project.jdk.version}</target>
|
<target>${project.jdk.version}</target>
|
||||||
|
|||||||
@@ -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.2</version>
|
<version>4.0.7</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package cc.carm.lib.configuration.source.json;
|
|||||||
|
|
||||||
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.section.MemorySection;
|
import cc.carm.lib.configuration.source.section.SourcedSection;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.JsonSerializer;
|
import com.google.gson.JsonSerializer;
|
||||||
@@ -14,17 +14,17 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class JSONSource extends FileConfigSource<MemorySection, Map<String, Object>, JSONSource> {
|
public class JSONSource extends FileConfigSource<SourcedSection, Map<String, Object>, JSONSource> {
|
||||||
|
|
||||||
public static final @NotNull Gson DEFAULT_GSON = new GsonBuilder()
|
public static final @NotNull Gson DEFAULT_GSON = new GsonBuilder()
|
||||||
.serializeNulls().disableHtmlEscaping().setPrettyPrinting()
|
.serializeNulls().disableHtmlEscaping().setPrettyPrinting()
|
||||||
.registerTypeAdapter(
|
.registerTypeAdapter(
|
||||||
MemorySection.class,
|
SourcedSection.class,
|
||||||
(JsonSerializer<MemorySection>) (src, t, c) -> c.serialize(src.data())
|
(JsonSerializer<SourcedSection>) (src, t, c) -> c.serialize(src.data())
|
||||||
).create();
|
).create();
|
||||||
|
|
||||||
protected final @NotNull Gson gson;
|
protected final @NotNull Gson gson;
|
||||||
protected @Nullable MemorySection rootSection;
|
protected @Nullable SourcedSection rootSection;
|
||||||
|
|
||||||
protected JSONSource(@NotNull ConfigurationHolder<? extends JSONSource> holder,
|
protected JSONSource(@NotNull ConfigurationHolder<? extends JSONSource> holder,
|
||||||
@NotNull File file, @Nullable String resourcePath) {
|
@NotNull File file, @Nullable String resourcePath) {
|
||||||
@@ -58,7 +58,7 @@ public class JSONSource extends FileConfigSource<MemorySection, Map<String, Obje
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull MemorySection section() {
|
public @NotNull SourcedSection section() {
|
||||||
return Objects.requireNonNull(this.rootSection, "Root section is not initialized");
|
return Objects.requireNonNull(this.rootSection, "Root section is not initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ public class JSONSource extends FileConfigSource<MemorySection, Map<String, Obje
|
|||||||
@Override
|
@Override
|
||||||
protected void onReload() throws Exception {
|
protected void onReload() throws Exception {
|
||||||
Map<?, ?> data = fileReader(reader -> gson.fromJson(reader, LinkedHashMap.class));
|
Map<?, ?> data = fileReader(reader -> gson.fromJson(reader, LinkedHashMap.class));
|
||||||
this.rootSection = MemorySection.root(this, data);
|
this.rootSection = SourcedSection.root(this, data);
|
||||||
this.lastUpdateMillis = System.currentTimeMillis(); // 更新时间
|
this.lastUpdateMillis = System.currentTimeMillis(); // 更新时间
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,74 +62,3 @@ dependencies {
|
|||||||
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
|
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Example file format
|
|
||||||
```yaml
|
|
||||||
version: 1.0.0
|
|
||||||
|
|
||||||
test-save: false
|
|
||||||
|
|
||||||
test-number: 6161926779561752576
|
|
||||||
|
|
||||||
test-enum: DAYS
|
|
||||||
|
|
||||||
# Section类型数据测试
|
|
||||||
user: # Section数据也支持InlineComment注释
|
|
||||||
name: '35882'
|
|
||||||
info:
|
|
||||||
uuid: 554b79f1-7c39-4960-82d1-5514c9734417
|
|
||||||
|
|
||||||
uuid-value: 9a86663e-2fc7-4851-a423-c7e5d8e94a47 # This is an inline comment
|
|
||||||
|
|
||||||
sub:
|
|
||||||
that:
|
|
||||||
operators: []
|
|
||||||
|
|
||||||
# [ID - UUID]对照表
|
|
||||||
|
|
||||||
# 用于测试Map类型的解析与序列化保存
|
|
||||||
users:
|
|
||||||
'1': 1c055bdd-c9d1-4931-8270-3d162247f38a
|
|
||||||
'2': 934e2b05-2417-424e-80fd-fe58c6725837
|
|
||||||
'3': 442949a2-8345-4210-a87b-593d7168980e
|
|
||||||
'4': 5c015453-4b5b-42e3-ad87-b9498f2dfeab
|
|
||||||
'5': 8f9640e7-0fbd-4f73-b737-f0b707215e71
|
|
||||||
|
|
||||||
# Inner Test
|
|
||||||
inner:
|
|
||||||
inner-value: 51.223503560658166
|
|
||||||
|
|
||||||
class-value: 1.0
|
|
||||||
|
|
||||||
test:
|
|
||||||
# Section类型数据测试
|
|
||||||
user: # Section数据也支持InlineComment注释
|
|
||||||
name: Carm
|
|
||||||
info:
|
|
||||||
uuid: 3d1ef2a0-a38b-44f3-b15f-8e3b22cb8cc6
|
|
||||||
|
|
||||||
# 以下内容用于测试序列化
|
|
||||||
model-test:
|
|
||||||
some-model:
|
|
||||||
==: SomeModel
|
|
||||||
num: 855
|
|
||||||
name: 4f6b7
|
|
||||||
any-model:
|
|
||||||
==: AnyModel
|
|
||||||
name: 63d05
|
|
||||||
state: false
|
|
||||||
models:
|
|
||||||
- name: 481f3
|
|
||||||
state: true
|
|
||||||
- name: fcf3e
|
|
||||||
state: false
|
|
||||||
- name: '14e50'
|
|
||||||
state: false
|
|
||||||
model-map:
|
|
||||||
a:
|
|
||||||
name: 1fb9b
|
|
||||||
state: false
|
|
||||||
b:
|
|
||||||
name: 5486f
|
|
||||||
state: false
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -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.2</version>
|
<version>4.0.7</version>
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
@@ -29,13 +29,6 @@
|
|||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>cc.carm.lib</groupId>
|
|
||||||
<artifactId>yamlcommentwriter</artifactId>
|
|
||||||
<version>1.2.0</version>
|
|
||||||
<scope>compile</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.parent.groupId}</groupId>
|
<groupId>${project.parent.groupId}</groupId>
|
||||||
<artifactId>easyconfiguration-feature-file</artifactId>
|
<artifactId>easyconfiguration-feature-file</artifactId>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ 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.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.SourcedSection;
|
||||||
import cc.carm.lib.yamlcommentupdater.CommentedSection;
|
import cc.carm.lib.yamlcommentupdater.CommentedSection;
|
||||||
import cc.carm.lib.yamlcommentupdater.CommentedYAMLWriter;
|
import cc.carm.lib.yamlcommentupdater.CommentedYAMLWriter;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -26,14 +26,14 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class YAMLSource
|
public class YAMLSource
|
||||||
extends FileConfigSource<MemorySection, Map<String, Object>, YAMLSource>
|
extends FileConfigSource<SourcedSection, Map<String, Object>, YAMLSource>
|
||||||
implements CommentedSection {
|
implements CommentedSection {
|
||||||
|
|
||||||
protected final @NotNull YamlConstructor yamlConstructor;
|
protected final @NotNull YamlConstructor yamlConstructor;
|
||||||
protected final @NotNull YamlRepresenter yamlRepresenter;
|
protected final @NotNull YamlRepresenter yamlRepresenter;
|
||||||
protected final @NotNull Yaml yaml;
|
protected final @NotNull Yaml yaml;
|
||||||
|
|
||||||
protected @Nullable MemorySection rootSection;
|
protected @Nullable SourcedSection rootSection;
|
||||||
|
|
||||||
protected YAMLSource(@NotNull ConfigurationHolder<? extends YAMLSource> holder,
|
protected YAMLSource(@NotNull ConfigurationHolder<? extends YAMLSource> holder,
|
||||||
@NotNull File file, @Nullable String resourcePath) {
|
@NotNull File file, @Nullable String resourcePath) {
|
||||||
@@ -56,7 +56,7 @@ public class YAMLSource
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @NotNull YAMLSource self() {
|
protected @NotNull YAMLSource self() {
|
||||||
return null;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -65,7 +65,7 @@ public class YAMLSource
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull MemorySection section() {
|
public @NotNull SourcedSection section() {
|
||||||
return Objects.requireNonNull(this.rootSection, "Root section is not initialized.");
|
return Objects.requireNonNull(this.rootSection, "Root section is not initialized.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,18 +130,18 @@ public class YAMLSource
|
|||||||
return this.saveToString(section());
|
return this.saveToString(section());
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull MemorySection loadFromString(@NotNull String data) throws Exception {
|
public @NotNull SourcedSection loadFromString(@NotNull String data) throws Exception {
|
||||||
MappingNode mappingNode;
|
MappingNode mappingNode;
|
||||||
try (Reader reader = new UnicodeReader(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)))) {
|
try (Reader reader = new UnicodeReader(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)))) {
|
||||||
Node rawNode = this.yaml.compose(reader);
|
Node rawNode = this.yaml.compose(reader);
|
||||||
mappingNode = (MappingNode) rawNode;
|
mappingNode = (MappingNode) rawNode;
|
||||||
}
|
}
|
||||||
if (mappingNode == null) return MemorySection.root(this);
|
if (mappingNode == null) return SourcedSection.root(this);
|
||||||
|
|
||||||
|
|
||||||
Map<String, Object> map = new LinkedHashMap<>();
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
this.constructMap(mappingNode, map);
|
this.constructMap(mappingNode, map);
|
||||||
return MemorySection.root(this, map);
|
return SourcedSection.root(this, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void constructMap(@NotNull MappingNode mappingNode, @NotNull Map<String, Object> section) {
|
private void constructMap(@NotNull MappingNode mappingNode, @NotNull Map<String, Object> section) {
|
||||||
@@ -170,7 +170,7 @@ public class YAMLSource
|
|||||||
public String serializeValue(@NotNull String key, @NotNull Object value) {
|
public String serializeValue(@NotNull String key, @NotNull Object value) {
|
||||||
Map<String, Object> map = new LinkedHashMap<>();
|
Map<String, Object> map = new LinkedHashMap<>();
|
||||||
map.put(key, value);
|
map.put(key, value);
|
||||||
return saveToString(MemorySection.root(this, map));
|
return saveToString(SourcedSection.root(this, map));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class YamlTests {
|
public class YamlTests {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user