refactor!(core): Simplify ConfigEntryValueVisitor by introducing SubEntryKey instead of passing values separately
This commit is contained in:
@@ -9,5 +9,5 @@ public interface AddressableStructuredConfigEntry<T> extends StructuredConfigEnt
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object get(T value, String key);
|
Object get(T value, String dataKey);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ public interface CollectionConfigEntry<E, T extends Collection<E>> extends Struc
|
|||||||
if (visitor.enterStructuredEntry(this, value)) {
|
if (visitor.enterStructuredEntry(this, value)) {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (E item : value) {
|
for (E item : value) {
|
||||||
String indexString = Integer.toString(index);
|
SubEntryKey subEntryKey = SubEntryKey.structured("element", Integer.toString(index));
|
||||||
if (visitor.enterAddressableStructuredSubEntry("element", indexString, null)) {
|
if (visitor.enterSubEntry(subEntryKey)) {
|
||||||
elementEntry().visitInOrder(visitor, item);
|
elementEntry().visitInOrder(visitor, item);
|
||||||
visitor.leaveAddressableStructuredSubEntry("element", indexString, null);
|
visitor.leaveSubEntry(subEntryKey);
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,11 @@ public interface ConfigEntryValueVisitor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean enterAddressableStructuredSubEntry(String entryKey, String valueKey, String dataKey) {
|
default boolean enterSubEntry(SubEntryKey subEntryKey) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean enterStructuredSubEntry(String entryKey, String valueKey) {
|
default void leaveSubEntry(SubEntryKey subEntryKey) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default void leaveAddressableStructuredSubEntry(String entryKey, String valueKey, String dataKey) {
|
|
||||||
}
|
|
||||||
|
|
||||||
default void leaveStructuredSubEntry(String entryKey, String valueKey) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default <T> void leaveStructuredEntry(StructuredConfigEntry<T> entry, T value) {
|
default <T> void leaveStructuredEntry(StructuredConfigEntry<T> entry, T value) {
|
||||||
|
|||||||
@@ -12,5 +12,5 @@ public interface MutableStructuredConfigEntry<T> extends AddressableStructuredCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NonNull T instantiateValue();
|
@NonNull T instantiateValue();
|
||||||
void set(T value, String key, Object subValue);
|
void set(T value, String dataKey, Object subValue);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package de.siphalor.tweed5.core.api.entry;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class SubEntryKey {
|
||||||
|
String entry;
|
||||||
|
@Nullable String value;
|
||||||
|
@Nullable String data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models the key of a transparent entry. Transparent entries are sub entries that only exist in the entry tree
|
||||||
|
* but are not actually present in the data.
|
||||||
|
* @param entryKey the key of the entry in the entry tree
|
||||||
|
* @apiNote The resulting key is not addressable.
|
||||||
|
*/
|
||||||
|
public static SubEntryKey transparent(String entryKey) {
|
||||||
|
return new SubEntryKey(entryKey, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models the key of a transparent entry with a data key for use with {@link AddressableStructuredConfigEntry}s.
|
||||||
|
* @param entryKey the key of the entry in the entry tree
|
||||||
|
* @param dataKey the "address" of the data in the {@link AddressableStructuredConfigEntry}
|
||||||
|
*/
|
||||||
|
public static SubEntryKey transparentAddressable(String entryKey, String dataKey) {
|
||||||
|
return new SubEntryKey(entryKey, null, dataKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A "normal" sub entry key.
|
||||||
|
* @param entryKey the key of the entry in the entry tree
|
||||||
|
* @param valueKey a potentially differing key for the user-facing data tree
|
||||||
|
*/
|
||||||
|
public static SubEntryKey structured(String entryKey, String valueKey) {
|
||||||
|
return new SubEntryKey(entryKey, valueKey, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A sub entry key for {@link AddressableStructuredConfigEntry}s.
|
||||||
|
* @param entryKey the key of the entry in the entry tree
|
||||||
|
* @param valueKey a potentially differing key for the user-facing data tree
|
||||||
|
* @param dataKey the "address" of the data in the {@link AddressableStructuredConfigEntry}
|
||||||
|
* @apiNote {@code valueKey} and {@code dataKey} are usually a 1:1 mapping.
|
||||||
|
*/
|
||||||
|
public static SubEntryKey addressable(String entryKey, String valueKey, String dataKey) {
|
||||||
|
return new SubEntryKey(entryKey, valueKey, dataKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,6 +5,7 @@ import de.siphalor.tweed5.core.api.entry.BaseConfigEntry;
|
|||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
||||||
import de.siphalor.tweed5.core.api.entry.NullableConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.NullableConfigEntry;
|
||||||
|
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -25,7 +26,7 @@ public class NullableConfigEntryImpl<T extends @Nullable Object> extends BaseCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T get(T value, String key) {
|
public T get(T value, String dataKey) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,9 +39,10 @@ public class NullableConfigEntryImpl<T extends @Nullable Object> extends BaseCon
|
|||||||
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
if (visitor.enterStructuredEntry(this, value)) {
|
if (visitor.enterStructuredEntry(this, value)) {
|
||||||
if (visitor.enterAddressableStructuredSubEntry(NON_NULL_KEY, NON_NULL_KEY, NON_NULL_KEY)) {
|
SubEntryKey subEntryKey = SubEntryKey.transparentAddressable(NON_NULL_KEY, NON_NULL_KEY);
|
||||||
|
if (visitor.enterSubEntry(subEntryKey)) {
|
||||||
nonNullEntry.visitInOrder(visitor, value);
|
nonNullEntry.visitInOrder(visitor, value);
|
||||||
visitor.leaveAddressableStructuredSubEntry(NON_NULL_KEY, NON_NULL_KEY, NON_NULL_KEY);
|
visitor.leaveSubEntry(subEntryKey);
|
||||||
}
|
}
|
||||||
visitor.leaveStructuredEntry(this, value);
|
visitor.leaveStructuredEntry(this, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,15 +29,15 @@ public class StaticMapCompoundConfigEntryImpl<T extends @NonNull Map<String, Obj
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(T compoundValue, String key, Object value) {
|
public void set(T compoundValue, String dataKey, Object value) {
|
||||||
requireKey(key);
|
requireKey(dataKey);
|
||||||
compoundValue.put(key, value);
|
compoundValue.put(dataKey, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get(T compoundValue, String key) {
|
public Object get(T compoundValue, String dataKey) {
|
||||||
requireKey(key);
|
requireKey(dataKey);
|
||||||
return compoundValue.get(key);
|
return compoundValue.get(dataKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requireKey(String key) {
|
private void requireKey(String key) {
|
||||||
@@ -55,10 +55,11 @@ public class StaticMapCompoundConfigEntryImpl<T extends @NonNull Map<String, Obj
|
|||||||
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
||||||
if (visitor.enterStructuredEntry(this, value)) {
|
if (visitor.enterStructuredEntry(this, value)) {
|
||||||
compoundEntries.forEach((key, entry) -> {
|
compoundEntries.forEach((key, entry) -> {
|
||||||
if (visitor.enterAddressableStructuredSubEntry(key, key, key)) {
|
SubEntryKey subEntryKey = SubEntryKey.addressable(key, key, key);
|
||||||
|
if (visitor.enterSubEntry(subEntryKey)) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
((ConfigEntry<Object>) entry).visitInOrder(visitor, value.get(key));
|
((ConfigEntry<Object>) entry).visitInOrder(visitor, value.get(key));
|
||||||
visitor.leaveAddressableStructuredSubEntry(key, key, key);
|
visitor.leaveSubEntry(subEntryKey);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
visitor.leaveStructuredEntry(this, value);
|
visitor.leaveStructuredEntry(this, value);
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ public interface PathTracking {
|
|||||||
|
|
||||||
void pushPathPart(String pathPart);
|
void pushPathPart(String pathPart);
|
||||||
|
|
||||||
|
void pushEmptyPathPart();
|
||||||
|
|
||||||
void popPathPart();
|
void popPathPart();
|
||||||
|
|
||||||
String currentPath();
|
String currentPath();
|
||||||
|
|
||||||
|
String[] currentPathParts();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package de.siphalor.tweed5.defaultextensions.pather.api;
|
|||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
||||||
import de.siphalor.tweed5.core.api.entry.StructuredConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.StructuredConfigEntry;
|
||||||
|
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@@ -22,32 +23,21 @@ public class PathTrackingConfigEntryValueVisitor implements ConfigEntryValueVisi
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean enterAddressableStructuredSubEntry(String entryKey, String valueKey, String dataKey) {
|
public boolean enterSubEntry(SubEntryKey subEntryKey) {
|
||||||
boolean enter = delegate.enterAddressableStructuredSubEntry(entryKey, valueKey, dataKey);
|
boolean enter = delegate.enterSubEntry(subEntryKey);
|
||||||
if (enter) {
|
if (enter) {
|
||||||
pathTracking.pushPathPart(entryKey, valueKey);
|
if (subEntryKey.value() != null) {
|
||||||
|
pathTracking.pushPathPart(subEntryKey.entry(), subEntryKey.value());
|
||||||
|
} else {
|
||||||
|
pathTracking.pushEmptyValuePathPart(subEntryKey.entry());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return enter;
|
return enter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean enterStructuredSubEntry(String entryKey, String valueKey) {
|
public void leaveSubEntry(SubEntryKey subEntryKey) {
|
||||||
boolean enter = delegate.enterStructuredSubEntry(entryKey, valueKey);
|
delegate.leaveSubEntry(subEntryKey);
|
||||||
if (enter) {
|
|
||||||
pathTracking.pushPathPart(entryKey, valueKey);
|
|
||||||
}
|
|
||||||
return enter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leaveAddressableStructuredSubEntry(String entryKey, String valueKey, String dataKey) {
|
|
||||||
delegate.leaveAddressableStructuredSubEntry(entryKey, valueKey, dataKey);
|
|
||||||
pathTracking.popPathPart();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void leaveStructuredSubEntry(String entryKey, String valueKey) {
|
|
||||||
delegate.leaveStructuredSubEntry(entryKey, valueKey);
|
|
||||||
pathTracking.popPathPart();
|
pathTracking.popPathPart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,17 @@ public final class ValuePathTracking implements PathTracking {
|
|||||||
valuePathTracking.pushPathPart(valuePathPart);
|
valuePathTracking.pushPathPart(valuePathPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pushEmptyPathPart() {
|
||||||
|
entryPathTracking.pushEmptyPathPart();
|
||||||
|
valuePathTracking.pushEmptyPathPart();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushEmptyValuePathPart(String entryPathPart) {
|
||||||
|
entryPathTracking.pushPathPart(entryPathPart);
|
||||||
|
valuePathTracking.pushEmptyPathPart();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void popPathPart() {
|
public void popPathPart() {
|
||||||
valuePathTracking.popPathPart();
|
valuePathTracking.popPathPart();
|
||||||
@@ -31,4 +42,13 @@ public final class ValuePathTracking implements PathTracking {
|
|||||||
public String currentEntryPath() {
|
public String currentEntryPath() {
|
||||||
return entryPathTracking.currentPath();
|
return entryPathTracking.currentPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] currentPathParts() {
|
||||||
|
return valuePathTracking.currentPathParts();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] currentEntryPathParts() {
|
||||||
|
return entryPathTracking.currentPathParts();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
package de.siphalor.tweed5.defaultextensions.pather.impl;
|
package de.siphalor.tweed5.defaultextensions.pather.impl;
|
||||||
|
|
||||||
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
|
||||||
public class PathTrackingImpl implements PathTracking {
|
public class PathTrackingImpl implements PathTracking {
|
||||||
private final StringBuilder pathBuilder = new StringBuilder(256);
|
private final StringBuilder pathBuilder = new StringBuilder(256);
|
||||||
private final Deque<String> pathParts = new ArrayDeque<>(50);
|
private final Deque<@Nullable String> pathParts = new ArrayDeque<>(50);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pushPathPart(String entryPathPart) {
|
public void pushPathPart(String entryPathPart) {
|
||||||
@@ -15,11 +16,18 @@ public class PathTrackingImpl implements PathTracking {
|
|||||||
pathBuilder.append(".").append(entryPathPart);
|
pathBuilder.append(".").append(entryPathPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pushEmptyPathPart() {
|
||||||
|
pathParts.push(null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void popPathPart() {
|
public void popPathPart() {
|
||||||
if (!pathParts.isEmpty()) {
|
if (!pathParts.isEmpty()) {
|
||||||
String poppedPart = pathParts.pop();
|
String poppedPart = pathParts.pop();
|
||||||
pathBuilder.setLength(pathBuilder.length() - poppedPart.length() - 1);
|
if (poppedPart != null) {
|
||||||
|
pathBuilder.setLength(pathBuilder.length() - poppedPart.length() - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,4 +35,9 @@ public class PathTrackingImpl implements PathTracking {
|
|||||||
public String currentPath() {
|
public String currentPath() {
|
||||||
return pathBuilder.toString();
|
return pathBuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] currentPathParts() {
|
||||||
|
return pathParts.toArray(new String[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
|||||||
import de.siphalor.tweed5.core.api.entry.BaseConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.BaseConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
|
||||||
|
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||||
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
|
import de.siphalor.tweed5.weaver.pojo.api.entry.WeavableCompoundConfigEntry;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -40,30 +41,30 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(T compoundValue, String key, Object value) {
|
public void set(T compoundValue, String dataKey, Object value) {
|
||||||
SubEntry subEntry = subEntries.get(key);
|
SubEntry subEntry = subEntries.get(dataKey);
|
||||||
if (subEntry == null) {
|
if (subEntry == null) {
|
||||||
throw new IllegalArgumentException("Unknown config entry: " + key);
|
throw new IllegalArgumentException("Unknown config entry: " + dataKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
subEntry.setter().invoke(compoundValue, value);
|
subEntry.setter().invoke(compoundValue, value);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new IllegalStateException("Failed to set value for config entry \"" + key + "\"", e);
|
throw new IllegalStateException("Failed to set value for config entry \"" + dataKey + "\"", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get(T compoundValue, String key) {
|
public Object get(T compoundValue, String dataKey) {
|
||||||
SubEntry subEntry = subEntries.get(key);
|
SubEntry subEntry = subEntries.get(dataKey);
|
||||||
if (subEntry == null) {
|
if (subEntry == null) {
|
||||||
throw new IllegalArgumentException("Unknown config entry: " + key);
|
throw new IllegalArgumentException("Unknown config entry: " + dataKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return subEntry.getter().invoke(compoundValue);
|
return subEntry.getter().invoke(compoundValue);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new IllegalStateException("Failed to get value for config entry \"" + key + "\"", e);
|
throw new IllegalStateException("Failed to get value for config entry \"" + dataKey + "\"", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,12 +81,13 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
|
|||||||
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
||||||
if (visitor.enterStructuredEntry(this, value)) {
|
if (visitor.enterStructuredEntry(this, value)) {
|
||||||
subEntries.forEach((key, entry) -> {
|
subEntries.forEach((key, entry) -> {
|
||||||
if (visitor.enterAddressableStructuredSubEntry(key, key, key)) {
|
SubEntryKey subEntryKey = SubEntryKey.addressable(key, key, key);
|
||||||
|
if (visitor.enterSubEntry(subEntryKey)) {
|
||||||
try {
|
try {
|
||||||
Object subValue = entry.getter().invoke(value);
|
Object subValue = entry.getter().invoke(value);
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
((ConfigEntry<Object>) entry.configEntry()).visitInOrder(visitor, subValue);
|
((ConfigEntry<Object>) entry.configEntry()).visitInOrder(visitor, subValue);
|
||||||
visitor.leaveAddressableStructuredSubEntry(key, key, key);
|
visitor.leaveSubEntry(subEntryKey);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new RuntimeException("Failed to get compound sub entry value \"" + key + "\"");
|
throw new RuntimeException("Failed to get compound sub entry value \"" + key + "\"");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user