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

Compare commits

...

12 Commits

Author SHA1 Message Date
carm 07424284b7 fix(file): 修复 FileConfigProvider#saveResource 文件创建异常的问题。#39 2023-07-18 00:25:40 +08:00
carm 81e024e309 fix(file): 修复 FileConfigProvider#saveResource 文件创建异常的问题。#39 2023-07-18 00:20:31 +08:00
carm 763fc7c758 fix(file): 修复 FileConfigProvider#saveResource 文件创建异常的问题。#39 2023-07-18 00:20:20 +08:00
carm 56557221a4 feat(list): 添加快速获取副本列表的方法 2023-07-17 17:34:34 +08:00
冬花ice e4435bf883 修复路径截取错误导致无法拥有内部object类型的问题 (#38)
* 修复路径截取错误导致无法拥有内部object类型的问题

* 移除测试输出
2023-07-10 12:32:24 +08:00
carm eee4a278d9 feat(value): 支持对Enum对象的快速解析 2023-06-23 14:06:56 +08:00
冬花ice 3a0a8e79b9 feat(hocon): 完成对 HOCON 格式的支持 (#36) 2023-06-21 19:54:30 +08:00
dependabot[bot] 3b2b1b27cc chore(deps): Bump maven-shade-plugin from 3.4.1 to 3.5.0 (#35)
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.1...maven-shade-plugin-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-20 01:35:02 +08:00
dependabot[bot] d84ea1b7da chore(deps): Bump maven-surefire-plugin from 3.1.0 to 3.1.2 (#34)
Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.1.0 to 3.1.2.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.0...surefire-3.1.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-09 13:37:21 +08:00
dependabot[bot] a1f2cdca04 chore(deps): Bump yamlconfiguration from 1.3.2 to 1.3.3 (#33)
Bumps [yamlconfiguration](https://github.com/bspfsystems/YamlConfiguration) from 1.3.2 to 1.3.3.
- [Release notes](https://github.com/bspfsystems/YamlConfiguration/releases)
- [Commits](https://github.com/bspfsystems/YamlConfiguration/compare/v1.3.2...v1.3.3)

---
updated-dependencies:
- dependency-name: org.bspfsystems:yamlconfiguration
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-09 13:37:12 +08:00
dependabot[bot] c52183aadd chore(deps): Bump maven-release-plugin from 3.0.0 to 3.0.1 (#32)
Bumps [maven-release-plugin](https://github.com/apache/maven-release) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/apache/maven-release/releases)
- [Commits](https://github.com/apache/maven-release/compare/maven-release-3.0.0...maven-release-3.0.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-release-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-06 03:44:21 +08:00
dependabot[bot] d71aabad2d chore(deps): Bump maven-source-plugin from 3.2.1 to 3.3.0 (#31)
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.2.1 to 3.3.0.
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.1...maven-source-plugin-3.3.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-source-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-23 02:51:34 +08:00
24 changed files with 592 additions and 49 deletions
+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>3.6.0</version> <version>3.7.1</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>
@@ -46,7 +46,10 @@ public class ConfigValueBuilder<V> {
return from( return from(
Object.class, ConfigDataFunction.identity(), Object.class, ConfigDataFunction.identity(),
ConfigValueParser.castObject(valueClass), ConfigValueParser.castObject(valueClass),
ConfigDataFunction.toObject(), ConfigDataFunction.toObject() s -> {
if (s instanceof Enum<?>) return ((Enum<?>) s).name();
else return s;
}, ConfigDataFunction.toObject()
); );
} }
@@ -13,34 +13,34 @@ public interface ConfigDataFunction<T, R> {
default <V> @NotNull ConfigDataFunction<T, V> andThen(@NotNull ConfigDataFunction<? super R, V> after) { default <V> @NotNull ConfigDataFunction<T, V> andThen(@NotNull ConfigDataFunction<? super R, V> after) {
Objects.requireNonNull(after); Objects.requireNonNull(after);
return ((data) -> after.parse(parse(data))); return data -> after.parse(parse(data));
} }
@Contract(pure = true) @Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, T> identity() { static <T> @NotNull ConfigDataFunction<T, T> identity() {
return (input) -> input; return input -> input;
} }
@Contract(pure = true) @Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, T> identity(Class<T> type) { static <T> @NotNull ConfigDataFunction<T, T> identity(Class<T> type) {
return (input) -> input; return input -> input;
} }
@Contract(pure = true) @Contract(pure = true)
static <T, V> @NotNull ConfigDataFunction<T, V> required() { static <T, V> @NotNull ConfigDataFunction<T, V> required() {
return (input) -> { return input -> {
throw new IllegalArgumentException("Please specify the value parser."); throw new IllegalArgumentException("Please specify the value parser.");
}; };
} }
@Contract(pure = true) @Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, Object> toObject() { static <T> @NotNull ConfigDataFunction<T, Object> toObject() {
return (input) -> input; return input -> input;
} }
@Contract(pure = true) @Contract(pure = true)
static <V> @NotNull ConfigDataFunction<Object, V> castObject(Class<V> valueClass) { static <V> @NotNull ConfigDataFunction<Object, V> castObject(Class<V> valueClass) {
return (input) -> { return input -> {
if (valueClass.isInstance(input)) return valueClass.cast(input); if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName()); else throw new IllegalArgumentException("Cannot cast value to " + valueClass.getName());
}; };
@@ -48,7 +48,7 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true) @Contract(pure = true)
static <V> @NotNull ConfigDataFunction<String, V> castFromString(Class<V> valueClass) { static <V> @NotNull ConfigDataFunction<String, V> castFromString(Class<V> valueClass) {
return (input) -> { return input -> {
if (valueClass.isInstance(input)) return valueClass.cast(input); if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName()); else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
}; };
@@ -56,15 +56,16 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true) @Contract(pure = true)
static <T> @NotNull ConfigDataFunction<T, String> castToString() { static <T> @NotNull ConfigDataFunction<T, String> castToString() {
return (input) -> { return input -> {
if (input instanceof String) return (String) input; if (input instanceof String) return (String) input;
else if (input instanceof Enum<?>) return ((Enum<?>) input).name();
else return input.toString(); else return input.toString();
}; };
} }
@Contract(pure = true) @Contract(pure = true)
static <V> @NotNull ConfigDataFunction<String, V> parseString(Class<V> valueClass) { static <V> @NotNull ConfigDataFunction<String, V> parseString(Class<V> valueClass) {
return (input) -> { return input -> {
if (valueClass.isInstance(input)) return valueClass.cast(input); if (valueClass.isInstance(input)) return valueClass.cast(input);
else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName()); else throw new IllegalArgumentException("Cannot cast string to " + valueClass.getName());
}; };
@@ -72,7 +73,7 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true) @Contract(pure = true)
static @NotNull ConfigDataFunction<Object, Integer> intValue() { static @NotNull ConfigDataFunction<Object, Integer> intValue() {
return (input) -> { return input -> {
if (input instanceof Integer) { if (input instanceof Integer) {
return (Integer) input; return (Integer) input;
} else if (input instanceof Number) { } else if (input instanceof Number) {
@@ -83,7 +84,7 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true) @Contract(pure = true)
static @NotNull ConfigDataFunction<Object, Short> shortValue() { static @NotNull ConfigDataFunction<Object, Short> shortValue() {
return (input) -> { return input -> {
if (input instanceof Short) { if (input instanceof Short) {
return (Short) input; return (Short) input;
} else if (input instanceof Number) { } else if (input instanceof Number) {
@@ -94,7 +95,7 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true) @Contract(pure = true)
static @NotNull ConfigDataFunction<Object, Double> doubleValue() { static @NotNull ConfigDataFunction<Object, Double> doubleValue() {
return (input) -> { return input -> {
if (input instanceof Double) { if (input instanceof Double) {
return (Double) input; return (Double) input;
} else if (input instanceof Number) { } else if (input instanceof Number) {
@@ -105,7 +106,7 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true) @Contract(pure = true)
static @NotNull ConfigDataFunction<Object, Byte> byteValue() { static @NotNull ConfigDataFunction<Object, Byte> byteValue() {
return (input) -> { return input -> {
if (input instanceof Byte) { if (input instanceof Byte) {
return (Byte) input; return (Byte) input;
} else if (input instanceof Number) { } else if (input instanceof Number) {
@@ -116,7 +117,7 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true) @Contract(pure = true)
static @NotNull ConfigDataFunction<Object, Float> floatValue() { static @NotNull ConfigDataFunction<Object, Float> floatValue() {
return (input) -> { return input -> {
if (input instanceof Float) { if (input instanceof Float) {
return (Float) input; return (Float) input;
} else if (input instanceof Number) { } else if (input instanceof Number) {
@@ -127,7 +128,7 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true) @Contract(pure = true)
static @NotNull ConfigDataFunction<Object, Long> longValue() { static @NotNull ConfigDataFunction<Object, Long> longValue() {
return (input) -> { return input -> {
if (input instanceof Long) { if (input instanceof Long) {
return (Long) input; return (Long) input;
} else if (input instanceof Number) { } else if (input instanceof Number) {
@@ -138,14 +139,14 @@ public interface ConfigDataFunction<T, R> {
@Contract(pure = true) @Contract(pure = true)
static @NotNull ConfigDataFunction<Object, Boolean> booleanValue() { static @NotNull ConfigDataFunction<Object, Boolean> booleanValue() {
return (input) -> { return input -> {
if (input instanceof Boolean) { if (input instanceof Boolean) {
return (Boolean) input; return (Boolean) input;
} else if (input instanceof String) { } else if (input instanceof String) {
String s = (String) input; String s = (String) input;
return Boolean.parseBoolean(s) || "yes".equalsIgnoreCase(s); return Boolean.parseBoolean(s) || "yes".equalsIgnoreCase(s);
} else if (input instanceof Integer) { } else if (input instanceof Integer) {
return ((Integer) input) == 1; return (Integer) input == 1;
} else throw new IllegalArgumentException("Cannot cast value to " + Boolean.class.getName()); } else throw new IllegalArgumentException("Cannot cast value to " + Boolean.class.getName());
}; };
} }
@@ -67,6 +67,9 @@ public interface ConfigValueParser<T, R> {
} }
} else if (Boolean.class.isAssignableFrom(valueClass)) { } else if (Boolean.class.isAssignableFrom(valueClass)) {
input = booleanValue().parse(input, (Boolean) defaultValue); input = booleanValue().parse(input, (Boolean) defaultValue);
} else if (Enum.class.isAssignableFrom(valueClass) && input instanceof String) {
String enumName = (String) input;
input = valueClass.getDeclaredMethod("valueOf", String.class).invoke(null, enumName);
} }
if (valueClass.isInstance(input)) return valueClass.cast(input); if (valueClass.isInstance(input)) return valueClass.cast(input);
@@ -125,6 +128,21 @@ public interface ConfigValueParser<T, R> {
return (input, defaultValue) -> ConfigDataFunction.booleanValue().parse(input); return (input, defaultValue) -> ConfigDataFunction.booleanValue().parse(input);
} }
@Contract(pure = true)
static @NotNull <E extends Enum<E>> ConfigValueParser<Object, E> enumValue(Class<E> enumClass) {
return (input, defaultValue) -> {
if (input instanceof Enum) {
return enumClass.cast(input);
} else if (input instanceof String) {
return Enum.valueOf(enumClass, (String) input);
} else if (input instanceof Number) {
return enumClass.getEnumConstants()[((Number) input).intValue()];
} else {
throw new IllegalArgumentException("Cannot cast value to " + enumClass.getName());
}
};
}
} }
@@ -5,9 +5,13 @@ import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.*; import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.nio.file.Files;
import java.util.Objects; import java.util.Objects;
public abstract class FileConfigProvider<W extends ConfigurationWrapper<?>> extends ConfigurationProvider<W> { public abstract class FileConfigProvider<W extends ConfigurationWrapper<?>> extends ConfigurationProvider<W> {
@@ -37,39 +41,36 @@ public abstract class FileConfigProvider<W extends ConfigurationWrapper<?>> exte
if (sourcePath != null) { if (sourcePath != null) {
try { try {
saveResource(sourcePath, true); saveResource(sourcePath, true);
} catch (Exception ignored) { } catch (IllegalArgumentException ignored) {
} }
} }
} }
public void saveResource(@NotNull String resourcePath, boolean replace) public void saveResource(@NotNull String resourcePath, boolean replace)
throws NullPointerException, IOException, IllegalArgumentException { throws IOException, IllegalArgumentException {
Objects.requireNonNull(resourcePath, "ResourcePath cannot be null"); Objects.requireNonNull(resourcePath, "ResourcePath cannot be null");
if (resourcePath.equals("")) throw new IllegalArgumentException("ResourcePath cannot be empty"); if (resourcePath.equals("")) throw new IllegalArgumentException("ResourcePath cannot be empty");
resourcePath = resourcePath.replace('\\', '/'); resourcePath = resourcePath.replace('\\', '/');
InputStream in = getResource(resourcePath);
if (in == null) throw new IllegalArgumentException("The resource '" + resourcePath + "' not exists");
URL url = this.getClass().getClassLoader().getResource(resourcePath);
if (url == null) throw new IllegalArgumentException("The resource '" + resourcePath + "' not exists");
int lastIndex = resourcePath.lastIndexOf('/'); int lastIndex = resourcePath.lastIndexOf('/');
File outDir = new File(file, resourcePath.substring(0, Math.max(lastIndex, 0))); File outDir = new File(file.getParentFile(), resourcePath.substring(0, Math.max(lastIndex, 0)));
if (!outDir.exists() && !outDir.mkdirs()) throw new IOException("Failed to create directory " + outDir); if (!outDir.exists() && !outDir.mkdirs()) throw new IOException("Failed to create directory " + outDir);
if (!file.exists() || replace) { if (!file.exists() || replace) {
try { try (OutputStream out = Files.newOutputStream(file.toPath())) {
URLConnection connection = url.openConnection();
OutputStream out = new FileOutputStream(file); connection.setUseCaches(false);
byte[] buf = new byte[1024]; try (InputStream in = connection.getInputStream()) {
int len; byte[] buf = new byte[1024];
while ((len = in.read(buf)) > 0) { int len;
out.write(buf, 0, len); while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
} }
out.close();
in.close();
} catch (IOException ex) {
ex.printStackTrace();
} }
} }
} }
@@ -65,6 +65,10 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> implements Lis
return get().get(index); return get().get(index);
} }
public @NotNull List<V> copy() {
return new ArrayList<>(get());
}
public <T> @NotNull T handle(Function<List<V>, T> function) { public <T> @NotNull T handle(Function<List<V>, T> function) {
List<V> list = get(); List<V> list = get();
T result = function.apply(list); T result = function.apply(list);
+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>3.6.0</version> <version>3.7.1</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>
@@ -12,6 +12,7 @@ import cc.carm.lib.configuration.core.value.type.ConfiguredSection;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue; import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import cc.carm.lib.configuration.demo.tests.model.TestModel; import cc.carm.lib.configuration.demo.tests.model.TestModel;
import java.time.temporal.ChronoUnit;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@@ -25,6 +26,8 @@ public class DemoConfiguration extends ConfigurationRoot {
@ConfigPath(root = true) @ConfigPath(root = true)
public static final ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(Long.class, 1000000L); public static final ConfigValue<Long> TEST_NUMBER = ConfiguredValue.of(Long.class, 1000000L);
public static final ConfigValue<ChronoUnit> TEST_ENUM = ConfiguredValue.of(ChronoUnit.class, ChronoUnit.DAYS);
// 支持通过 Class<?> 变量标注子配置,一并注册。 // 支持通过 Class<?> 变量标注子配置,一并注册。
// 注意: 若对应类也有注解,则优先使用类的注解。 // 注意: 若对应类也有注解,则优先使用类的注解。
@ConfigPath("other-class-config") //支持通过注解修改子配置的主路径,若不修改则以变量名自动生成。 @ConfigPath("other-class-config") //支持通过注解修改子配置的主路径,若不修改则以变量名自动生成。
+66
View File
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cc.carm.lib</groupId>
<artifactId>easyconfiguration-parent</artifactId>
<version>3.7.1</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<properties>
<maven.compiler.source>${project.jdk.version}</maven.compiler.source>
<maven.compiler.target>${project.jdk.version}</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
</properties>
<artifactId>easyconfiguration-hocon</artifactId>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-core</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>${project.parent.groupId}</groupId>
<artifactId>easyconfiguration-demo</artifactId>
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.typesafe</groupId>
<artifactId>config</artifactId>
<version>1.4.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,36 @@
package cc.carm.lib.configuration;
import cc.carm.lib.configuration.hocon.HOCONFileConfigProvider;
import java.io.File;
import java.io.IOException;
public class EasyConfiguration {
private EasyConfiguration() {
}
public static HOCONFileConfigProvider from(File file, String source) {
HOCONFileConfigProvider provider = new HOCONFileConfigProvider(file);
try {
provider.initializeFile(source);
provider.initializeConfig();
} catch (IOException e) {
e.printStackTrace();
}
return provider;
}
public static HOCONFileConfigProvider from(File file) {
return from(file, file.getName());
}
public static HOCONFileConfigProvider from(String fileName) {
return from(fileName, fileName);
}
public static HOCONFileConfigProvider from(String fileName, String source) {
return from(new File(fileName), source);
}
}
@@ -0,0 +1,117 @@
package cc.carm.lib.configuration.hocon;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.hocon.util.HOCONUtils;
import com.typesafe.config.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class HOCONConfigWrapper implements ConfigurationWrapper<Map<String, Object>> {
private static final char SEPARATOR = '.';
protected final Map<String, Object> data;
public HOCONConfigWrapper(ConfigObject config) {
this.data = new LinkedHashMap<>();
config.forEach((key, value) -> {
Config cfg = config.toConfig();
ConfigValue cv = cfg.getValue(key);
if (cv.valueType() == ConfigValueType.OBJECT) {
HOCONConfigWrapper.this.data.put(key, new HOCONConfigWrapper((ConfigObject) cv));
} else {
HOCONConfigWrapper.this.data.put(key, value.unwrapped());
}
});
}
@Override
public @NotNull Map<String, Object> getSource() {
return this.data;
}
@Override
public @NotNull Set<String> getKeys(boolean deep) {
return this.getValues(deep).keySet();
}
@Override
public @NotNull Map<String, Object> getValues(boolean deep) {
return HOCONUtils.getKeysFromObject(this, deep, "").stream().collect(
LinkedHashMap::new,
(map, key) -> map.put(key, get(key)),
LinkedHashMap::putAll
);
}
@Override
public void set(@NotNull String path, @Nullable Object value) {
if (value instanceof Map) {
//noinspection unchecked
value = new HOCONConfigWrapper(ConfigFactory.parseMap((Map<String, ?>) value).root());
}
HOCONConfigWrapper section = HOCONUtils.getObjectOn(this, path, SEPARATOR);
String simplePath = HOCONUtils.getSimplePath(path, SEPARATOR);
if (value == null) {
section.data.remove(simplePath);
} else {
section.setDirect(simplePath, value);
}
}
/**
* 只能设置当前路径下的内容
* 避免环回
*
* @param path 路径
*/
public void setDirect(@NotNull String path, @Nullable Object value) {
this.data.put(path, value);
}
@Override
public boolean contains(@NotNull String path) {
return this.get(path) != null;
}
@Override
public @Nullable Object get(@NotNull String path) {
HOCONConfigWrapper section = HOCONUtils.getObjectOn(this, path, SEPARATOR);
return section.getDirect(HOCONUtils.getSimplePath(path, SEPARATOR));
}
/**
* 只能获取当前路径下的内容
* 避免环回
*
* @param path 路径
*/
public Object getDirect(@NotNull String path) {
return this.data.get(path);
}
@Override
public boolean isList(@NotNull String path) {
return this.get(path) instanceof List<?>;
}
@Override
public @Nullable List<?> getList(@NotNull String path) {
Object val = this.get(path);
return (val instanceof List<?>) ? (List<?>) val : null;
}
@Override
public boolean isConfigurationSection(@NotNull String path) {
return this.get(path) instanceof HOCONConfigWrapper;
}
@Override
public @Nullable ConfigurationWrapper<Map<String, Object>> getConfigurationSection(@NotNull String path) {
Object val = get(path);
return (val instanceof HOCONConfigWrapper) ? (HOCONConfigWrapper) val : null;
}
}
@@ -0,0 +1,106 @@
package cc.carm.lib.configuration.hocon;
import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.core.source.ConfigurationComments;
import cc.carm.lib.configuration.core.source.impl.FileConfigProvider;
import cc.carm.lib.configuration.hocon.exception.HOCONGetValueException;
import cc.carm.lib.configuration.hocon.util.HOCONUtils;
import com.typesafe.config.*;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import java.util.Set;
public class HOCONFileConfigProvider extends FileConfigProvider<HOCONConfigWrapper> {
protected final @NotNull ConfigurationComments comments = new ConfigurationComments();
protected HOCONConfigWrapper configuration;
protected ConfigInitializer<HOCONFileConfigProvider> initializer;
public HOCONFileConfigProvider(@NotNull File file) {
super(file);
this.initializer = new ConfigInitializer<>(this);
}
public void initializeConfig() {
try {
this.configuration = new HOCONConfigWrapper(ConfigFactory.parseFile(this.file, ConfigParseOptions.defaults()
.setSyntax(ConfigSyntax.CONF)
.setAllowMissing(false)).root());
} catch (ConfigException e) {
e.printStackTrace();
}
}
@Override
public @NotNull HOCONConfigWrapper getConfiguration() {
return this.configuration;
}
@Override
public void save() throws IOException {
Files.write(this.file.toPath(), HOCONUtils.renderWithComment(configuration, comments::getHeaderComment).getBytes(StandardCharsets.UTF_8));
}
@Override
protected void onReload() throws ConfigException {
ConfigObject conf = ConfigFactory.parseFile(this.file, ConfigParseOptions.defaults()
.setSyntax(ConfigSyntax.CONF)
.setAllowMissing(false)).root();
this.configuration = new HOCONConfigWrapper(conf);
}
@Override
public @NotNull ConfigurationComments getComments() {
return this.comments;
}
@Override
public @NotNull ConfigInitializer<HOCONFileConfigProvider> getInitializer() {
return this.initializer;
}
public String serializeValue(@NotNull String key, @NotNull Object value) {
// 带有 key=value 的新空对象
return ConfigFactory.empty()
.withValue(key, ConfigValueFactory.fromAnyRef(value))
.root().render();
}
public @NotNull Set<String> getKeys() {
return getKeys(null, true);
}
@Contract("null,_->!null")
public @Nullable Set<String> getKeys(@Nullable String sectionKey, boolean deep) {
if (sectionKey == null) { // 当前路径
return HOCONUtils.getKeysFromObject(this.configuration, deep, "");
}
HOCONConfigWrapper section;
try {
// 获取目标字段所在路径
section = (HOCONConfigWrapper) this.configuration.get(sectionKey);
} catch (ClassCastException e) {
// 值和类型不匹配
throw new HOCONGetValueException(e);
}
if (section == null) {
return null;
}
return HOCONUtils.getKeysFromObject(section, deep, "");
}
public @Nullable Object getValue(@NotNull String key) {
return this.configuration.get(key);
}
public @Nullable List<String> getHeaderComments(@Nullable String key) {
return this.comments.getHeaderComment(key);
}
}
@@ -0,0 +1,19 @@
package cc.carm.lib.configuration.hocon.exception;
public class HOCONGetValueException extends RuntimeException {
public HOCONGetValueException() {
super();
}
public HOCONGetValueException(String message) {
super(message);
}
public HOCONGetValueException(String message, Throwable cause) {
super(message, cause);
}
public HOCONGetValueException(Throwable cause) {
super(cause);
}
}
@@ -0,0 +1,110 @@
package cc.carm.lib.configuration.hocon.util;
import cc.carm.lib.configuration.hocon.HOCONConfigWrapper;
import cc.carm.lib.configuration.hocon.exception.HOCONGetValueException;
import com.typesafe.config.*;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
public class HOCONUtils {
private HOCONUtils() {
}
public static String getSimplePath(String path, char separator) {
int index = path.lastIndexOf(separator);
return (index == -1) ? path : path.substring(index + 1);
}
public static HOCONConfigWrapper getObjectOn(@NotNull HOCONConfigWrapper parent, @NotNull String path, char separator) {
String currentPath = path;
HOCONConfigWrapper currentObject = parent;
int index;
while ((index = currentPath.indexOf(separator)) != -1) {
HOCONConfigWrapper previousObject = currentObject;
String pathName = currentPath.substring(0, index);
try {
currentObject = (HOCONConfigWrapper) previousObject.getDirect(pathName);
} catch (ClassCastException e) {
throw new HOCONGetValueException(e);
}
if (currentObject == null) {
currentObject = new HOCONConfigWrapper(ConfigFactory.empty().root());
previousObject.setDirect(pathName, currentObject);
}
currentPath = currentPath.substring(index + 1);
}
return currentObject;
}
/**
* 在 Object 中获取所有键
* 思路:在第一次执行时 prefix 应该是 ""
* 后续找到了更深层的键,将会变为 "deep."
* 下一次键名就是 "deep.key"
*
* @param parent Object
* @param deep 是否更深层获取
* @param prefix 当前 Object 键名前缀
* @return Object 中的所有键
*/
public static Set<String> getKeysFromObject(HOCONConfigWrapper parent, boolean deep, String prefix) {
return parent.getSource().entrySet().stream().collect(
LinkedHashSet::new,
(set, entry) -> {
Object value = entry.getValue();
if (value instanceof HOCONConfigWrapper && deep) {
set.addAll(HOCONUtils.getKeysFromObject((HOCONConfigWrapper) value, true, prefix + entry.getKey() + "."));
} else {
set.add(prefix + entry.getKey());
}
},
LinkedHashSet::addAll
);
}
/**
* 将 Object 保存为字符串
* 并使用注释器打上注释
*
* @param object Object
* @param commenter 注释器
* @return 保存的字符串
*/
public static @NotNull String renderWithComment(@NotNull HOCONConfigWrapper object, @NotNull Function<String, List<String>> commenter) {
return HOCONUtils.makeConfigWithComment(object, "", commenter).root().render(
ConfigRenderOptions.defaults()
.setJson(false)
.setOriginComments(false)
);
}
public static @NotNull Config makeConfigWithComment(@NotNull HOCONConfigWrapper object, @NotNull String prefix, @NotNull Function<String, List<String>> commenter) {
Config config = ConfigFactory.empty();
for (Map.Entry<String, Object> entry : object.getSource().entrySet()) {
String key = entry.getKey();
String fullKey = prefix + key;
Object value = entry.getValue();
ConfigValue result;
if (value instanceof Iterable) {
result = ConfigValueFactory.fromIterable((Iterable<?>) value);
} else if (value instanceof HOCONConfigWrapper) {
result = makeConfigWithComment((HOCONConfigWrapper) value, fullKey + ".", commenter).root();
} else {
result = ConfigValueFactory.fromAnyRef(value);
}
result = result.withOrigin(
ConfigOriginFactory.newSimple()
.withComments(commenter.apply(fullKey))
);
config = config.withValue(key, result);
}
return config;
}
}
@@ -0,0 +1,24 @@
package online.flowerinsnow.test.easyconfiguration;
import cc.carm.lib.configuration.EasyConfiguration;
//import cc.carm.lib.configuration.demo.DatabaseConfiguration;
//import cc.carm.lib.configuration.demo.tests.conf.DemoConfiguration;
import cc.carm.lib.configuration.hocon.HOCONFileConfigProvider;
import online.flowerinsnow.test.easyconfiguration.config.Config;
import org.junit.Test;
import java.io.File;
public class HOCONTest {
@Test
public void onTest() {
HOCONFileConfigProvider provider = EasyConfiguration.from(new File("target/hocon.conf"));
provider.initialize(Config.class);
// provider.initialize(DatabaseConfiguration.class);
try {
provider.reload();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@@ -0,0 +1,25 @@
package online.flowerinsnow.test.easyconfiguration.config;
import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.value.type.ConfiguredList;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
public class Config extends ConfigurationRoot {
@HeaderComment("测试字段 int")
public static final ConfiguredValue<Integer> TEST_INT = ConfiguredValue.of(Integer.class, 15);
@HeaderComment("测试字段 List<String>")
public static final ConfiguredList<String> TEST_LIST_STRING = ConfiguredList.of(String.class, "li", "li", "li1");
@HeaderComment("测试对象")
public static class TestObject extends ConfigurationRoot {
@HeaderComment("测试字段 Boolean")
public static final ConfiguredValue<Boolean> TEST_BOOLEAN = ConfiguredValue.of(Boolean.class, true);
@HeaderComment("inner")
public static class InnerObject extends ConfigurationRoot {
@HeaderComment("测试字段")
public static final ConfiguredValue<Boolean> TEST_BOOLEAN_1 = ConfiguredValue.of(Boolean.class, true);
}
}
}
+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>3.6.0</version> <version>3.7.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -7,6 +7,9 @@ import java.io.IOException;
public class EasyConfiguration { public class EasyConfiguration {
private EasyConfiguration() {
}
public static JSONConfigProvider from(File file, String source) { public static JSONConfigProvider from(File file, String source) {
JSONConfigProvider provider = new JSONConfigProvider(file); JSONConfigProvider provider = new JSONConfigProvider(file);
try { try {
+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>3.6.0</version> <version>3.7.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -1,6 +1,8 @@
package cc.carm.lib.configuration; package cc.carm.lib.configuration;
public class EasyConfiguration { public class EasyConfiguration {
private EasyConfiguration() {
}
} }
+2 -2
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>3.6.0</version> <version>3.7.1</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -44,7 +44,7 @@
<dependency> <dependency>
<groupId>org.bspfsystems</groupId> <groupId>org.bspfsystems</groupId>
<artifactId>yamlconfiguration</artifactId> <artifactId>yamlconfiguration</artifactId>
<version>1.3.2</version> <version>1.3.3</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@@ -6,6 +6,9 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
public class EasyConfiguration { public class EasyConfiguration {
private EasyConfiguration() {
}
public static YAMLConfigProvider from(File file, String source) { public static YAMLConfigProvider from(File file, String source) {
YAMLConfigProvider provider = new YAMLConfigProvider(file); YAMLConfigProvider provider = new YAMLConfigProvider(file);
+2 -1
View File
@@ -1 +1,2 @@
version: 1.0 version: 1.0
test-save: false
+6 -5
View File
@@ -15,13 +15,14 @@
<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>3.6.0</version> <version>3.7.1</version>
<modules> <modules>
<module>core</module> <module>core</module>
<module>demo</module> <module>demo</module>
<module>impl/yaml</module> <module>impl/yaml</module>
<module>impl/json</module> <module>impl/json</module>
<module>impl/sql</module> <module>impl/sql</module>
<module>impl/hocon</module>
</modules> </modules>
<name>EasyConfiguration</name> <name>EasyConfiguration</name>
@@ -122,7 +123,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.1.0</version> <version>3.1.2</version>
<configuration> <configuration>
<useSystemClassLoader>false</useSystemClassLoader> <useSystemClassLoader>false</useSystemClassLoader>
</configuration> </configuration>
@@ -150,7 +151,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId> <artifactId>maven-release-plugin</artifactId>
<version>3.0.0</version> <version>3.0.1</version>
<configuration> <configuration>
<autoVersionSubmodules>true</autoVersionSubmodules> <autoVersionSubmodules>true</autoVersionSubmodules>
<useReleaseProfile>false</useReleaseProfile> <useReleaseProfile>false</useReleaseProfile>
@@ -211,7 +212,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version> <version>3.3.0</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@@ -225,7 +226,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version> <version>3.5.0</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>