diff --git a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java index 21ec7cc..52ad20a 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSection.java @@ -19,7 +19,7 @@ import java.util.stream.Stream; * @since 4.0.0 */ public interface ConfigureSection extends Cloneable { - + /** * Gets the parent section of this section. *

@@ -136,7 +136,9 @@ public interface ConfigureSection extends Cloneable { * @param path The path to check. * @return True if the value is present, false otherwise. */ - boolean contains(@NotNull String path); + default boolean contains(@NotNull String path) { + return get(path) != null; + } /** * Predicate the value of given path is specific type. @@ -166,7 +168,10 @@ public interface ConfigureSection extends Cloneable { * @param path The path to get the {@link List}. * @return The list if the path exists and is a list, otherwise null. */ - @Nullable List getList(@NotNull String path); + default @Nullable List getList(@NotNull String path) { + Object val = get(path); + return (val instanceof List) ? (List) val : null; + } /** * Predicate the value of given path is a {@link ConfigureSection}. diff --git a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSource.java b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSource.java index a5e0363..dde17cf 100644 --- a/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSource.java +++ b/core/src/main/java/cc/carm/lib/configuration/source/section/ConfigureSource.java @@ -7,7 +7,6 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; import java.util.Map; /** @@ -104,21 +103,11 @@ public abstract class ConfigureSource< section().set(path, value); } - @Override - public boolean contains(@NotNull String path) { - return section().contains(path); - } - @Override public void remove(@NotNull String path) { section().remove(path); } - @Override - public @Nullable List getList(@NotNull String path) { - return section().getList(path); - } - @Override public @Nullable ConfigureSection getSection(@NotNull String path) { return section().getSection(path); diff --git a/features/section/src/main/java/cc/carm/lib/configuration/source/section/MapSection.java b/features/section/src/main/java/cc/carm/lib/configuration/source/section/MapSection.java index 9a11614..347e6db 100644 --- a/features/section/src/main/java/cc/carm/lib/configuration/source/section/MapSection.java +++ b/features/section/src/main/java/cc/carm/lib/configuration/source/section/MapSection.java @@ -8,6 +8,14 @@ import java.util.*; public abstract class MapSection> implements ConfigureSection { + public static RawMapSection of() { + return new RawMapSection(new LinkedHashMap<>(), null); + } + + public static RawMapSection of(@NotNull Map data) { + return new RawMapSection(data, null); + } + protected final @NotNull Map data; protected final @Nullable R parent; @@ -50,11 +58,11 @@ public abstract class MapSection> implements ConfigureSe } @UnmodifiableView - public @NotNull Map original() { + public @NotNull Map rawMap() { Map output = new LinkedHashMap<>(); for (Map.Entry entry : this.data.entrySet()) { if (entry.getValue() instanceof MapSection) { - output.put(entry.getKey(), ((MapSection) entry.getValue()).original()); + output.put(entry.getKey(), ((MapSection) entry.getValue()).rawMap()); } else { output.put(entry.getKey(), entry.getValue()); } @@ -104,23 +112,12 @@ public abstract class MapSection> implements ConfigureSe } } - @Override - public boolean contains(@NotNull String path) { - return get(path) != null; - } - @Override public @Nullable Object get(@NotNull String path) { R section = getSectionFor(path); return section == this ? data.get(path) : section.get(childPath(path)); } - @Override - public @Nullable List getList(@NotNull String path) { - Object val = get(path); - return (val instanceof List) ? (List) val : null; - } - @Override public @Nullable ConfigureSection getSection(@NotNull String path) { Object val = get(path); @@ -160,4 +157,5 @@ public abstract class MapSection> implements ConfigureSe } return output; } + } diff --git a/features/section/src/main/java/cc/carm/lib/configuration/source/section/RawMapSection.java b/features/section/src/main/java/cc/carm/lib/configuration/source/section/RawMapSection.java new file mode 100644 index 0000000..f23d5e6 --- /dev/null +++ b/features/section/src/main/java/cc/carm/lib/configuration/source/section/RawMapSection.java @@ -0,0 +1,25 @@ +package cc.carm.lib.configuration.source.section; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +public class RawMapSection extends MapSection { + + protected RawMapSection(@NotNull Map raw, @Nullable RawMapSection parent) { + super(parent); + migrate(raw); + } + + @Override + public @NotNull RawMapSection self() { + return this; + } + + @Override + protected @NotNull RawMapSection createChild(@NotNull Map data) { + return new RawMapSection(data, this); + } + +} diff --git a/features/section/src/main/java/cc/carm/lib/configuration/source/section/ShadedSection.java b/features/section/src/main/java/cc/carm/lib/configuration/source/section/ShadedSection.java new file mode 100644 index 0000000..1bae9a4 --- /dev/null +++ b/features/section/src/main/java/cc/carm/lib/configuration/source/section/ShadedSection.java @@ -0,0 +1,161 @@ +package cc.carm.lib.configuration.source.section; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ShadedSection extends MapSection { + private final ConfigureSection template; + + // 构造方法 + public ShadedSection(@Nullable ShadedSection parent, @Nullable ConfigureSection template) { + super(parent); + this.template = template; + } + + public ShadedSection(@NotNull Map data, @Nullable ShadedSection parent, @Nullable ConfigureSection template) { + super(parent); + this.template = template; + migrate(data); + } + + @Override + public @NotNull ShadedSection self() { + return this; + } + + @Override + protected @NotNull ShadedSection createChild(@NotNull Map data) { + return new ShadedSection(data, this, null); + } + + @Override + public @Nullable Object get(@NotNull String path) { + // 优先从当前section获取 + Object value = super.get(path); + if (value != null) { + return wrapNestedValues(path, value); + } + + // 当前section无数据时从模板获取 + if (template != null) { + Object templateValue = template.get(path); + return wrapTemplateNestedValues(path, templateValue); + } + + return null; + } + + private Object wrapNestedValues(String path, Object value) { + if (value instanceof ConfigureSection) { + // 包装子Section,继承当前模板的对应子Section + ConfigureSection templateChild = template != null ? template.getSection(path) : null; + return new ShadedSection( + ((ConfigureSection) value).getValues(false), + this, + templateChild + ); + } else if (value instanceof List) { + // 处理列表中的嵌套结构 + return processList(path, (List) value); + } + return value; + } + + private Object wrapTemplateNestedValues(String path, Object templateValue) { + if (templateValue instanceof ConfigureSection) { + // 模板子Section作为新Section的模板 + return new ShadedSection( + ((ConfigureSection) templateValue).getValues(false), + this, + ((ConfigureSection) templateValue) // 模板继承 + ); + } else if (templateValue instanceof List) { + // 处理模板列表中的嵌套结构 + return processTemplateList(path, (List) templateValue); + } + return templateValue; + } + + private List processList(String path, List list) { + List processed = new ArrayList<>(); + for (Object item : list) { + if (item instanceof Map) { + processed.add(new ShadedSection( + (Map) item, this, + template != null ? template.getSection(path) : null + )); + } else if (item instanceof ConfigureSection) { + processed.add(new ShadedSection( + ((ConfigureSection) item).getValues(false), this, + template != null ? template.getSection(path) : null + )); + } else { + processed.add(item); + } + } + return processed; + } + + private List processTemplateList(String path, List list) { + List processed = new ArrayList<>(); + for (Object item : list) { + if (item instanceof ConfigureSection) { + processed.add(new ShadedSection( + ((ConfigureSection) item).getValues(false), this, + (ConfigureSection) item + )); + } else { + processed.add(item); + } + } + return processed; + } + + @Override + public void set(@NotNull String path, @Nullable Object value) { + // 获取模板值并深度比较 + Object templateValue = template != null ? template.get(path) : null; + Object processedValue = preprocessValue(path, value); + + if (isDeepEqual(processedValue, templateValue)) { + return; // 与模板一致则跳过 + } + + super.set(path, processedValue); + } + + private Object preprocessValue(String path, Object value) { + if (value instanceof Map) { + return new ShadedSection( + (Map) value, this, + template != null ? template.getSection(path) : null + ); + } else if (value instanceof List) { + return processList(path, (List) value); + } + return value; + } + + private boolean isDeepEqual(Object a, Object b) { + if (a == b) return true; + if (a == null || b == null) return false; + + if (a instanceof ConfigureSection && b instanceof ConfigureSection) { + return ((ConfigureSection) a).getValues(true) + .equals(((ConfigureSection) b).getValues(true)); + } else if (a instanceof List && b instanceof List) { + List listA = (List) a; + List listB = (List) b; + if (listA.size() != listB.size()) return false; + for (int i = 0; i < listA.size(); i++) { + if (!isDeepEqual(listA.get(i), listB.get(i))) return false; + } + return true; + } + return a.equals(b); + } +} \ No newline at end of file