1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2026-06-05 02:58:20 +08:00

Compare commits

...

22 Commits

Author SHA1 Message Date
carm 6f28abebb9 feat(section): Add #path and #fullPath for sections 2025-02-25 00:04:24 +08:00
LSeng 842cd78ce3 feat(section): Implement createSection() for ShadedSection 2025-02-22 23:56:45 +08:00
carm 11f1f36a15 docs: Change logo file 2025-02-22 10:13:54 +08:00
renovate[bot] ee9f29ba30 chore(deps): update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.14.0 2025-02-22 09:57:51 +08:00
carm f5bccdaad5 chore: Upgraded to 4.0.6 2025-02-22 09:57:24 +08:00
carm f5f70ff69b chore(source): Add more pre implemented functions 2025-02-22 09:56:59 +08:00
carm 3e221740bc feat(section): Implement shaded sections 2025-02-22 09:55:28 +08:00
LSeng 96d09be977 feat(section): support ShadedSection 2025-02-21 20:48:37 +08:00
carm 5d7c946db5 feat(section): Implement more sections 2025-02-21 18:45:15 +08:00
carm 9e008ff4cd feat(section): Add shaded section 2025-02-21 17:31:05 +08:00
carm df19da170b feat(section): Add #contains and #containsValue methods 2025-02-21 17:15:16 +08:00
carm 3473ef2247 feat: Implement more sections functions 2025-02-21 16:17:12 +08:00
carm d543530305 feat: Implement more sections functions 2025-02-21 16:09:58 +08:00
carm d81855697c feat: Implement more sections functions 2025-02-21 11:27:03 +08:00
carm 5c16e98f30 feat(section): Implement more sections 2025-02-21 03:20:11 +08:00
carm 3f1ffadeff feat(section): Implement more sections 2025-02-21 03:07:43 +08:00
carm d8191b7c6d feat(section): Add original method 2025-02-21 02:00:36 +08:00
carm ba66220f92 docs(sponsor): Add sponsors banner 2025-02-21 01:00:27 +08:00
carm 730d6d7e9c docs(sponsor): Add sponsors banner 2025-02-21 00:58:32 +08:00
carm 4523190cb0 feat: Upgraded to 4.0.5 2025-02-20 16:50:07 +08:00
carm 2a49e2ee6b docs: Fixed quantity usage 2025-02-20 16:49:36 +08:00
carm 77b223b2cb feat: Add stream functions 2025-02-20 16:38:49 +08:00
24 changed files with 1065 additions and 164 deletions
+5
View File
@@ -256,6 +256,11 @@ Many thanks to Jetbrains for kindly providing a license for us to work on this a
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration) [![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](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
+29 -23
View File
@@ -32,47 +32,49 @@ 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 {
@InlineComment("Enabled?") // 行后注释 @InlineComment("Enabled?") // 行后注释
ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true); ConfiguredValue<Boolean> ENABLED = ConfiguredValue.of(true);
@HeaderComments("Server configurations") // 头部注释 @HeaderComments("Server configurations") // 头部注释
ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class); ConfiguredValue<Integer> PORT = ConfiguredValue.of(Integer.class);
@HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"}) @HeaderComments({"[ UUID >-----------------------------------", "A lot of UUIDs"})
@FooterComments("[ UUID >-----------------------------------") @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(
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();
interface INFO extends Configuration { interface INFO extends Configuration {
@HeaderComments("Configure your name!") // Header comment @HeaderComments("Configure your name!") // Header comment
ConfiguredValue<String> NAME = ConfiguredValue.of("Joker"); ConfiguredValue<String> NAME = ConfiguredValue.of("Joker");
@ConfigPath("how-old-are-you") // 自定义路径 @ConfigPath("how-old-are-you") // 自定义路径
ConfiguredValue<Integer> AGE = ConfiguredValue.of(24); ConfiguredValue<Integer> AGE = ConfiguredValue.of(24);
} }
} }
@@ -244,7 +246,7 @@ dependencies {
//基于YAML文件的实现版本,可用于全部Java环境。 //基于YAML文件的实现版本,可用于全部Java环境。
api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]" api "cc.carm.lib:easyconfiguration-yaml:[LATEST RELEASE]"
//基于JSON文件的实现版本,可用于全部Java环境。 //基于JSON文件的实现版本,可用于全部Java环境。
//需要注意的是,JSON不支持文件注释。 //需要注意的是,JSON不支持文件注释。
api "cc.carm.lib:easyconfiguration-gson:[LATEST RELEASE]" api "cc.carm.lib:easyconfiguration-gson:[LATEST RELEASE]"
@@ -276,6 +278,10 @@ EasyConfiguration for MineCraft!
[![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/?from=https://github.com/CarmJos/EasyConfiguration) [![](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](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
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.4</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
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.4</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");
+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.4</version> <version>4.0.7</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.4</version> <version>4.0.7</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.4</version> <version>4.0.7</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
@@ -2,32 +2,37 @@ 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 org.jetbrains.annotations.UnmodifiableView;
import java.util.*; import java.util.*;
public abstract class MapSection<R extends MapSection<R>> implements ConfigureSection { public abstract class AbstractMapSection<R extends AbstractMapSection<R>> implements ConfigureSection {
protected final @NotNull Map<String, Object> data; protected final @NotNull Map<String, Object> data;
protected final @Nullable R parent; protected final @Nullable R parent;
protected final @NotNull String path;
protected MapSection(@Nullable R parent) { protected AbstractMapSection(@Nullable R parent, @NotNull String path) {
this.parent = parent; this.parent = parent;
this.path = path;
this.data = new LinkedHashMap<>(); this.data = new LinkedHashMap<>();
} }
public void migrate(Map<?, ?> data) { public void migrate(Map<?, ?> data) {
for (Map.Entry<?, ?> entry : data.entrySet()) { for (Map.Entry<?, ?> entry : data.entrySet()) {
String key = (entry.getKey() == null) ? "null" : entry.getKey().toString(); String key = (entry.getKey() == null) ? "" : entry.getKey().toString();
if (entry.getValue() instanceof Map) { if (entry.getValue() instanceof Map) {
this.data.put(key, createChild((Map<?, ?>) entry.getValue())); this.data.put(key, createSection(key, (Map<?, ?>) entry.getValue()));
} else if (entry.getValue() instanceof List) { } else if (entry.getValue() instanceof List) {
List<Object> list = new ArrayList<>(); List<Object> list = new ArrayList<>();
int index = 0;
for (Object obj : (List<?>) entry.getValue()) { for (Object obj : (List<?>) entry.getValue()) {
if (obj instanceof Map) { if (obj instanceof Map) {
list.add(createChild((Map<?, ?>) obj)); list.add(createSection(key + "[" + index + "]", (Map<?, ?>) obj));
} else { } else {
list.add(obj); list.add(obj);
} }
index++;
} }
this.data.put(key, list); this.data.put(key, list);
} else { } else {
@@ -38,37 +43,64 @@ public abstract class MapSection<R extends MapSection<R>> implements ConfigureSe
public abstract @NotNull R self(); public abstract @NotNull R self();
protected abstract @NotNull R createChild(@NotNull Map<?, ?> data); @Override
public abstract @NotNull R createSection(@NotNull String path, @NotNull Map<?, ?> data);
protected @NotNull R createChild() { @Override
return createChild(new LinkedHashMap<>()); 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() { public @NotNull Map<String, Object> data() {
return this.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() { public @Nullable R parent() {
return this.parent; return this.parent;
} }
/**
* Get the path separator for the section.
*
* @return The path separator
*/
public char pathSeparator() {
return '.';
}
@Override @Override
public @NotNull Map<String, Object> getValues(boolean deep) { public @NotNull Map<String, Object> getValues(boolean deep) {
return Collections.unmodifiableMap(deep ? mappingValues(this, null, true) : data()); return Collections.unmodifiableMap(deep ? mappingValues(this, null, true, String.valueOf(pathSeparator())) : data());
} }
@Override @Override
public void set(@NotNull String path, @Nullable Object value) { public void set(@NotNull String path, @Nullable Object value) {
if (value instanceof Map) value = createChild((Map<?, ?>) value); if (value instanceof Map) value = createSection(path, (Map<?, ?>) value);
R section = getSectionFor(path); R section = getSectionFor(path);
if (section == this) { if (section == this) {
@@ -90,41 +122,19 @@ public abstract class MapSection<R extends MapSection<R>> implements ConfigureSe
} }
} }
@Override
public boolean contains(@NotNull String path) {
return get(path) != null;
}
@Override @Override
public @Nullable Object get(@NotNull String path) { public @Nullable Object get(@NotNull String path) {
R section = getSectionFor(path); R section = getSectionFor(path);
return section == this ? data.get(path) : section.get(childPath(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;
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private R getSectionFor(String path) { private R getSectionFor(String path) {
int index = path.indexOf(pathSeparator()); int index = path.indexOf(pathSeparator());
if (index == -1) return self(); if (index == -1) return self();
String root = path.substring(0, index); String root = path.substring(0, index);
return (R) data().computeIfAbsent(root, k -> createChild()); return (R) computeSection(root);
}
private String childPath(String path) {
int index = path.indexOf(pathSeparator());
return (index == -1) ? path : path.substring(index + 1);
} }
/** /**
@@ -134,16 +144,18 @@ public abstract class MapSection<R extends MapSection<R>> implements ConfigureSe
* @param parent The parent path * @param parent The parent path
* @param deep If the mapping should be deep * @param deep If the mapping should be deep
*/ */
protected Map<String, Object> mappingValues(@NotNull MapSection<?> section, @Nullable String parent, boolean deep) { protected static Map<String, Object> mappingValues(@NotNull AbstractMapSection<?> section, @Nullable String parent, boolean deep, String pathSeparator) {
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 + pathSeparator()) + 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 MapSection<?>) { if (deep && entry.getValue() instanceof AbstractMapSection<?>) {
output.putAll(mappingValues((MapSection<?>) entry.getValue(), path, true)); output.putAll(mappingValues((AbstractMapSection<?>) entry.getValue(), path, true, pathSeparator));
} }
} }
return output; return output;
} }
} }
@@ -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);
}
}
@@ -5,44 +5,52 @@ import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class MemorySection extends MapSection<MemorySection> { 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<?, ?> raw) { return of(() -> {
return new MemorySection(source, raw == null ? new LinkedHashMap<>() : raw, 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) {
return of(data.get());
}
protected MemorySection(@NotNull ConfigureSource<? extends MemorySection, ?, ?> source, public static MemorySection of(@NotNull Map<?, ?> data) {
@NotNull Map<?, ?> raw, @Nullable MemorySection parent) { return of(data, null, "");
super(parent); }
this.source = source;
public static MemorySection of(@Nullable MemorySection parent, @NotNull String path) {
return of(new LinkedHashMap<>(), parent, path);
}
public static MemorySection of(@NotNull Map<?, ?> data, @Nullable MemorySection parent, @NotNull String path) {
return new MemorySection(data, parent, path);
}
public MemorySection(@NotNull Map<?, ?> raw, @Nullable MemorySection parent, @NotNull String path) {
super(parent, path);
migrate(raw); migrate(raw);
} }
public @NotNull ConfigureSource<? extends MemorySection, ?, ?> source() {
return source;
}
@Override
public char pathSeparator() {
return source().pathSeparator();
}
@Override @Override
public @NotNull MemorySection self() { public @NotNull MemorySection self() {
return this; return this;
} }
@Override @Override
protected @NotNull MemorySection createChild(@NotNull Map<?, ?> data) { public @NotNull MemorySection createSection(@NotNull String path, @NotNull Map<?, ?> data) {
return new MemorySection(source(), data, this); return new MemorySection(data, this, path);
} }
} }
@@ -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;
}
}
@@ -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());
}
}
}
+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.4</version> <version>4.0.7</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.4</version> <version>4.0.7</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<properties> <properties>
+2 -8
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.4</version> <version>4.0.7</version>
<modules> <modules>
<module>core</module> <module>core</module>
<module>features/section</module> <module>features/section</module>
@@ -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>
+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.4</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(); // 更新时间
} }
+1 -8
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.4</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 {