diff --git a/core/pom.xml b/core/pom.xml index 13937d7..36380d8 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -5,7 +5,7 @@ easyconfiguration-parent cc.carm.lib - 2.2.0 + 2.3.0 4.0.0 diff --git a/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java b/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java index 6fee3e0..f9c9ba7 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/ConfigInitializer.java @@ -2,6 +2,7 @@ package cc.carm.lib.configuration.core; import cc.carm.lib.configuration.core.annotation.ConfigComment; import cc.carm.lib.configuration.core.annotation.ConfigPath; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.value.ConfigValue; import org.jetbrains.annotations.NotNull; @@ -62,7 +63,7 @@ public class ConfigInitializer> { @Nullable ConfigPath fieldPath, @Nullable ConfigComment filedComments, boolean saveDefaults, boolean loadSubClasses) { String path = getClassPath(clazz, parentPath, fieldName, fieldPath); - if (path != null) setComments(path, getClassComments(clazz, filedComments)); + this.provider.setComment(path, getClassComments(clazz, filedComments)); for (Field field : clazz.getDeclaredFields()) { initializeField(clazz, field, path, saveDefaults, loadSubClasses); } @@ -82,21 +83,21 @@ public class ConfigInitializer> { protected void initializeValue(@NotNull ConfigValue value, @NotNull String path, - @NotNull String[] comments, boolean saveDefaults) { + @Nullable ConfigCommentInfo comments, boolean saveDefaults) { value.initialize(provider, saveDefaults, path, comments); } private void initializeField(@NotNull Class source, @NotNull Field field, @Nullable String parent, boolean saveDefaults, boolean loadSubClasses) { - try { field.setAccessible(true); Object object = field.get(source); if (object instanceof ConfigValue) { - String path = getFieldPath(field, parent); - String[] comments = readComments(field.getAnnotation(ConfigComment.class)); - initializeValue((ConfigValue) object, path, comments, saveDefaults); - setComments(path, comments); + initializeValue( + (ConfigValue) object, getFieldPath(field, parent), + ConfigCommentInfo.fromAnnotation(field.getAnnotation(ConfigComment.class)), + saveDefaults + ); } else if (object instanceof Class) { initializeClass( (Class) object, parent, field.getName(), @@ -109,26 +110,15 @@ public class ConfigInitializer> { } } - protected void setComments(@NotNull String path, @Nullable ConfigComment filedComments) { - setComments(path, readComments(filedComments)); + protected void setComments(@Nullable String path, @Nullable ConfigCommentInfo comments) { + if (comments != null) this.provider.setComment(path, comments); } - protected void setComments(@NotNull String path, @NotNull String[] comments) { - if (comments.length <= 0) return; - this.provider.setComments(path, comments); - } - - protected static @NotNull String[] readComments(@Nullable ConfigComment filedComments) { - if (filedComments == null) return new String[0]; - if (String.join("", filedComments.value()).length() <= 0) return new String[0]; - return filedComments.value(); - } - - protected static @NotNull String[] getClassComments(@NotNull Class clazz, - @Nullable ConfigComment fieldAnnotation) { - String[] clazzComments = readComments(clazz.getAnnotation(ConfigComment.class)); - if (clazzComments.length > 0) return clazzComments; - else return readComments(fieldAnnotation); + protected static @Nullable ConfigCommentInfo getClassComments(@NotNull Class clazz, + @Nullable ConfigComment fieldAnnotation) { + ConfigCommentInfo classComments = ConfigCommentInfo.fromAnnotation(clazz.getAnnotation(ConfigComment.class)); + if (classComments != null) return classComments; + return ConfigCommentInfo.fromAnnotation(fieldAnnotation); } protected static @Nullable String getClassPath(@NotNull Class clazz, diff --git a/core/src/main/java/cc/carm/lib/configuration/core/annotation/ConfigComment.java b/core/src/main/java/cc/carm/lib/configuration/core/annotation/ConfigComment.java index b24e874..5874024 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/annotation/ConfigComment.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/annotation/ConfigComment.java @@ -14,4 +14,32 @@ public @interface ConfigComment { @NotNull String[] value() default ""; + /** + * 首行换行,即会在注释开始前进行一次换行,与上方配置分离,优化观感。 + * 如: + *
+     * some-key: "SomeValue"
+     *
+     * # 注释第一行
+     * # 注释第二行
+     * startWrap: true
+     * 
+ * + * @return 是否在结尾添加换行符 + */ + boolean startWrap() default true; + + /** + * 末尾换行,即会在注释结束后进行一次换行,如: + *
+     * # 注释第一行
+     * # 注释第二行
+     *
+     * endWrap: true
+     * 
+ *

该功能可用于编写配置文件的顶部注释。 + * + * @return 是否在结尾添加换行符 + */ + boolean endWrap() default false; } diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java index 2b6b275..0be89fd 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/AbstractConfigBuilder.java @@ -1,5 +1,6 @@ package cc.carm.lib.configuration.core.builder; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.value.ConfigValue; import org.jetbrains.annotations.NotNull; @@ -13,6 +14,9 @@ public abstract class AbstractConfigBuilder providerClass) { @@ -38,10 +42,34 @@ public abstract class AbstractConfigBuilder> extends AbstractConfigBuilder> { - protected @Nullable ConfigurationProvider provider; - protected @Nullable String path; - - protected @NotNull String[] comments = new String[0]; - protected @Nullable T defaultValue; - public CommonConfigBuilder() { super(ConfigurationProvider.class); } - protected abstract @NotNull B getThis(); - - public abstract @NotNull ConfigValue build(); - - public @NotNull B from(@Nullable ConfigurationProvider provider) { - this.provider = provider; - return getThis(); - } - - public @NotNull B path(@Nullable String path) { - this.path = path; - return getThis(); - } - - public @NotNull B comments(@NotNull String... comments) { - this.comments = comments; - return getThis(); - } - - public @NotNull B defaults(@Nullable T defaultValue) { - this.defaultValue = defaultValue; - return getThis(); - } - - } diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java index 3ede77f..3a09cda 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/list/SourceListBuilder.java @@ -65,7 +65,7 @@ public class SourceListBuilder extends CommonConfigBuilder, Source @Override public @NotNull ConfiguredList build() { return new ConfiguredList<>( - this.provider, this.path, this.comments, + this.provider, this.path, this.buildComments(), this.valueClass, this.defaultValue, this.sourceParser.andThen(this.valueParser), this.valueSerializer.andThen(sourceSerializer) diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java index 1667bd0..3345c6d 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/map/SourceMapBuilder.java @@ -89,7 +89,7 @@ public class SourceMapBuilder, S, K, V> extends CommonConfig @Override public @NotNull ConfiguredMap build() { return new ConfiguredMap<>( - this.provider, this.path, this.comments, + this.provider, this.path,this.buildComments(), this.defaultValue, this.supplier, this.keyClass, this.keyParser, this.valueClass, this.sourceParser.andThen(this.valueParser), diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java index d9bdbe2..4366f73 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SectionValueBuilder.java @@ -45,7 +45,7 @@ public class SectionValueBuilder @Override public @NotNull ConfiguredSection build() { return new ConfiguredSection<>( - this.provider, this.path, this.comments, + this.provider, this.path,this.buildComments(), this.valueClass, this.defaultValue, this.parser, this.serializer ); diff --git a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java b/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java index deb77fb..f52f0ee 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/builder/value/SourceValueBuilder.java @@ -3,6 +3,7 @@ package cc.carm.lib.configuration.core.builder.value; import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigValueParser; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.value.type.ConfiguredValue; import org.jetbrains.annotations.NotNull; @@ -57,7 +58,7 @@ public class SourceValueBuilder extends CommonConfigBuilder build() { return new ConfiguredValue<>( - this.provider, this.path, this.comments, + this.provider, this.path, this.buildComments(), this.valueClass, this.defaultValue, this.valueParser.compose(this.sourceParser), this.valueSerializer.andThen(sourceSerializer) diff --git a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigCommentInfo.java b/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigCommentInfo.java new file mode 100644 index 0000000..47818a3 --- /dev/null +++ b/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigCommentInfo.java @@ -0,0 +1,80 @@ +package cc.carm.lib.configuration.core.source; + +import cc.carm.lib.configuration.core.annotation.ConfigComment; +import cc.carm.lib.configuration.core.value.ConfigValue; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Objects; +import java.util.Optional; + +public class ConfigCommentInfo { + + public static @NotNull ConfigCommentInfo DEFAULT_INFO = of(new String[0], true, false); + + protected final @NotNull String[] comments; + protected final boolean startWrap; + protected final boolean endWrap; + + public ConfigCommentInfo(@NotNull String[] comments, boolean startWrap, boolean endWrap) { + this.comments = comments; + this.startWrap = startWrap; + this.endWrap = endWrap; + } + + public @NotNull String[] getComments() { + return comments; + } + + public boolean endWrap() { + return endWrap; + } + + public boolean startWrap() { + return startWrap; + } + + public static @NotNull ConfigCommentInfo of(@NotNull String[] comments, boolean startWrap, boolean endWrap) { + return new ConfigCommentInfo(comments, startWrap, endWrap); + } + + public static @NotNull ConfigCommentInfo defaults() { + return DEFAULT_INFO; + } + + @Contract("!null->!null") + public static @Nullable ConfigCommentInfo fromAnnotation(@Nullable ConfigComment comment) { + if (comment == null) return null; + else return new ConfigCommentInfo(comment.value(), comment.startWrap(), comment.endWrap()); + } + + public static @NotNull ConfigCommentInfo fromValue(@NotNull ConfigValue value) { + return Optional.ofNullable(value.getComments()).orElse(defaults()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConfigCommentInfo that = (ConfigCommentInfo) o; + return startWrap == that.startWrap && endWrap == that.endWrap && Arrays.equals(getComments(), that.getComments()); + } + + @Override + public int hashCode() { + int result = Objects.hash(startWrap, endWrap); + result = 31 * result + Arrays.hashCode(getComments()); + return result; + } + + @Override + public String toString() { + return "ConfigCommentInfo{" + + "comments=" + Arrays.toString(comments) + + ", startWrap=" + startWrap + + ", endWrap=" + endWrap + + '}'; + } +} diff --git a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java b/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java index cfc735a..66153e6 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/source/ConfigurationProvider.java @@ -27,9 +27,9 @@ public abstract class ConfigurationProvider { public abstract void save() throws Exception; - public abstract void setComments(@NotNull String path, @NotNull String... comments); + public abstract void setComment(@Nullable String path, @Nullable ConfigCommentInfo comment); - public abstract @Nullable String[] getComments(@NotNull String path); + public abstract @Nullable ConfigCommentInfo getComment(@Nullable String path); public abstract @NotNull ConfigInitializer> getInitializer(); diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/ConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/core/value/ConfigValue.java index 6ebfe37..426ca7d 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/ConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/value/ConfigValue.java @@ -1,6 +1,7 @@ package cc.carm.lib.configuration.core.value; import cc.carm.lib.configuration.core.builder.ConfigBuilder; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import org.jetbrains.annotations.NotNull; @@ -17,12 +18,13 @@ public abstract class ConfigValue { protected @Nullable ConfigurationProvider provider; protected @Nullable String configPath; - protected @NotNull String[] comments; + protected @Nullable ConfigCommentInfo comments; protected @Nullable T defaultValue; public ConfigValue(@Nullable ConfigurationProvider provider, - @Nullable String configPath, @NotNull String[] comments, @Nullable T defaultValue) { + @Nullable String configPath, @Nullable ConfigCommentInfo comments, + @Nullable T defaultValue) { this.provider = provider; this.configPath = configPath; this.comments = comments; @@ -30,11 +32,12 @@ public abstract class ConfigValue { } public void initialize(@NotNull ConfigurationProvider provider, boolean saveDefault, - @NotNull String configPath, @NotNull String... comments) { + @NotNull String configPath, @Nullable ConfigCommentInfo comments) { if (this.provider == null) this.provider = provider; if (this.configPath == null) this.configPath = configPath; - if (this.comments.length == 0) this.comments = comments; + if (this.comments == null) this.comments = comments; if (saveDefault) setDefault(); + if (getComments() != null) this.provider.setComment(getConfigPath(), getComments()); } public @Nullable T getDefaultValue() { @@ -103,6 +106,11 @@ public abstract class ConfigValue { Optional.ofNullable(getDefaultValue()).ifPresent(this::set); } + /** + * 判断加载的配置是否与默认值相同。 + * + * @return 获取当前值是否为默认值。 + */ public boolean isDefault() { T defaultValue = getDefaultValue(); T value = get(); @@ -137,12 +145,8 @@ public abstract class ConfigValue { getConfiguration().set(getConfigPath(), value); } - public String[] getComments() { + public @Nullable ConfigCommentInfo getComments() { return comments; } - public void setComments(String[] comments) { - this.comments = comments; - } - } diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/impl/CachedConfigValue.java b/core/src/main/java/cc/carm/lib/configuration/core/value/impl/CachedConfigValue.java index 368809c..93a9b4a 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/impl/CachedConfigValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/value/impl/CachedConfigValue.java @@ -1,5 +1,6 @@ package cc.carm.lib.configuration.core.value.impl; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.value.ConfigValue; import org.jetbrains.annotations.NotNull; @@ -12,7 +13,7 @@ public abstract class CachedConfigValue extends ConfigValue { protected long parsedTime = -1; public CachedConfigValue(@Nullable ConfigurationProvider provider, @Nullable String sectionPath, - @NotNull String[] comments, @Nullable T defaultValue) { + @Nullable ConfigCommentInfo comments, @Nullable T defaultValue) { super(provider, sectionPath, comments, defaultValue); } diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredList.java b/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredList.java index 7cdb942..9eb95b2 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredList.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredList.java @@ -2,6 +2,7 @@ package cc.carm.lib.configuration.core.value.type; import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; @@ -22,7 +23,7 @@ public class ConfiguredList extends CachedConfigValue> { protected final @NotNull ConfigDataFunction serializer; public ConfiguredList(@Nullable ConfigurationProvider provider, - @Nullable String sectionPath, @NotNull String[] comments, + @Nullable String sectionPath, @Nullable ConfigCommentInfo comments, @NotNull Class valueClass, @Nullable List defaultValue, @NotNull ConfigDataFunction parser, @NotNull ConfigDataFunction serializer) { diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredMap.java b/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredMap.java index 99d2104..0393dd2 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredMap.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredMap.java @@ -2,6 +2,7 @@ package cc.carm.lib.configuration.core.value.type; import cc.carm.lib.configuration.core.builder.map.ConfigMapBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; @@ -32,7 +33,7 @@ public class ConfiguredMap extends CachedConfigValue> { protected final @NotNull ConfigDataFunction valueSerializer; public ConfiguredMap(@Nullable ConfigurationProvider provider, - @Nullable String sectionPath, @NotNull String[] comments, + @Nullable String sectionPath, @Nullable ConfigCommentInfo comments, @Nullable Map defaultValue, @NotNull Supplier> supplier, @NotNull Class keyClass, @NotNull ConfigDataFunction keyParser, @NotNull Class valueClass, @NotNull ConfigDataFunction valueParser, diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredSection.java b/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredSection.java index 48eee63..9912e81 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredSection.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredSection.java @@ -3,6 +3,7 @@ package cc.carm.lib.configuration.core.value.type; import cc.carm.lib.configuration.core.builder.value.SectionValueBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigValueParser; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; @@ -24,7 +25,7 @@ public class ConfiguredSection extends CachedConfigValue { protected final @NotNull ConfigDataFunction> serializer; public ConfiguredSection(@Nullable ConfigurationProvider provider, - @Nullable String sectionPath, @NotNull String[] comments, + @Nullable String sectionPath, @Nullable ConfigCommentInfo comments, @NotNull Class valueClass, @Nullable V defaultValue, @NotNull ConfigValueParser parser, @NotNull ConfigDataFunction> serializer) { diff --git a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredValue.java b/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredValue.java index 4dea911..00b4ed1 100644 --- a/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredValue.java +++ b/core/src/main/java/cc/carm/lib/configuration/core/value/type/ConfiguredValue.java @@ -3,6 +3,7 @@ package cc.carm.lib.configuration.core.value.type; import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder; import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigValueParser; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; import org.jetbrains.annotations.NotNull; @@ -30,7 +31,7 @@ public class ConfiguredValue extends CachedConfigValue { protected final @NotNull ConfigDataFunction serializer; public ConfiguredValue(@Nullable ConfigurationProvider provider, - @Nullable String sectionPath, @NotNull String[] comments, + @Nullable String sectionPath, @Nullable ConfigCommentInfo comments, @NotNull Class valueClass, @Nullable V defaultValue, @NotNull ConfigValueParser parser, @NotNull ConfigDataFunction serializer) { diff --git a/impl/json/pom.xml b/impl/json/pom.xml index dd3d9ab..bf39558 100644 --- a/impl/json/pom.xml +++ b/impl/json/pom.xml @@ -5,7 +5,7 @@ easyconfiguration-parent cc.carm.lib - 2.2.0 + 2.3.0 ../../pom.xml 4.0.0 diff --git a/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java b/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java index a55be0e..f92a308 100644 --- a/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java +++ b/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigProvider.java @@ -1,6 +1,7 @@ package cc.carm.lib.configuration.json; import cc.carm.lib.configuration.core.ConfigInitializer; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.source.impl.FileConfigProvider; import com.google.gson.Gson; @@ -68,15 +69,16 @@ public class JSONConfigProvider extends FileConfigProvider { } @Override - public void setComments(@NotNull String path, @NotNull String... comments) { - // JSON doesn't support comments. + public void setComment(@Nullable String path, @Nullable ConfigCommentInfo comment) { + // JSON doesn't support comments; } @Override - public @Nullable String[] getComments(@NotNull String path) { - return new String[0]; // JSON doesn't support comments. + public @Nullable ConfigCommentInfo getComment(@Nullable String path) { + return null; } + @Override public @NotNull ConfigInitializer> getInitializer() { return this.initializer; diff --git a/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java b/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java index f0f7c65..e114fa0 100644 --- a/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java +++ b/impl/json/src/main/java/cc/carm/lib/configuration/json/JSONConfigWrapper.java @@ -4,7 +4,10 @@ import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * Some code comes from BungeeCord's implementation of the JsonConfiguration. @@ -33,12 +36,16 @@ public class JSONConfigWrapper implements ConfigurationWrapper { @Override public @NotNull Set getKeys(boolean deep) { - return new LinkedHashSet<>(this.data.keySet()); + return getValues(deep).keySet(); } @Override public @NotNull Map getValues(boolean deep) { - return new LinkedHashMap<>(this.data); + if (deep) { + Map values = new LinkedHashMap<>(); + mapChildrenValues(values, this, null, true); + return values; + } else return new LinkedHashMap<>(this.data); } @Override @@ -111,4 +118,16 @@ public class JSONConfigWrapper implements ConfigurationWrapper { return (index == -1) ? path : path.substring(index + 1); } + + protected void mapChildrenValues(@NotNull Map output, @NotNull JSONConfigWrapper section, + @Nullable String parent, boolean deep) { + for (Map.Entry entry : section.data.entrySet()) { + String path = (parent == null ? "" : parent + ".") + entry.getKey(); + output.remove(path); + output.put(path, entry.getValue()); + if (deep && entry.getValue() instanceof JSONConfigWrapper) { + this.mapChildrenValues(output, (JSONConfigWrapper) entry.getValue(), path, true); + } + } + } } diff --git a/impl/json/src/test/java/config/JSONConfigTest.java b/impl/json/src/test/java/config/JSONConfigTest.java index 4edf1c6..dfe5d41 100644 --- a/impl/json/src/test/java/config/JSONConfigTest.java +++ b/impl/json/src/test/java/config/JSONConfigTest.java @@ -23,6 +23,11 @@ public class JSONConfigTest { provider.initialize(DemoConfiguration.class); testDemo(); + System.out.println("----------------------------------------------------"); + provider.getConfiguration().getValues(true).forEach((k, v) -> System.out.println(k + ": " + v)); + System.out.println("----------------------------------------------------"); + provider.getConfiguration().getValues(false).forEach((k, v) -> System.out.println(k + ": " + v)); + System.out.println("----------------------------------------------------"); try { provider.save(); diff --git a/impl/yaml/pom.xml b/impl/yaml/pom.xml index b26d511..5f87f9f 100644 --- a/impl/yaml/pom.xml +++ b/impl/yaml/pom.xml @@ -5,7 +5,7 @@ easyconfiguration-parent cc.carm.lib - 2.2.0 + 2.3.0 ../../pom.xml 4.0.0 @@ -27,9 +27,9 @@ - cc.carm.lib - yamlconfiguration-commented - 2.0.2 + org.bspfsystems + yamlconfiguration + 1.0.11 compile diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLComments.java b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLComments.java index 3206f8e..3a1d389 100644 --- a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLComments.java +++ b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLComments.java @@ -1,35 +1,114 @@ package cc.carm.lib.configuration.yaml; -import org.bspfsystems.yamlconfiguration.commented.CommentsProvider; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; +import org.bspfsystems.yamlconfiguration.configuration.ConfigurationSection; +import org.bspfsystems.yamlconfiguration.file.FileConfiguration; +import org.bspfsystems.yamlconfiguration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.BufferedWriter; +import java.io.IOException; import java.util.HashMap; import java.util.Map; +import java.util.StringJoiner; +import java.util.stream.Collectors; +import java.util.stream.IntStream; -public class YAMLComments implements CommentsProvider { +import static cc.carm.lib.configuration.yaml.YAMLConfigProvider.SEPARATOR; - Map comments = new HashMap<>(); +public class YAMLComments { - protected Map getComments() { + Map comments = new HashMap<>(); + + protected Map getComments() { return comments; } - public void set(@NotNull String path, @NotNull String... comments) { - if (comments.length == 0) { + public void set(@Nullable String path, @Nullable ConfigCommentInfo comments) { + if (comments == null) { getComments().remove(path); } else { getComments().put(path, comments); } } - public @Nullable String[] get(@NotNull String path) { - return getComments().get(path); + public @NotNull ConfigCommentInfo get(@Nullable String path) { + return getComments().getOrDefault(path, ConfigCommentInfo.defaults()); } - @Override - public String[] apply(String s) { - return get(s); + public @Nullable String buildComments(@NotNull String indents, @Nullable String path) { + ConfigCommentInfo comments = get(path); + if (!String.join("", comments.getComments()).isEmpty()) { + String prefix = comments.startWrap() ? "\n" : ""; + String suffix = comments.endWrap() ? "\n" : ""; + StringJoiner joiner = new StringJoiner("\n", prefix, suffix); + for (String comment : comments.getComments()) { + if (comment.length() == 0) joiner.add(" "); + else joiner.add(indents + "# " + comment); + } + return joiner + "\n"; + } else { + return comments.startWrap() || comments.endWrap() ? "\n" : null; + } + } + + /** + * 从一个文件读取配置并写入注释到某个写入器中。 + * 该方法的源代码来自 tchristofferson/ConfigUpdater 项目。 + * + * @param source 源配置文件 + * @param writer 配置写入器 + * @throws IOException 当写入发生错误时抛出 + */ + public void writeComments(@NotNull YamlConfiguration source, @NotNull BufferedWriter writer) throws IOException { + FileConfiguration parserConfig = new YamlConfiguration(); + + for (String fullKey : source.getKeys(true)) { + String indents = getIndents(fullKey); + String comment = buildComments(indents, fullKey); + if (comment != null) writer.write(comment); + + Object currentValue = source.get(fullKey); + + String[] splitFullKey = fullKey.split("[" + SEPARATOR + "]"); + String trailingKey = splitFullKey[splitFullKey.length - 1]; + + if (currentValue instanceof ConfigurationSection) { + writer.write(indents + trailingKey + ":"); + + if (!((ConfigurationSection) currentValue).getKeys(false).isEmpty()) + writer.write("\n"); + else + writer.write(" {}\n"); + + continue; + } + + parserConfig.set(trailingKey, currentValue); + String yaml = parserConfig.saveToString(); + yaml = yaml.substring(0, yaml.length() - 1).replace("\n", "\n" + indents); + String toWrite = indents + yaml + "\n"; + parserConfig.set(trailingKey, null); + writer.write(toWrite); + } + + String endComment = buildComments("", null); + if (endComment != null) writer.write(endComment); + + writer.close(); + } + + /** + * 得到一个键的缩进。 + * 该方法的源代码来自 tchristofferson/ConfigUpdater 项目。 + * + * @param key 键 + * @return 该键的缩进文本 + */ + protected static String getIndents(String key) { + String[] splitKey = key.split("[" + YAMLConfigProvider.SEPARATOR + "]"); + return IntStream.range(1, splitKey.length).mapToObj(i -> " ").collect(Collectors.joining()); } } diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java index f5a976f..d321063 100644 --- a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java +++ b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLConfigProvider.java @@ -1,17 +1,25 @@ package cc.carm.lib.configuration.yaml; import cc.carm.lib.configuration.core.ConfigInitializer; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.impl.FileConfigProvider; -import org.bspfsystems.yamlconfiguration.commented.CommentedYamlConfiguration; +import org.bspfsystems.yamlconfiguration.file.YamlConfiguration; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.BufferedWriter; import java.io.File; +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; public class YAMLConfigProvider extends FileConfigProvider { + protected static final char SEPARATOR = '.'; + protected final @NotNull YAMLComments comments = new YAMLComments(); - protected CommentedYamlConfiguration configuration; + protected YamlConfiguration configuration; protected ConfigInitializer initializer; public YAMLConfigProvider(@NotNull File file) { @@ -19,7 +27,7 @@ public class YAMLConfigProvider extends FileConfigProvider { } public void initializeConfig() { - this.configuration = CommentedYamlConfiguration.loadConfiguration(comments, file); + this.configuration = YamlConfiguration.loadConfiguration(file); this.initializer = new ConfigInitializer<>(this); } @@ -36,15 +44,29 @@ public class YAMLConfigProvider extends FileConfigProvider { @Override public void save() throws Exception { configuration.save(getFile()); + + + // tchristofferson/ConfigUpdater start + StringWriter writer = new StringWriter(); + this.comments.writeComments(configuration, new BufferedWriter(writer)); + String value = writer.toString(); // config contents + + Path toUpdatePath = getFile().toPath(); + if (!value.equals(new String(Files.readAllBytes(toUpdatePath), StandardCharsets.UTF_8))) { + // if updated contents are not the same as current file contents, update + Files.write(toUpdatePath, value.getBytes(StandardCharsets.UTF_8)); + } + // tchristofferson/ConfigUpdater end + } @Override - public void setComments(@NotNull String path, @NotNull String... comments) { + public void setComment(@Nullable String path, @Nullable ConfigCommentInfo comments) { this.comments.set(path, comments); } @Override - public @Nullable String[] getComments(@NotNull String path) { + public @Nullable ConfigCommentInfo getComment(@Nullable String path) { return this.comments.get(path); } diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java index 6db05fc..e2a1a1d 100644 --- a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java +++ b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/YAMLValue.java @@ -1,5 +1,6 @@ package cc.carm.lib.configuration.yaml; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; import cc.carm.lib.configuration.yaml.builder.YAMLConfigBuilder; @@ -13,7 +14,8 @@ public abstract class YAMLValue extends CachedConfigValue { } public YAMLValue(@Nullable YAMLConfigProvider provider, - @Nullable String configPath, @NotNull String[] comments, @Nullable T defaultValue) { + @Nullable String configPath, @Nullable ConfigCommentInfo comments, + @Nullable T defaultValue) { super(provider, configPath, comments, defaultValue); } diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java index 75bcff2..11f9714 100644 --- a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java +++ b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/builder/serializable/SerializableBuilder.java @@ -21,7 +21,7 @@ public class SerializableBuilder @Override public @NotNull ConfiguredSerializable build() { - return new ConfiguredSerializable<>(this.provider, this.path, this.comments, this.valueClass, this.defaultValue); + return new ConfiguredSerializable<>(this.provider, this.path, buildComments(), this.valueClass, this.defaultValue); } diff --git a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java index 03de303..aa2d7f4 100644 --- a/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java +++ b/impl/yaml/src/main/java/cc/carm/lib/configuration/yaml/value/ConfiguredSerializable.java @@ -1,7 +1,8 @@ package cc.carm.lib.configuration.yaml.value; -import cc.carm.lib.configuration.yaml.YAMLValue; +import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.yaml.YAMLConfigProvider; +import cc.carm.lib.configuration.yaml.YAMLValue; import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -15,14 +16,14 @@ public class ConfiguredSerializable extends } public static ConfiguredSerializable of(@NotNull Class valueClass, - @Nullable V defaultValue) { + @Nullable V defaultValue) { return builder().ofSerializable(valueClass).defaults(defaultValue).build(); } protected final @NotNull Class valueClass; public ConfiguredSerializable(@Nullable YAMLConfigProvider provider, - @Nullable String configPath, @NotNull String[] comments, + @Nullable String configPath, @Nullable ConfigCommentInfo comments, @NotNull Class valueClass, @Nullable T defaultValue) { super(provider, configPath, comments, defaultValue); this.valueClass = valueClass; diff --git a/impl/yaml/src/test/java/config/source/DatabaseConfiguration.java b/impl/yaml/src/test/java/config/source/DatabaseConfiguration.java index 298886f..404f571 100644 --- a/impl/yaml/src/test/java/config/source/DatabaseConfiguration.java +++ b/impl/yaml/src/test/java/config/source/DatabaseConfiguration.java @@ -10,22 +10,26 @@ import cc.carm.lib.configuration.core.value.type.ConfiguredValue; public class DatabaseConfiguration extends ConfigurationRoot { @ConfigPath("driver") - @ConfigComment({ + @ConfigComment(value = { "数据库驱动配置,请根据数据库类型设置。", "- MySQL: com.mysql.cj.jdbc.Driver", "- MariaDB(推荐): org.mariadb.jdbc.Driver", - }) + }, startWrap = false) protected static final ConfigValue DRIVER_NAME = ConfiguredValue.of( String.class, "com.mysql.cj.jdbc.Driver" ); + @ConfigComment(startWrap = false) protected static final ConfigValue HOST = ConfiguredValue.of(String.class, "127.0.0.1"); + @ConfigComment(startWrap = false) protected static final ConfigValue PORT = ConfiguredValue.of(Integer.class, 3306); - + @ConfigComment(startWrap = false) protected static final ConfigValue DATABASE = ConfiguredValue.of(String.class, "minecraft"); + @ConfigComment(startWrap = false) protected static final ConfigValue USERNAME = ConfiguredValue.of(String.class, "root"); + @ConfigComment(startWrap = false) protected static final ConfigValue PASSWORD = ConfiguredValue.of(String.class, "password"); - + @ConfigComment(startWrap = false) protected static final ConfigValue EXTRA = ConfiguredValue.of(String.class, "?useSSL=false"); protected static String buildJDBC() { diff --git a/impl/yaml/src/test/java/config/source/DemoConfiguration.java b/impl/yaml/src/test/java/config/source/DemoConfiguration.java index 15903d9..ba07388 100644 --- a/impl/yaml/src/test/java/config/source/DemoConfiguration.java +++ b/impl/yaml/src/test/java/config/source/DemoConfiguration.java @@ -16,14 +16,16 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; + +@ConfigComment({"给根类添加的注释将显示在文件的末尾。"}) public class DemoConfiguration extends ConfigurationRoot { @ConfigPath(root = true) - @ConfigComment({ + @ConfigComment(value = { "有时候,需要在配置文件最上面显示点东西,", "此时就推荐添加一个可以用到但并不重要的参数到最上面", "并给他添加对应的注释。" - }) + }, startWrap = false, endWrap = true) protected static final ConfigValue VERSION = ConfiguredValue.of(Double.class, 1.0D); diff --git a/pom.xml b/pom.xml index 7c28a1c..d045080 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ cc.carm.lib easyconfiguration-parent pom - 2.2.0 + 2.3.0 core impl/yaml