Skip to content

Commit

Permalink
feat(hocon): 完成对 HOCON 格式的支持 (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
flowerinsnowdh authored Jun 21, 2023
1 parent 3b2b1b2 commit 3a0a8e7
Show file tree
Hide file tree
Showing 11 changed files with 534 additions and 0 deletions.
66 changes: 66 additions & 0 deletions impl/hocon/pom.xml
Original file line number Diff line number Diff line change
@@ -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.6.0</version>
<relativePath>../../pom.xml</relativePath>
</parent>

<artifactId>easyconfiguration-hocon</artifactId>
<packaging>jar</packaging>

<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>

<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>

<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>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cc.carm.lib.configuration;

import cc.carm.lib.configuration.hocon.HOCONFileConfigProvider;

import java.io.File;
import java.io.IOException;

public class 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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package cc.carm.lib.configuration.hocon;

import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.List;
import java.util.Set;

public interface CommentedHOCON {
default @NotNull Set<String> getKeys() {
return getKeys(null, true);
}

String serializeValue(@NotNull String key, @NotNull Object value);

@Contract("null,_ -> !null;!null,_ -> _")
@Nullable Set<String> getKeys(@Nullable String sectionKey, boolean deep);

@Nullable Object getValue(@NotNull String key);

@Nullable String getInlineComment(@NotNull String key);

@Nullable
List<String> getHeaderComments(@Nullable String key);
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
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.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> implements CommentedHOCON {
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 {
this.configuration = new HOCONConfigWrapper(ConfigFactory.parseFile(this.file, ConfigParseOptions.defaults()
.setSyntax(ConfigSyntax.CONF)
.setAllowMissing(false)).root());
}

@Override
public @NotNull ConfigurationComments getComments() {
return this.comments;
}

@Override
public @NotNull ConfigInitializer<HOCONFileConfigProvider> getInitializer() {
return this.initializer;
}

@Override
public String serializeValue(@NotNull String key, @NotNull Object value) {
// 带有 key=value 的新空对象
return ConfigFactory.empty()
.withValue(key, ConfigValueFactory.fromAnyRef(value))
.root().render();
}

@Override
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, "");
}

@Override
public @Nullable Object getValue(@NotNull String key) {
return this.configuration.get(key);
}

@Override
public @Nullable List<String> getHeaderComments(@Nullable String key) {
return this.comments.getHeaderComment(key);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package cc.carm.lib.configuration.hocon.source;

import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import org.jetbrains.annotations.NotNull;

/**
* 暂时未实现,原因是如果要实现,就需要修改部分代码
* @see ConfigurationProvider#save()
* @see ConfigurationProvider#reload()
* 等一系列代码
*/
public abstract class StringConfigProvider<W extends ConfigurationWrapper<?>> extends ConfigurationProvider<W> {
protected final @NotNull String source;

protected StringConfigProvider(@NotNull String source) {
this.source = source;
}

public @NotNull String getSource() {
return this.source;
}
}
Loading

0 comments on commit 3a0a8e7

Please sign in to comment.