1
mirror of https://github.com/CarmJos/EasyConfiguration.git synced 2024-09-19 20:25:51 +00:00

[3.0.0] (breaking-update) update comments usage.

This commit is contained in:
Carm Jos 2022-05-18 23:23:11 +08:00
parent e9a0f0ff30
commit 6b3a353fcc
35 changed files with 399 additions and 314 deletions

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>2.3.0</version> <version>3.0.0</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<properties> <properties>

View File

@ -1,14 +1,16 @@
package cc.carm.lib.configuration.core; 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.annotation.ConfigPath;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo; import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.annotation.InlineComment;
import cc.carm.lib.configuration.core.source.ConfigurationProvider; import cc.carm.lib.configuration.core.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ConfigValue; import cc.carm.lib.configuration.core.value.ConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
/** /**
* 配置文件类初始化方法 * 配置文件类初始化方法
@ -45,7 +47,7 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
public void initialize(@NotNull Class<? extends ConfigurationRoot> clazz, public void initialize(@NotNull Class<? extends ConfigurationRoot> clazz,
boolean saveDefaults, boolean loadSubClasses) { boolean saveDefaults, boolean loadSubClasses) {
initializeClass( initializeClass(
clazz, null, clazz, null, null,
null, null, null, null, null, null,
saveDefaults, loadSubClasses saveDefaults, loadSubClasses
); );
@ -60,32 +62,28 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
protected void initializeClass(@NotNull Class<?> clazz, protected void initializeClass(@NotNull Class<?> clazz,
@Nullable String parentPath, @Nullable String fieldName, @Nullable String parentPath, @Nullable String fieldName,
@Nullable ConfigPath fieldPath, @Nullable ConfigComment filedComments, @Nullable ConfigPath fieldPath,
@Nullable HeaderComment fieldHeaderComments,
@Nullable InlineComment fieldInlineComments,
boolean saveDefaults, boolean loadSubClasses) { boolean saveDefaults, boolean loadSubClasses) {
String path = getClassPath(clazz, parentPath, fieldName, fieldPath); String path = getClassPath(clazz, parentPath, fieldName, fieldPath);
this.provider.setComment(path, getClassComments(clazz, filedComments)); this.provider.setHeaderComment(path, getClassHeaderComments(clazz, fieldHeaderComments));
if (path != null) this.provider.setInlineComment(path, readInlineComments(fieldInlineComments));
for (Field field : clazz.getDeclaredFields()) { for (Field field : clazz.getDeclaredFields()) {
initializeField(clazz, field, path, saveDefaults, loadSubClasses); initializeField(clazz, field, path, saveDefaults, loadSubClasses);
} }
if (!loadSubClasses) return;
Class<?>[] classes = clazz.getDeclaredClasses(); Class<?>[] classes = clazz.getDeclaredClasses();
if (loadSubClasses && classes.length > 0) { for (int i = classes.length - 1; i >= 0; i--) { // 逆向加载保持顺序
// 逆向加载保持顺序
for (int i = classes.length - 1; i >= 0; i--) {
initializeClass( initializeClass(
classes[i], path, classes[i].getSimpleName(), classes[i], path, classes[i].getSimpleName(),
null, null, null, null, null,
saveDefaults, true saveDefaults, true
); );
} }
} }
}
protected void initializeValue(@NotNull ConfigValue<?> value, @NotNull String path,
@Nullable ConfigCommentInfo comments, boolean saveDefaults) {
value.initialize(provider, saveDefaults, path, comments);
}
private void initializeField(@NotNull Class<?> source, @NotNull Field field, @Nullable String parent, private void initializeField(@NotNull Class<?> source, @NotNull Field field, @Nullable String parent,
boolean saveDefaults, boolean loadSubClasses) { boolean saveDefaults, boolean loadSubClasses) {
@ -95,14 +93,16 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
if (object instanceof ConfigValue<?>) { if (object instanceof ConfigValue<?>) {
initializeValue( initializeValue(
(ConfigValue<?>) object, getFieldPath(field, parent), (ConfigValue<?>) object, getFieldPath(field, parent),
ConfigCommentInfo.fromAnnotation(field.getAnnotation(ConfigComment.class)), field.getAnnotation(HeaderComment.class),
field.getAnnotation(InlineComment.class),
saveDefaults saveDefaults
); );
} else if (object instanceof Class<?>) { } else if (object instanceof Class<?>) {
initializeClass( initializeClass(
(Class<?>) object, parent, field.getName(), (Class<?>) object, parent, field.getName(),
field.getAnnotation(ConfigPath.class), field.getAnnotation(ConfigPath.class),
field.getAnnotation(ConfigComment.class), field.getAnnotation(HeaderComment.class),
field.getAnnotation(InlineComment.class),
saveDefaults, loadSubClasses saveDefaults, loadSubClasses
); );
} }
@ -110,15 +110,36 @@ public class ConfigInitializer<T extends ConfigurationProvider<?>> {
} }
} }
protected void setComments(@Nullable String path, @Nullable ConfigCommentInfo comments) { protected void initializeValue(@NotNull ConfigValue<?> value, @NotNull String path,
if (comments != null) this.provider.setComment(path, comments); @Nullable HeaderComment fieldHeaderComment,
@Nullable InlineComment fieldInlineComment,
boolean saveDefaults) {
value.initialize(
provider, saveDefaults, path,
readHeaderComments(fieldHeaderComment),
readInlineComments(fieldInlineComment)
);
} }
protected static @Nullable ConfigCommentInfo getClassComments(@NotNull Class<?> clazz, protected static @Nullable List<String> getClassHeaderComments(@NotNull Class<?> clazz,
@Nullable ConfigComment fieldAnnotation) { @Nullable HeaderComment fieldAnnotation) {
ConfigCommentInfo classComments = ConfigCommentInfo.fromAnnotation(clazz.getAnnotation(ConfigComment.class)); List<String> classComments = readHeaderComments(clazz.getAnnotation(HeaderComment.class));
if (classComments != null) return classComments; if (classComments != null) return classComments;
return ConfigCommentInfo.fromAnnotation(fieldAnnotation); else return readHeaderComments(fieldAnnotation);
}
protected static List<String> readHeaderComments(@Nullable HeaderComment annotation) {
if (annotation == null) return null;
String[] value = annotation.value();
return value.length > 0 ? Arrays.asList(value) : null;
}
protected static @Nullable String readInlineComments(@Nullable InlineComment annotation) {
if (annotation == null) return null;
String value = annotation.value();
return value.length() > 0 ? value : null;
} }
protected static @Nullable String getClassPath(@NotNull Class<?> clazz, protected static @Nullable String getClassPath(@NotNull Class<?> clazz,

View File

@ -1,45 +0,0 @@
package cc.carm.lib.configuration.core.annotation;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigComment {
@NotNull
String[] value() default "";
/**
* 首行换行即会在注释开始前进行一次换行与上方配置分离优化观感
*
* <blockquote><pre>
* some-key: "SomeValue"
*
* # 注释第一行
* # 注释第二行
* startWrap: true
* </pre></blockquote>
*
* @return 是否在结尾添加换行符
*/
boolean startWrap() default true;
/**
* 末尾换行即会在注释结束后进行一次换行
* <blockquote><pre>
* # 注释第一行
* # 注释第二行
*
* endWrap: true
* </pre></blockquote>
* <p> 该功能可用于编写配置文件的顶部注释
*
* @return 是否在结尾添加换行符
*/
boolean endWrap() default false;
}

View File

@ -0,0 +1,39 @@
package cc.carm.lib.configuration.core.annotation;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 顶部注释用于给对应配置的顶部添加注释便于使用者阅读查看
* <p>
* <blockquote><pre>
* # 注释第一行
* # 注释第二行
* foo: "bar"
* </pre></blockquote>
*/
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface HeaderComment {
/**
* 注释内容若内容长度为0则会视为一个空行
* <p> <b>{"foo","","bar"}</b>
* 会被添加为
* <blockquote><pre>
* # foo
*
* # bar
* foo: "bar"
* </pre></blockquote>
*
* @return 注释内容
*/
@NotNull
String[] value() default "";
}

View File

@ -0,0 +1,33 @@
package cc.carm.lib.configuration.core.annotation;
import org.jetbrains.annotations.NotNull;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 行内注释用于给对应配置的所在行添加注释便于使用者阅读查看
*
* <blockquote><pre>
* foo: "bar" # 注释内容
* </pre></blockquote>
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface InlineComment {
/**
* 注释内容若内容长度为0则不会添加注释
* <p> <b>"foobar"</b> 将被设定为
* <blockquote><pre>
* foo: "bar" # foobar
* </pre></blockquote>
*
* @return 注释内容
*/
@NotNull
String value() default "";
}

View File

@ -1,11 +1,13 @@
package cc.carm.lib.configuration.core.builder; 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.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ConfigValue; import cc.carm.lib.configuration.core.value.ConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T, B, P>, P extends ConfigurationProvider<?>> { public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T, B, P>, P extends ConfigurationProvider<?>> {
protected final Class<? super P> providerClass; protected final Class<? super P> providerClass;
@ -13,9 +15,8 @@ public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T
protected @Nullable P provider; protected @Nullable P provider;
protected @Nullable String path; protected @Nullable String path;
protected @NotNull String[] comments = new String[0]; protected @Nullable List<String> headerComments;
protected boolean startWrap = true; protected @Nullable String inlineComment;
protected boolean endWrap = false;
protected @Nullable T defaultValue; protected @Nullable T defaultValue;
@ -38,38 +39,26 @@ public abstract class AbstractConfigBuilder<T, B extends AbstractConfigBuilder<T
} }
public @NotNull B comments(@NotNull String... comments) { public @NotNull B comments(@NotNull String... comments) {
this.comments = comments; return headerComments(comments);
}
public @NotNull B headerComments(@NotNull String... comments) {
return headerComments(Arrays.asList(comments));
}
public @NotNull B headerComments(@NotNull List<String> comments) {
this.headerComments = comments;
return getThis(); return getThis();
} }
public @NotNull B setStartWarp(boolean enable) { public @NotNull B inlineComment(@NotNull String comment) {
this.startWrap = enable; this.inlineComment = comment;
return getThis(); return getThis();
} }
public @NotNull B startWarp() {
return setStartWarp(true);
}
public @NotNull B setEndWarp(boolean enable) {
this.endWrap = enable;
return getThis();
}
public @NotNull B endWarp() {
return setEndWarp(true);
}
public @NotNull B defaults(@Nullable T defaultValue) { public @NotNull B defaults(@Nullable T defaultValue) {
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
return getThis(); return getThis();
} }
protected @Nullable ConfigCommentInfo buildComments() {
ConfigCommentInfo info = ConfigCommentInfo.of(this.comments, this.startWrap, this.endWrap);
if (info.equals(ConfigCommentInfo.defaults())) return null;
else return info;
}
} }

View File

@ -1,8 +1,10 @@
package cc.carm.lib.configuration.core.builder.list; package cc.carm.lib.configuration.core.builder.list;
import cc.carm.lib.configuration.core.annotation.InlineComment;
import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class ConfigListBuilder<V> { public class ConfigListBuilder<V> {
protected final @NotNull Class<V> valueClass; protected final @NotNull Class<V> valueClass;

View File

@ -65,7 +65,8 @@ public class SourceListBuilder<S, V> extends CommonConfigBuilder<List<V>, Source
@Override @Override
public @NotNull ConfiguredList<V> build() { public @NotNull ConfiguredList<V> build() {
return new ConfiguredList<>( return new ConfiguredList<>(
this.provider, this.path, this.buildComments(), this.provider, this.path,
this.headerComments, this.inlineComment,
this.valueClass, this.defaultValue, this.valueClass, this.defaultValue,
this.sourceParser.andThen(this.valueParser), this.sourceParser.andThen(this.valueParser),
this.valueSerializer.andThen(sourceSerializer) this.valueSerializer.andThen(sourceSerializer)

View File

@ -89,7 +89,8 @@ public class SourceMapBuilder<M extends Map<K, V>, S, K, V> extends CommonConfig
@Override @Override
public @NotNull ConfiguredMap<K, V> build() { public @NotNull ConfiguredMap<K, V> build() {
return new ConfiguredMap<>( return new ConfiguredMap<>(
this.provider, this.path,this.buildComments(), this.provider, this.path,
this.headerComments, this.inlineComment,
this.defaultValue, this.supplier, this.defaultValue, this.supplier,
this.keyClass, this.keyParser, this.keyClass, this.keyParser,
this.valueClass, this.sourceParser.andThen(this.valueParser), this.valueClass, this.sourceParser.andThen(this.valueParser),

View File

@ -45,7 +45,8 @@ public class SectionValueBuilder<V>
@Override @Override
public @NotNull ConfiguredSection<V> build() { public @NotNull ConfiguredSection<V> build() {
return new ConfiguredSection<>( return new ConfiguredSection<>(
this.provider, this.path,this.buildComments(), this.provider, this.path,
this.headerComments, this.inlineComment,
this.valueClass, this.defaultValue, this.valueClass, this.defaultValue,
this.parser, this.serializer this.parser, this.serializer
); );

View File

@ -3,7 +3,6 @@ package cc.carm.lib.configuration.core.builder.value;
import cc.carm.lib.configuration.core.builder.CommonConfigBuilder; import cc.carm.lib.configuration.core.builder.CommonConfigBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.function.ConfigValueParser; 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 cc.carm.lib.configuration.core.value.type.ConfiguredValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -58,7 +57,8 @@ public class SourceValueBuilder<S, V> extends CommonConfigBuilder<V, SourceValue
@Override @Override
public @NotNull ConfiguredValue<V> build() { public @NotNull ConfiguredValue<V> build() {
return new ConfiguredValue<>( return new ConfiguredValue<>(
this.provider, this.path, this.buildComments(), this.provider, this.path,
this.headerComments, this.inlineComment,
this.valueClass, this.defaultValue, this.valueClass, this.defaultValue,
this.valueParser.compose(this.sourceParser), this.valueParser.compose(this.sourceParser),
this.valueSerializer.andThen(sourceSerializer) this.valueSerializer.andThen(sourceSerializer)

View File

@ -1,80 +0,0 @@
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 +
'}';
}
}

View File

@ -4,6 +4,9 @@ import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.core.ConfigurationRoot; import cc.carm.lib.configuration.core.ConfigurationRoot;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.List;
public abstract class ConfigurationProvider<W extends ConfigurationWrapper> { public abstract class ConfigurationProvider<W extends ConfigurationWrapper> {
@ -27,9 +30,15 @@ public abstract class ConfigurationProvider<W extends ConfigurationWrapper> {
public abstract void save() throws Exception; public abstract void save() throws Exception;
public abstract void setComment(@Nullable String path, @Nullable ConfigCommentInfo comment); public abstract void setHeaderComment(@Nullable String path, @Nullable List<String> comments);
public abstract @Nullable ConfigCommentInfo getComment(@Nullable String path); public abstract void setInlineComment(@NotNull String path, @Nullable String comment);
@Nullable
@Unmodifiable
public abstract List<String> getHeaderComment(@Nullable String path);
public abstract @Nullable String getInlineComment(@NotNull String path);
public abstract @NotNull ConfigInitializer<? extends ConfigurationProvider<W>> getInitializer(); public abstract @NotNull ConfigInitializer<? extends ConfigurationProvider<W>> getInitializer();

View File

@ -4,6 +4,11 @@ import cc.carm.lib.configuration.core.function.ConfigValueParser;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
interface ConfigurationReader { interface ConfigurationReader {
@ -26,7 +31,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Byte.class); return getWrapper().isType(path, Byte.class);
} }
default @Nullable Byte getByte(@NotNull String path) { default @Nullable Byte getByte(@NotNull String path) {
return getByte(path, (byte) 0); return getByte(path, (byte) 0);
} }
@ -36,12 +40,10 @@ interface ConfigurationReader {
return getWrapper().get(path, def, ConfigValueParser.byteValue()); return getWrapper().get(path, def, ConfigValueParser.byteValue());
} }
default boolean isShort(@NotNull String path) { default boolean isShort(@NotNull String path) {
return getWrapper().isType(path, Short.class); return getWrapper().isType(path, Short.class);
} }
default @Nullable Short getShort(@NotNull String path) { default @Nullable Short getShort(@NotNull String path) {
return getShort(path, (short) 0); return getShort(path, (short) 0);
} }
@ -56,7 +58,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Integer.class); return getWrapper().isType(path, Integer.class);
} }
default @Nullable Integer getInt(@NotNull String path) { default @Nullable Integer getInt(@NotNull String path) {
return getInt(path, 0); return getInt(path, 0);
} }
@ -71,7 +72,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Long.class); return getWrapper().isType(path, Long.class);
} }
default @Nullable Long getLong(@NotNull String path) { default @Nullable Long getLong(@NotNull String path) {
return getLong(path, 0L); return getLong(path, 0L);
} }
@ -86,7 +86,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Float.class); return getWrapper().isType(path, Float.class);
} }
default @Nullable Float getFloat(@NotNull String path) { default @Nullable Float getFloat(@NotNull String path) {
return getFloat(path, 0.0F); return getFloat(path, 0.0F);
} }
@ -101,7 +100,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Double.class); return getWrapper().isType(path, Double.class);
} }
default @Nullable Double getDouble(@NotNull String path) { default @Nullable Double getDouble(@NotNull String path) {
return getDouble(path, 0.0D); return getDouble(path, 0.0D);
} }
@ -116,7 +114,6 @@ interface ConfigurationReader {
return getWrapper().isType(path, Boolean.class); return getWrapper().isType(path, Boolean.class);
} }
default @Nullable Character getChar(@NotNull String path) { default @Nullable Character getChar(@NotNull String path) {
return getChar(path, null); return getChar(path, null);
} }
@ -140,5 +137,54 @@ interface ConfigurationReader {
return getWrapper().get(path, def, String.class); return getWrapper().get(path, def, String.class);
} }
@Unmodifiable
default @NotNull List<String> getStringList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.castToString());
}
@Unmodifiable
default @NotNull List<Integer> getIntegerList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.intValue());
}
@Unmodifiable
default @NotNull List<Long> getLongList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.longValue());
}
@Unmodifiable
default @NotNull List<Double> getDoubleList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.doubleValue());
}
@Unmodifiable
default @NotNull List<Float> getFloatList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.floatValue());
}
@Unmodifiable
default @NotNull List<Byte> getByteList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.byteValue());
}
@Unmodifiable
default @NotNull List<Character> getCharList(@NotNull String path) {
return parseList(getWrapper().getList(path), ConfigValueParser.castObject(Character.class));
}
@Unmodifiable
static <T> @NotNull List<T> parseList(@Nullable List<?> list, ConfigValueParser<Object, T> parser) {
if (list == null) return Collections.emptyList();
List<T> values = new ArrayList<>();
for (Object o : list) {
try {
T parsed = parser.parse(o, null);
if (parsed != null) values.add(parsed);
} catch (Exception ignored) {
}
}
return values;
}
} }

View File

@ -1,12 +1,13 @@
package cc.carm.lib.configuration.core.value; package cc.carm.lib.configuration.core.value;
import cc.carm.lib.configuration.core.builder.ConfigBuilder; 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.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper; 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 org.jetbrains.annotations.Unmodifiable;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
@ -18,26 +19,37 @@ public abstract class ConfigValue<T> {
protected @Nullable ConfigurationProvider<?> provider; protected @Nullable ConfigurationProvider<?> provider;
protected @Nullable String configPath; protected @Nullable String configPath;
protected @Nullable ConfigCommentInfo comments;
protected @Nullable List<String> headerComments;
protected @Nullable String inlineComments;
protected @Nullable T defaultValue; protected @Nullable T defaultValue;
public ConfigValue(@Nullable ConfigurationProvider<?> provider, public ConfigValue(@Nullable ConfigurationProvider<?> provider, @Nullable String configPath,
@Nullable String configPath, @Nullable ConfigCommentInfo comments, @Nullable List<String> headerComments, @Nullable String inlineComments,
@Nullable T defaultValue) { @Nullable T defaultValue) {
this.provider = provider; this.provider = provider;
this.configPath = configPath; this.configPath = configPath;
this.comments = comments; this.headerComments = headerComments;
this.inlineComments = inlineComments;
this.defaultValue = defaultValue; this.defaultValue = defaultValue;
} }
public void initialize(@NotNull ConfigurationProvider<?> provider, boolean saveDefault, public void initialize(@NotNull ConfigurationProvider<?> provider, boolean saveDefault, @NotNull String configPath,
@NotNull String configPath, @Nullable ConfigCommentInfo comments) { @Nullable List<String> headerComments, @Nullable String inlineComments) {
if (this.provider == null) this.provider = provider; if (this.provider == null) this.provider = provider;
if (this.configPath == null) this.configPath = configPath; if (this.configPath == null) this.configPath = configPath;
if (this.comments == null) this.comments = comments; if (this.headerComments == null) this.headerComments = headerComments;
if (this.inlineComments == null) this.inlineComments = inlineComments;
if (saveDefault) setDefault(); if (saveDefault) setDefault();
if (getComments() != null) this.provider.setComment(getConfigPath(), getComments());
if (getHeaderComments() != null) {
this.provider.setHeaderComment(getConfigPath(), getHeaderComments());
}
if (getInlineComments() != null) {
this.provider.setInlineComment(getConfigPath(), getInlineComments());
}
} }
public @Nullable T getDefaultValue() { public @Nullable T getDefaultValue() {
@ -145,8 +157,13 @@ public abstract class ConfigValue<T> {
getConfiguration().set(getConfigPath(), value); getConfiguration().set(getConfigPath(), value);
} }
public @Nullable ConfigCommentInfo getComments() { public @Nullable String getInlineComments() {
return comments; return inlineComments;
}
@Unmodifiable
public @Nullable List<String> getHeaderComments() {
return headerComments;
} }
} }

View File

@ -1,11 +1,11 @@
package cc.carm.lib.configuration.core.value.impl; 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.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.ConfigValue; import cc.carm.lib.configuration.core.value.ConfigValue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
public abstract class CachedConfigValue<T> extends ConfigValue<T> { public abstract class CachedConfigValue<T> extends ConfigValue<T> {
@ -13,8 +13,9 @@ public abstract class CachedConfigValue<T> extends ConfigValue<T> {
protected long parsedTime = -1; protected long parsedTime = -1;
public CachedConfigValue(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath, public CachedConfigValue(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
@Nullable ConfigCommentInfo comments, @Nullable T defaultValue) { @Nullable List<String> headerComments, @Nullable String inlineComments,
super(provider, sectionPath, comments, defaultValue); @Nullable T defaultValue) {
super(provider, sectionPath, headerComments, inlineComments, defaultValue);
} }
protected T updateCache(T value) { protected T updateCache(T value) {

View File

@ -1,8 +1,8 @@
package cc.carm.lib.configuration.core.value.type; package cc.carm.lib.configuration.core.value.type;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder; import cc.carm.lib.configuration.core.builder.list.ConfigListBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction; 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.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -17,17 +17,18 @@ public class ConfiguredList<V> extends CachedConfigValue<List<V>> {
return builder().asList(valueClass); return builder().asList(valueClass);
} }
@HeaderComment
protected final @NotNull Class<V> valueClass; protected final @NotNull Class<V> valueClass;
protected final @NotNull ConfigDataFunction<Object, V> parser; protected final @NotNull ConfigDataFunction<Object, V> parser;
protected final @NotNull ConfigDataFunction<V, Object> serializer; protected final @NotNull ConfigDataFunction<V, Object> serializer;
public ConfiguredList(@Nullable ConfigurationProvider<?> provider, public ConfiguredList(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
@Nullable String sectionPath, @Nullable ConfigCommentInfo comments, @Nullable List<String> headerComments, @Nullable String inlineComments,
@NotNull Class<V> valueClass, @Nullable List<V> defaultValue, @NotNull Class<V> valueClass, @Nullable List<V> defaultValue,
@NotNull ConfigDataFunction<Object, V> parser, @NotNull ConfigDataFunction<Object, V> parser,
@NotNull ConfigDataFunction<V, Object> serializer) { @NotNull ConfigDataFunction<V, Object> serializer) {
super(provider, sectionPath, comments, defaultValue); super(provider, sectionPath, headerComments, inlineComments, defaultValue);
this.valueClass = valueClass; this.valueClass = valueClass;
this.parser = parser; this.parser = parser;
this.serializer = serializer; this.serializer = serializer;

View File

@ -2,7 +2,6 @@ package cc.carm.lib.configuration.core.value.type;
import cc.carm.lib.configuration.core.builder.map.ConfigMapBuilder; import cc.carm.lib.configuration.core.builder.map.ConfigMapBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction; 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.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
@ -10,6 +9,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -32,14 +32,14 @@ public class ConfiguredMap<K, V> extends CachedConfigValue<Map<K, V>> {
protected final @NotNull ConfigDataFunction<K, String> keySerializer; protected final @NotNull ConfigDataFunction<K, String> keySerializer;
protected final @NotNull ConfigDataFunction<V, Object> valueSerializer; protected final @NotNull ConfigDataFunction<V, Object> valueSerializer;
public ConfiguredMap(@Nullable ConfigurationProvider<?> provider, public ConfiguredMap(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
@Nullable String sectionPath, @Nullable ConfigCommentInfo comments, @Nullable List<String> headerComments, @Nullable String inlineComments,
@Nullable Map<K, V> defaultValue, @NotNull Supplier<? extends Map<K, V>> supplier, @Nullable Map<K, V> defaultValue, @NotNull Supplier<? extends Map<K, V>> supplier,
@NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser, @NotNull Class<K> keyClass, @NotNull ConfigDataFunction<String, K> keyParser,
@NotNull Class<V> valueClass, @NotNull ConfigDataFunction<Object, V> valueParser, @NotNull Class<V> valueClass, @NotNull ConfigDataFunction<Object, V> valueParser,
@NotNull ConfigDataFunction<K, String> keySerializer, @NotNull ConfigDataFunction<K, String> keySerializer,
@NotNull ConfigDataFunction<V, Object> valueSerializer) { @NotNull ConfigDataFunction<V, Object> valueSerializer) {
super(provider, sectionPath, comments, defaultValue); super(provider, sectionPath, headerComments, inlineComments, defaultValue);
this.supplier = supplier; this.supplier = supplier;
this.keyClass = keyClass; this.keyClass = keyClass;
this.valueClass = valueClass; this.valueClass = valueClass;

View File

@ -3,13 +3,13 @@ package cc.carm.lib.configuration.core.value.type;
import cc.carm.lib.configuration.core.builder.value.SectionValueBuilder; import cc.carm.lib.configuration.core.builder.value.SectionValueBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.function.ConfigValueParser; 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.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.ConfigurationWrapper; import cc.carm.lib.configuration.core.source.ConfigurationWrapper;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -24,12 +24,12 @@ public class ConfiguredSection<V> extends CachedConfigValue<V> {
protected final @NotNull ConfigValueParser<ConfigurationWrapper, V> parser; protected final @NotNull ConfigValueParser<ConfigurationWrapper, V> parser;
protected final @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer; protected final @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer;
public ConfiguredSection(@Nullable ConfigurationProvider<?> provider, public ConfiguredSection(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
@Nullable String sectionPath, @Nullable ConfigCommentInfo comments, @Nullable List<String> headerComments, @Nullable String inlineComments,
@NotNull Class<V> valueClass, @Nullable V defaultValue, @NotNull Class<V> valueClass, @Nullable V defaultValue,
@NotNull ConfigValueParser<ConfigurationWrapper, V> parser, @NotNull ConfigValueParser<ConfigurationWrapper, V> parser,
@NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) { @NotNull ConfigDataFunction<V, ? extends Map<String, Object>> serializer) {
super(provider, sectionPath, comments, defaultValue); super(provider, sectionPath, headerComments, inlineComments, defaultValue);
this.valueClass = valueClass; this.valueClass = valueClass;
this.parser = parser; this.parser = parser;
this.serializer = serializer; this.serializer = serializer;

View File

@ -3,12 +3,12 @@ package cc.carm.lib.configuration.core.value.type;
import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder; import cc.carm.lib.configuration.core.builder.value.ConfigValueBuilder;
import cc.carm.lib.configuration.core.function.ConfigDataFunction; import cc.carm.lib.configuration.core.function.ConfigDataFunction;
import cc.carm.lib.configuration.core.function.ConfigValueParser; 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.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Optional; import java.util.Optional;
public class ConfiguredValue<V> extends CachedConfigValue<V> { public class ConfiguredValue<V> extends CachedConfigValue<V> {
@ -30,13 +30,13 @@ public class ConfiguredValue<V> extends CachedConfigValue<V> {
protected final @NotNull ConfigValueParser<Object, V> parser; protected final @NotNull ConfigValueParser<Object, V> parser;
protected final @NotNull ConfigDataFunction<V, Object> serializer; protected final @NotNull ConfigDataFunction<V, Object> serializer;
public ConfiguredValue(@Nullable ConfigurationProvider<?> provider, public ConfiguredValue(@Nullable ConfigurationProvider<?> provider, @Nullable String sectionPath,
@Nullable String sectionPath, @Nullable ConfigCommentInfo comments, @Nullable List<String> headerComments, @Nullable String inlineComments,
@NotNull Class<V> valueClass, @Nullable V defaultValue, @NotNull Class<V> valueClass, @Nullable V defaultValue,
@NotNull ConfigValueParser<Object, V> parser, @NotNull ConfigValueParser<Object, V> parser,
@NotNull ConfigDataFunction<V, Object> serializer) { @NotNull ConfigDataFunction<V, Object> serializer) {
super(provider, sectionPath, comments, defaultValue); super(provider, sectionPath, headerComments, inlineComments, defaultValue);
this.valueClass = valueClass; this.valueClass = valueClass;
this.parser = parser; this.parser = parser;
this.serializer = serializer; this.serializer = serializer;

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>2.3.0</version> <version>3.0.0</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>

View File

@ -1,7 +1,6 @@
package cc.carm.lib.configuration.json; package cc.carm.lib.configuration.json;
import cc.carm.lib.configuration.core.ConfigInitializer; 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.ConfigurationProvider;
import cc.carm.lib.configuration.core.source.impl.FileConfigProvider; import cc.carm.lib.configuration.core.source.impl.FileConfigProvider;
import com.google.gson.Gson; import com.google.gson.Gson;
@ -9,10 +8,12 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonSerializer; import com.google.gson.JsonSerializer;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List;
/** /**
* Some code comes from BungeeCord's implementation of the JsonConfiguration. * Some code comes from BungeeCord's implementation of the JsonConfiguration.
@ -69,15 +70,24 @@ public class JSONConfigProvider extends FileConfigProvider<JSONConfigWrapper> {
} }
@Override @Override
public void setComment(@Nullable String path, @Nullable ConfigCommentInfo comment) { public void setHeaderComment(@Nullable String path, @Nullable List<String> comments) {
// JSON doesn't support comments; // JSON doesn't support comments;
} }
@Override @Override
public @Nullable ConfigCommentInfo getComment(@Nullable String path) { public void setInlineComment(@NotNull String path, @Nullable String comment) {
// JSON doesn't support comments;
}
@Override
public @Nullable @Unmodifiable List<String> getHeaderComment(@Nullable String path) {
return null; return null;
} }
@Override
public @Nullable String getInlineComment(@NotNull String path) {
return null;
}
@Override @Override
public @NotNull ConfigInitializer<? extends ConfigurationProvider<JSONConfigWrapper>> getInitializer() { public @NotNull ConfigInitializer<? extends ConfigurationProvider<JSONConfigWrapper>> getInitializer() {

View File

@ -1,4 +0,0 @@
package cc.carm.lib.configuration.json;
public abstract class JSONValue {
}

View File

@ -1,12 +1,12 @@
package config.source; package config.source;
import cc.carm.lib.configuration.core.ConfigurationRoot; import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigComment; import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.annotation.ConfigPath; import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.value.ConfigValue; import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue; import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
@ConfigComment({"数据库配置", " 用于提供数据库连接,进行数据库操作。"}) @HeaderComment({"数据库配置", " 用于提供数据库连接,进行数据库操作。"})
public class DatabaseConfiguration extends ConfigurationRoot { public class DatabaseConfiguration extends ConfigurationRoot {
@ConfigPath("driver") @ConfigPath("driver")

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>2.3.0</version> <version>3.0.0</version>
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@ -29,7 +29,7 @@
<dependency> <dependency>
<groupId>org.bspfsystems</groupId> <groupId>org.bspfsystems</groupId>
<artifactId>yamlconfiguration</artifactId> <artifactId>yamlconfiguration</artifactId>
<version>1.0.11</version> <version>1.1.0</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>

View File

@ -30,5 +30,4 @@ public class EasyConfiguration {
return from(new File(fileName), source); return from(new File(fileName), source);
} }
} }

View File

@ -1,17 +1,15 @@
package cc.carm.lib.configuration.yaml; package cc.carm.lib.configuration.yaml;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
import org.bspfsystems.yamlconfiguration.configuration.ConfigurationSection; import org.bspfsystems.yamlconfiguration.configuration.ConfigurationSection;
import org.bspfsystems.yamlconfiguration.file.FileConfiguration; import org.bspfsystems.yamlconfiguration.file.FileConfiguration;
import org.bspfsystems.yamlconfiguration.file.YamlConfiguration; import org.bspfsystems.yamlconfiguration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.*;
import java.util.Map;
import java.util.StringJoiner;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -19,38 +17,55 @@ import static cc.carm.lib.configuration.yaml.YAMLConfigProvider.SEPARATOR;
public class YAMLComments { public class YAMLComments {
Map<String, ConfigCommentInfo> comments = new HashMap<>(); protected final @NotNull Map<String, List<String>> headerComments = new HashMap<>();
protected final @NotNull Map<String, String> inlineComments = new HashMap<>();
protected Map<String, ConfigCommentInfo> getComments() { protected @NotNull Map<String, List<String>> getHeaderComments() {
return comments; return headerComments;
} }
public void set(@Nullable String path, @Nullable ConfigCommentInfo comments) { protected @NotNull Map<String, String> getInlineComments() {
return inlineComments;
}
public void setHeaderComments(@Nullable String path, @Nullable List<String> comments) {
if (comments == null) { if (comments == null) {
getComments().remove(path); getHeaderComments().remove(path);
} else { } else {
getComments().put(path, comments); getHeaderComments().put(path, comments);
} }
} }
public @NotNull ConfigCommentInfo get(@Nullable String path) {
return getComments().getOrDefault(path, ConfigCommentInfo.defaults()); public void setInlineComment(@NotNull String path, @Nullable String comment) {
if (comment == null) {
getInlineComments().remove(path);
} else {
getInlineComments().put(path, comment);
}
} }
public @Nullable String buildComments(@NotNull String indents, @Nullable String path) { @Nullable
ConfigCommentInfo comments = get(path); @Unmodifiable
if (!String.join("", comments.getComments()).isEmpty()) { public List<String> getHeaderComment(@Nullable String path) {
String prefix = comments.startWrap() ? "\n" : ""; return Optional.ofNullable(getHeaderComments().get(path)).map(Collections::unmodifiableList).orElse(null);
String suffix = comments.endWrap() ? "\n" : ""; }
StringJoiner joiner = new StringJoiner("\n", prefix, suffix);
for (String comment : comments.getComments()) { public @Nullable String getInlineComment(@NotNull String path) {
return getInlineComments().get(path);
}
public @Nullable String buildHeaderComments(@Nullable String path, @NotNull String indents) {
List<String> comments = getHeaderComment(path);
if (comments == null || comments.size() == 0) return null;
StringJoiner joiner = new StringJoiner("\n");
for (String comment : comments) {
if (comment.length() == 0) joiner.add(" "); if (comment.length() == 0) joiner.add(" ");
else joiner.add(indents + "# " + comment); else joiner.add(indents + "# " + comment);
} }
return joiner + "\n"; return joiner + "\n";
} else {
return comments.startWrap() || comments.endWrap() ? "\n" : null;
}
} }
/** /**
@ -64,37 +79,56 @@ public class YAMLComments {
public void writeComments(@NotNull YamlConfiguration source, @NotNull BufferedWriter writer) throws IOException { public void writeComments(@NotNull YamlConfiguration source, @NotNull BufferedWriter writer) throws IOException {
FileConfiguration temp = new YamlConfiguration(); // 该对象用于临时记录配置内容 FileConfiguration temp = new YamlConfiguration(); // 该对象用于临时记录配置内容
for (String fullKey : source.getKeys(true)) { String configHeader = buildHeaderComments(null, "");
String indents = getIndents(fullKey); if (configHeader != null) writer.write(configHeader);
String comment = buildComments(indents, fullKey);
if (comment != null) writer.write(comment);
for (String fullKey : source.getKeys(true)) {
Object currentValue = source.get(fullKey); Object currentValue = source.get(fullKey);
String indents = getIndents(fullKey);
String headerComments = buildHeaderComments(fullKey, indents);
String inlineComment = getInlineComment(fullKey);
if (headerComments != null) writer.write(headerComments);
String[] splitFullKey = fullKey.split("[" + SEPARATOR + "]"); String[] splitFullKey = fullKey.split("[" + SEPARATOR + "]");
String trailingKey = splitFullKey[splitFullKey.length - 1]; String trailingKey = splitFullKey[splitFullKey.length - 1];
if (currentValue instanceof ConfigurationSection) { if (currentValue instanceof ConfigurationSection) {
ConfigurationSection section = (ConfigurationSection) currentValue;
writer.write(indents + trailingKey + ":"); writer.write(indents + trailingKey + ":");
if (!((ConfigurationSection) currentValue).getKeys(false).isEmpty()) { if (inlineComment != null && inlineComment.length() > 0) {
writer.write(" # " + inlineComment);
}
if (!section.getKeys(false).isEmpty()) {
writer.write("\n"); writer.write("\n");
} else { } else {
writer.write(" {}\n"); writer.write(" {}\n");
if (indents.length() == 0) writer.write("\n");
} }
continue; continue;
} }
temp.set(trailingKey, currentValue); temp.set(trailingKey, currentValue);
String yaml = temp.saveToString(); String yaml = temp.saveToString();
yaml = yaml.substring(0, yaml.length() - 1).replace("\n", "\n" + indents);
String toWrite = indents + yaml + "\n";
temp.set(trailingKey, null); temp.set(trailingKey, null);
writer.write(toWrite); yaml = yaml.substring(0, yaml.length() - 1);
if (inlineComment != null && inlineComment.length() > 0) {
if (yaml.contains("\n")) {
// section为多行内容需要 InlineComment 加在首行末尾
String[] splitLine = yaml.split("\n", 2);
yaml = splitLine[0] + " # " + inlineComment + "\n" + splitLine[1];
} else {
// 其他情况下就直接加载后面就好
yaml += " # " + inlineComment;
}
} }
String endComment = buildComments("", null); writer.write(indents + yaml.replace("\n", "\n" + indents) + "\n");
if (endComment != null) writer.write(endComment); if (indents.length() == 0) writer.write("\n");
}
writer.close(); writer.close();
} }

View File

@ -1,11 +1,11 @@
package cc.carm.lib.configuration.yaml; package cc.carm.lib.configuration.yaml;
import cc.carm.lib.configuration.core.ConfigInitializer; 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 cc.carm.lib.configuration.core.source.impl.FileConfigProvider;
import org.bspfsystems.yamlconfiguration.file.YamlConfiguration; import org.bspfsystems.yamlconfiguration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Unmodifiable;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
@ -13,6 +13,7 @@ import java.io.StringWriter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.List;
public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> { public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> {
@ -45,7 +46,6 @@ public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> {
public void save() throws Exception { public void save() throws Exception {
configuration.save(getFile()); configuration.save(getFile());
// tchristofferson/ConfigUpdater start // tchristofferson/ConfigUpdater start
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
this.comments.writeComments(configuration, new BufferedWriter(writer)); this.comments.writeComments(configuration, new BufferedWriter(writer));
@ -61,13 +61,25 @@ public class YAMLConfigProvider extends FileConfigProvider<YAMLSectionWrapper> {
} }
@Override @Override
public void setComment(@Nullable String path, @Nullable ConfigCommentInfo comments) { public void setHeaderComment(@Nullable String path, @Nullable List<String> comments) {
this.comments.set(path, comments); this.comments.setHeaderComments(path, comments);
} }
@Override @Override
public @Nullable ConfigCommentInfo getComment(@Nullable String path) { public void setInlineComment(@NotNull String path, @Nullable String comment) {
return this.comments.get(path); this.comments.setInlineComment(path, comment);
}
@Override
@Nullable
@Unmodifiable
public List<String> getHeaderComment(@Nullable String path) {
return this.comments.getHeaderComment(path);
}
@Override
public @Nullable String getInlineComment(@NotNull String path) {
return this.comments.getInlineComment(path);
} }
@Override @Override

View File

@ -1,22 +1,23 @@
package cc.carm.lib.configuration.yaml; 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.source.ConfigurationProvider;
import cc.carm.lib.configuration.core.value.impl.CachedConfigValue; import cc.carm.lib.configuration.core.value.impl.CachedConfigValue;
import cc.carm.lib.configuration.yaml.builder.YAMLConfigBuilder; import cc.carm.lib.configuration.yaml.builder.YAMLConfigBuilder;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
public abstract class YAMLValue<T> extends CachedConfigValue<T> { public abstract class YAMLValue<T> extends CachedConfigValue<T> {
public static @NotNull YAMLConfigBuilder builder() { public static @NotNull YAMLConfigBuilder builder() {
return new YAMLConfigBuilder(); return new YAMLConfigBuilder();
} }
public YAMLValue(@Nullable YAMLConfigProvider provider, public YAMLValue(@Nullable YAMLConfigProvider provider, @Nullable String configPath,
@Nullable String configPath, @Nullable ConfigCommentInfo comments, @Nullable List<String> headerComments, @Nullable String inlineComments,
@Nullable T defaultValue) { @Nullable T defaultValue) {
super(provider, configPath, comments, defaultValue); super(provider, configPath, headerComments, inlineComments, defaultValue);
} }
public YAMLConfigProvider getYAMLProvider() { public YAMLConfigProvider getYAMLProvider() {

View File

@ -21,7 +21,7 @@ public class SerializableBuilder<T extends ConfigurationSerializable>
@Override @Override
public @NotNull ConfiguredSerializable<T> build() { public @NotNull ConfiguredSerializable<T> build() {
return new ConfiguredSerializable<>(this.provider, this.path, buildComments(), this.valueClass, this.defaultValue); return new ConfiguredSerializable<>(this.provider, this.path, this.headerComments, this.inlineComment, this.valueClass, this.defaultValue);
} }

View File

@ -1,12 +1,12 @@
package cc.carm.lib.configuration.yaml.value; package cc.carm.lib.configuration.yaml.value;
import cc.carm.lib.configuration.core.source.ConfigCommentInfo;
import cc.carm.lib.configuration.yaml.YAMLConfigProvider; import cc.carm.lib.configuration.yaml.YAMLConfigProvider;
import cc.carm.lib.configuration.yaml.YAMLValue; import cc.carm.lib.configuration.yaml.YAMLValue;
import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable; import org.bspfsystems.yamlconfiguration.serialization.ConfigurationSerializable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Optional; import java.util.Optional;
public class ConfiguredSerializable<T extends ConfigurationSerializable> extends YAMLValue<T> { public class ConfiguredSerializable<T extends ConfigurationSerializable> extends YAMLValue<T> {
@ -22,10 +22,10 @@ public class ConfiguredSerializable<T extends ConfigurationSerializable> extends
protected final @NotNull Class<T> valueClass; protected final @NotNull Class<T> valueClass;
public ConfiguredSerializable(@Nullable YAMLConfigProvider provider, public ConfiguredSerializable(@Nullable YAMLConfigProvider provider, @Nullable String configPath,
@Nullable String configPath, @Nullable ConfigCommentInfo comments, @Nullable List<String> headerComments, @Nullable String inlineComments,
@NotNull Class<T> valueClass, @Nullable T defaultValue) { @NotNull Class<T> valueClass, @Nullable T defaultValue) {
super(provider, configPath, comments, defaultValue); super(provider, configPath, headerComments, inlineComments, defaultValue);
this.valueClass = valueClass; this.valueClass = valueClass;
} }

View File

@ -1,35 +1,29 @@
package config.source; package config.source;
import cc.carm.lib.configuration.core.ConfigurationRoot; import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigComment;
import cc.carm.lib.configuration.core.annotation.ConfigPath; import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.value.ConfigValue; import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredValue; import cc.carm.lib.configuration.core.value.type.ConfiguredValue;
@ConfigComment({"数据库配置", " 用于提供数据库连接,进行数据库操作。"}) @HeaderComment({"", "数据库配置", " 用于提供数据库连接,进行数据库操作。"})
public class DatabaseConfiguration extends ConfigurationRoot { public class DatabaseConfiguration extends ConfigurationRoot {
@ConfigPath("driver") @ConfigPath("driver")
@ConfigComment(value = { @HeaderComment({
"数据库驱动配置,请根据数据库类型设置。", "数据库驱动配置,请根据数据库类型设置。",
"- MySQL: com.mysql.cj.jdbc.Driver", "- MySQL: com.mysql.cj.jdbc.Driver",
"- MariaDB(推荐): org.mariadb.jdbc.Driver", "- MariaDB(推荐): org.mariadb.jdbc.Driver",
}, startWrap = false) })
protected static final ConfigValue<String> DRIVER_NAME = ConfiguredValue.of( protected static final ConfigValue<String> DRIVER_NAME = ConfiguredValue.of(
String.class, "com.mysql.cj.jdbc.Driver" String.class, "com.mysql.cj.jdbc.Driver"
); );
@ConfigComment(startWrap = false)
protected static final ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1"); protected static final ConfigValue<String> HOST = ConfiguredValue.of(String.class, "127.0.0.1");
@ConfigComment(startWrap = false)
protected static final ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306); protected static final ConfigValue<Integer> PORT = ConfiguredValue.of(Integer.class, 3306);
@ConfigComment(startWrap = false)
protected static final ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft"); protected static final ConfigValue<String> DATABASE = ConfiguredValue.of(String.class, "minecraft");
@ConfigComment(startWrap = false)
protected static final ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root"); protected static final ConfigValue<String> USERNAME = ConfiguredValue.of(String.class, "root");
@ConfigComment(startWrap = false)
protected static final ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password"); protected static final ConfigValue<String> PASSWORD = ConfiguredValue.of(String.class, "password");
@ConfigComment(startWrap = false)
protected static final ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false"); protected static final ConfigValue<String> EXTRA = ConfiguredValue.of(String.class, "?useSSL=false");
protected static String buildJDBC() { protected static String buildJDBC() {

View File

@ -2,8 +2,9 @@ package config.source;
import cc.carm.lib.configuration.core.ConfigInitializer; import cc.carm.lib.configuration.core.ConfigInitializer;
import cc.carm.lib.configuration.core.ConfigurationRoot; import cc.carm.lib.configuration.core.ConfigurationRoot;
import cc.carm.lib.configuration.core.annotation.ConfigComment;
import cc.carm.lib.configuration.core.annotation.ConfigPath; import cc.carm.lib.configuration.core.annotation.ConfigPath;
import cc.carm.lib.configuration.core.annotation.HeaderComment;
import cc.carm.lib.configuration.core.annotation.InlineComment;
import cc.carm.lib.configuration.core.value.ConfigValue; import cc.carm.lib.configuration.core.value.ConfigValue;
import cc.carm.lib.configuration.core.value.type.ConfiguredList; import cc.carm.lib.configuration.core.value.type.ConfiguredList;
import cc.carm.lib.configuration.core.value.type.ConfiguredMap; import cc.carm.lib.configuration.core.value.type.ConfiguredMap;
@ -17,22 +18,20 @@ import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@ConfigComment({"给根类添加的注释将显示在文件的末尾。"}) @HeaderComment({
"此处内容将显示在配置文件的最上方",
""/*添加一个空行与其他配置的注释分割*/
})
public class DemoConfiguration extends ConfigurationRoot { public class DemoConfiguration extends ConfigurationRoot {
@ConfigPath(root = true) @ConfigPath(root = true)
@ConfigComment(value = {
"有时候,需要在配置文件最上面显示点东西,",
"此时就推荐添加一个可以用到但并不重要的参数到最上面",
"并给他添加对应的注释。"
}, startWrap = false, endWrap = true)
protected static final ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 1.0D); protected static final ConfigValue<Double> VERSION = ConfiguredValue.of(Double.class, 1.0D);
// 支持通过 Class<?> 变量标注子配置一并注册 // 支持通过 Class<?> 变量标注子配置一并注册
// 注意 若对应类也有注解则优先使用类的注解 // 注意 若对应类也有注解则优先使用类的注解
@ConfigPath("impl-test") //支持通过注解修改子配置的主路径若不修改则以变量名自动生成 @ConfigPath("impl-test") //支持通过注解修改子配置的主路径若不修改则以变量名自动生成
@ConfigComment("Something...") // 支持给子路径直接打注释 @HeaderComment({"", "Something..."}) // 支持给子路径直接打注释
@InlineComment("InlineComments for class path")
public static final Class<?> IMPL = ImplConfiguration.class; public static final Class<?> IMPL = ImplConfiguration.class;
// 子配置文件 // 子配置文件
@ -40,14 +39,15 @@ public class DemoConfiguration extends ConfigurationRoot {
public static final Class<?> DB_CONFIG = DatabaseConfiguration.class; public static final Class<?> DB_CONFIG = DatabaseConfiguration.class;
@ConfigPath("user") // 通过注解规定配置文件中的路径若不进行注解则以变量名自动生成 @ConfigPath("user") // 通过注解规定配置文件中的路径若不进行注解则以变量名自动生成
@ConfigComment({"Section类型数据测试"}) // 通过注解给配置添加注释 @HeaderComment({"", "Section类型数据测试"}) // 通过注解给配置添加注释
@InlineComment("Section数据也支持InlineComment注释")
public static final ConfigValue<TestModel> MODEL_TEST = ConfiguredSection public static final ConfigValue<TestModel> MODEL_TEST = ConfiguredSection
.builder(TestModel.class) .builder(TestModel.class)
.defaults(new TestModel("Carm", UUID.randomUUID())) .defaults(new TestModel("Carm", UUID.randomUUID()))
.parseValue((section, defaultValue) -> TestModel.deserialize(section)) .parseValue((section, defaultValue) -> TestModel.deserialize(section))
.serializeValue(TestModel::serialize).build(); .serializeValue(TestModel::serialize).build();
@ConfigComment({"[ID-UUID] 对照表", "", "用于测试Map类型的解析与序列化保存"}) @HeaderComment({"", "[ID - UUID]对照表", "", "用于测试Map类型的解析与序列化保存"})
public static final ConfigValue<Map<Integer, UUID>> USERS = ConfiguredMap public static final ConfigValue<Map<Integer, UUID>> USERS = ConfiguredMap
.builder(Integer.class, UUID.class).fromString() .builder(Integer.class, UUID.class).fromString()
.parseKey(Integer::parseInt) .parseKey(Integer::parseInt)
@ -62,6 +62,7 @@ public class DemoConfiguration extends ConfigurationRoot {
public static class Sub extends ConfigurationRoot { public static class Sub extends ConfigurationRoot {
@ConfigPath(value = "uuid-value", root = true) @ConfigPath(value = "uuid-value", root = true)
@InlineComment("This is an inline comment")
public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue public static final ConfigValue<UUID> UUID_CONFIG_VALUE = ConfiguredValue
.builder(UUID.class).fromString() .builder(UUID.class).fromString()
.parseValue((data, defaultValue) -> UUID.fromString(data)) .parseValue((data, defaultValue) -> UUID.fromString(data))

View File

@ -10,7 +10,9 @@ import config.model.TestModel;
@ConfigPath(root = true) @ConfigPath(root = true)
public class ImplConfiguration extends ConfigurationRoot { public class ImplConfiguration extends ConfigurationRoot {
public static final ConfigValue<? extends AbstractModel> TEST = ConfiguredSerializable.of(TestModel.class, TestModel.random()); public static final ConfigValue<? extends AbstractModel> TEST = ConfiguredSerializable.of(
TestModel.class, TestModel.random()
);
} }

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>2.3.0</version> <version>3.0.0</version>
<modules> <modules>
<module>core</module> <module>core</module>
<module>impl/yaml</module> <module>impl/yaml</module>