mirror of
https://github.com/CarmJos/EasyConfiguration.git
synced 2026-06-04 18:48:20 +08:00
feat(section): Implement more sections
This commit is contained in:
@@ -19,7 +19,7 @@ import java.util.stream.Stream;
|
|||||||
* @since 4.0.0
|
* @since 4.0.0
|
||||||
*/
|
*/
|
||||||
public interface ConfigureSection extends Cloneable {
|
public interface ConfigureSection extends Cloneable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the parent section of this section.
|
* Gets the parent section of this section.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -136,7 +136,9 @@ public interface ConfigureSection extends Cloneable {
|
|||||||
* @param path The path to check.
|
* @param path The path to check.
|
||||||
* @return True if the value is present, false otherwise.
|
* @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.
|
* 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}.
|
* @param path The path to get the {@link List}.
|
||||||
* @return The list if the path exists and is a list, otherwise null.
|
* @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}.
|
* Predicate the value of given path is a {@link ConfigureSection}.
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ 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 java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,21 +103,11 @@ public abstract class ConfigureSource<
|
|||||||
section().set(path, value);
|
section().set(path, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean contains(@NotNull String path) {
|
|
||||||
return section().contains(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(@NotNull String path) {
|
public void remove(@NotNull String path) {
|
||||||
section().remove(path);
|
section().remove(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable List<?> getList(@NotNull String path) {
|
|
||||||
return section().getList(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
||||||
return section().getSection(path);
|
return section().getSection(path);
|
||||||
|
|||||||
+11
-13
@@ -8,6 +8,14 @@ import java.util.*;
|
|||||||
|
|
||||||
public abstract class MapSection<R extends MapSection<R>> implements ConfigureSection {
|
public abstract class MapSection<R extends MapSection<R>> 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<String, Object> data;
|
protected final @NotNull Map<String, Object> data;
|
||||||
protected final @Nullable R parent;
|
protected final @Nullable R parent;
|
||||||
|
|
||||||
@@ -50,11 +58,11 @@ public abstract class MapSection<R extends MapSection<R>> implements ConfigureSe
|
|||||||
}
|
}
|
||||||
|
|
||||||
@UnmodifiableView
|
@UnmodifiableView
|
||||||
public @NotNull Map<String, Object> original() {
|
public @NotNull Map<String, Object> rawMap() {
|
||||||
Map<String, Object> output = new LinkedHashMap<>();
|
Map<String, Object> output = new LinkedHashMap<>();
|
||||||
for (Map.Entry<String, Object> entry : this.data.entrySet()) {
|
for (Map.Entry<String, Object> entry : this.data.entrySet()) {
|
||||||
if (entry.getValue() instanceof MapSection<?>) {
|
if (entry.getValue() instanceof MapSection<?>) {
|
||||||
output.put(entry.getKey(), ((MapSection<?>) entry.getValue()).original());
|
output.put(entry.getKey(), ((MapSection<?>) entry.getValue()).rawMap());
|
||||||
} else {
|
} else {
|
||||||
output.put(entry.getKey(), entry.getValue());
|
output.put(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
@@ -104,23 +112,12 @@ public abstract class MapSection<R extends MapSection<R>> implements ConfigureSe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean contains(@NotNull String path) {
|
|
||||||
return get(path) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Object get(@NotNull String path) {
|
public @Nullable Object get(@NotNull String path) {
|
||||||
R section = getSectionFor(path);
|
R section = getSectionFor(path);
|
||||||
return section == this ? data.get(path) : section.get(childPath(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
|
@Override
|
||||||
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
public @Nullable ConfigureSection getSection(@NotNull String path) {
|
||||||
Object val = get(path);
|
Object val = get(path);
|
||||||
@@ -160,4 +157,5 @@ public abstract class MapSection<R extends MapSection<R>> implements ConfigureSe
|
|||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+25
@@ -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<RawMapSection> {
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+161
@@ -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<ShadedSection> {
|
||||||
|
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<Object> processList(String path, List<?> list) {
|
||||||
|
List<Object> 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<Object> processTemplateList(String path, List<?> list) {
|
||||||
|
List<Object> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user