refactor(serde-ext, default-ext): Move path tracking into serde extension

This commit is contained in:
2026-05-24 16:45:59 +02:00
parent e5b433045f
commit f22c359a1c
13 changed files with 119 additions and 144 deletions
+2
View File
@@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `core`: Fixed return type of `MutableStructuredConfigEntry#apply` to correctly be itself. - `core`: Fixed return type of `MutableStructuredConfigEntry#apply` to correctly be itself.
- `minecraft-fabric-helper`: Fixed missing new line in error log message. - `minecraft-fabric-helper`: Fixed missing new line in error log message.
- `serde-extension`, `default-extensions`: Integrate path tracking into `ReadWriteExtension`, deprecate the existing
`PatherExtension`
- `type-utls`: Fixed missing `@Nullable` annotation on `ActualType#getAnnotation`. - `type-utls`: Fixed missing `@Nullable` annotation on `ActualType#getAnnotation`.
- `weaver-pojo`: Fixed `StringMapPojoWeaver` weaving entries without `@StringMapWeaving` annotation. - `weaver-pojo`: Fixed `StringMapPojoWeaver` weaving entries without `@StringMapWeaving` annotation.
@@ -1,10 +1,11 @@
package de.siphalor.tweed5.defaultextensions.pather.api; package de.siphalor.tweed5.defaultextensions.pather.api;
import de.siphalor.tweed5.core.api.extension.TweedExtension; import de.siphalor.tweed5.core.api.extension.TweedExtension;
import de.siphalor.tweed5.defaultextensions.pather.impl.PatherExtensionImpl;
import de.siphalor.tweed5.serde.extension.api.TweedReadContext; import de.siphalor.tweed5.serde.extension.api.TweedReadContext;
import de.siphalor.tweed5.serde.extension.api.TweedWriteContext; import de.siphalor.tweed5.serde.extension.api.TweedWriteContext;
import de.siphalor.tweed5.defaultextensions.pather.impl.PatherExtensionImpl;
@Deprecated
public interface PatherExtension extends TweedExtension { public interface PatherExtension extends TweedExtension {
Class<? extends PatherExtension> DEFAULT = PatherExtensionImpl.class; Class<? extends PatherExtension> DEFAULT = PatherExtensionImpl.class;
String EXTENSION_ID = "pather"; String EXTENSION_ID = "pather";
@@ -1,124 +1,17 @@
package de.siphalor.tweed5.defaultextensions.pather.impl; package de.siphalor.tweed5.defaultextensions.pather.impl;
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.middleware.Middleware;
import de.siphalor.tweed5.serde.extension.api.*;
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteExtensionSetupContext;
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteRelatedExtension;
import de.siphalor.tweed5.serde.extension.api.extension.ReaderMiddlewareContext;
import de.siphalor.tweed5.serde.extension.api.extension.WriterMiddlewareContext;
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataReader;
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingDataVisitor;
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension; import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess; import de.siphalor.tweed5.serde.extension.api.TweedReadContext;
import lombok.val; import de.siphalor.tweed5.serde.extension.api.TweedWriteContext;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
public class PatherExtensionImpl implements PatherExtension, ReadWriteRelatedExtension {
private @Nullable PatchworkPartAccess<PathTracking> rwContextPathTrackingAccess;
@Override
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
rwContextPathTrackingAccess = context.registerReadWriteContextExtensionData(PathTracking.class);
context.registerReaderMiddleware(createEntryReaderMiddleware());
context.registerWriterMiddleware(createEntryWriterMiddleware());
}
public class PatherExtensionImpl implements PatherExtension {
@Override @Override
public String getPath(TweedReadContext context) { public String getPath(TweedReadContext context) {
assert rwContextPathTrackingAccess != null; return context.currentEntryPath().toString();
PathTracking pathTracking = context.extensionsData().get(rwContextPathTrackingAccess);
if (pathTracking == null) {
throw new IllegalStateException("Path tracking is not active!");
}
return pathTracking.currentPath();
} }
@Override @Override
public String getPath(TweedWriteContext context) { public String getPath(TweedWriteContext context) {
assert rwContextPathTrackingAccess != null; return context.currentEntryPath().toString();
PathTracking pathTracking = context.extensionsData().get(rwContextPathTrackingAccess);
if (pathTracking == null) {
throw new IllegalStateException("Path tracking is not active!");
}
return pathTracking.currentPath();
}
private Middleware<TweedEntryReader<?, ?>, ReaderMiddlewareContext> createEntryReaderMiddleware() {
return new Middleware<TweedEntryReader<?, ?>, ReaderMiddlewareContext>() {
@Override
public String id() {
return EXTENSION_ID;
}
@Override
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner, ReaderMiddlewareContext context) {
assert rwContextPathTrackingAccess != null;
//noinspection unchecked
val castedInner = (TweedEntryReader<Object, @NonNull ConfigEntry<Object>>) inner;
return (TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext readContext) -> {
PathTracking pathTracking = readContext.extensionsData().get(rwContextPathTrackingAccess);
if (pathTracking != null) {
return castedInner.read(reader, entry, readContext);
}
pathTracking = PathTracking.create();
readContext.extensionsData().set(rwContextPathTrackingAccess, pathTracking);
return castedInner.read(new PathTrackingDataReader(reader, pathTracking), entry, readContext);
};
}
};
}
private Middleware<TweedEntryWriter<?, ?>, WriterMiddlewareContext> createEntryWriterMiddleware() {
return new Middleware<TweedEntryWriter<?, ?>, WriterMiddlewareContext>() {
@Override
public String id() {
return EXTENSION_ID;
}
@Override
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner, WriterMiddlewareContext context) {
assert rwContextPathTrackingAccess != null;
//noinspection unchecked
val castedInner = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
return (TweedDataVisitor writer, Object value, ConfigEntry<Object> entry, TweedWriteContext writeContext) -> {
PathTracking pathTracking = writeContext.extensionsData().get(rwContextPathTrackingAccess);
if (pathTracking != null) {
castedInner.write(writer, value, entry, writeContext);
return;
}
pathTracking = PathTracking.create();
writeContext.extensionsData().set(rwContextPathTrackingAccess, pathTracking);
try {
castedInner.write(new PathTrackingDataVisitor(writer, pathTracking), value, entry, writeContext);
} catch (TweedEntryWriteException e) {
PathTracking exceptionPathTracking =
e.context().extensionsData().get(rwContextPathTrackingAccess);
if (exceptionPathTracking != null) {
throw new TweedEntryWriteException(
"Exception while writing entry at "
+ exceptionPathTracking.currentPath()
+ ": " + e.getMessage(),
e
);
} else {
throw e;
}
}
};
}
};
} }
} }
@@ -6,7 +6,6 @@ import de.siphalor.tweed5.core.api.middleware.Middleware;
import de.siphalor.tweed5.serde.extension.api.TweedEntryReader; import de.siphalor.tweed5.serde.extension.api.TweedEntryReader;
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteExtensionSetupContext; import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteExtensionSetupContext;
import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteRelatedExtension; import de.siphalor.tweed5.serde.extension.api.extension.ReadWriteRelatedExtension;
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension; import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension; import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension; import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
@@ -39,7 +38,7 @@ public class ReadFallbackExtensionImpl implements ReadFallbackExtension, ReadWri
@Override @Override
public Set<String> mustComeBefore() { public Set<String> mustComeBefore() {
return Collections.singleton(PatherExtension.EXTENSION_ID); return Collections.emptySet();
} }
@Override @Override
@@ -14,7 +14,6 @@ import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducerMiddlewareContext; import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducerMiddlewareContext;
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking; import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingConfigEntryValueVisitor; import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingConfigEntryValueVisitor;
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
import de.siphalor.tweed5.defaultextensions.pather.api.ValuePathTracking; import de.siphalor.tweed5.defaultextensions.pather.api.ValuePathTracking;
import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator; import de.siphalor.tweed5.defaultextensions.validation.api.ConfigEntryValidator;
import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension; import de.siphalor.tweed5.defaultextensions.validation.api.ValidationExtension;
@@ -35,7 +34,6 @@ import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadIssue;
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult; import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
import de.siphalor.tweed5.serde_api.api.TweedDataReader; import de.siphalor.tweed5.serde_api.api.TweedDataReader;
import lombok.*; import lombok.*;
import org.jetbrains.annotations.UnknownNullability;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
import java.util.*; import java.util.*;
@@ -77,12 +75,10 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
private final MiddlewareContainer<ConfigEntryValidator, ValidatorMiddlewareContext> private final MiddlewareContainer<ConfigEntryValidator, ValidatorMiddlewareContext>
entryValidatorMiddlewareContainer = new DefaultMiddlewareContainer<>(); entryValidatorMiddlewareContainer = new DefaultMiddlewareContainer<>();
private @Nullable PatchworkPartAccess<ValidationIssues> readContextValidationIssuesAccess; private @Nullable PatchworkPartAccess<ValidationIssues> readContextValidationIssuesAccess;
private @Nullable PatherExtension patherExtension;
public ValidationExtensionImpl(ConfigContainer<?> configContainer, TweedExtensionSetupContext context) { public ValidationExtensionImpl(ConfigContainer<?> configContainer, TweedExtensionSetupContext context) {
this.configContainer = configContainer; this.configContainer = configContainer;
this.customEntryDataAccess = context.registerEntryExtensionData(CustomEntryData.class); this.customEntryDataAccess = context.registerEntryExtensionData(CustomEntryData.class);
context.registerExtension(PatherExtension.class);
} }
@Override @Override
@@ -95,9 +91,6 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
} }
} }
entryValidatorMiddlewareContainer.seal(); entryValidatorMiddlewareContainer.seal();
patherExtension = configContainer.extension(PatherExtension.class)
.orElseThrow(() -> new IllegalStateException("Missing requested PatherExtension"));
} }
@Override @Override
@@ -235,14 +228,9 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
return EXTENSION_ID; return EXTENSION_ID;
} }
@Override
public Set<String> mustComeBefore() {
return Collections.singleton(PatherExtension.EXTENSION_ID);
}
@Override @Override
public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner, ReaderMiddlewareContext context) { public TweedEntryReader<?, ?> process(TweedEntryReader<?, ?> inner, ReaderMiddlewareContext context) {
assert readContextValidationIssuesAccess != null && patherExtension != null; assert readContextValidationIssuesAccess != null;
//noinspection unchecked //noinspection unchecked
TweedEntryReader<Object, ConfigEntry<Object>> castedInner = (TweedEntryReader<Object, ConfigEntry<Object>>) inner; TweedEntryReader<Object, ConfigEntry<Object>> castedInner = (TweedEntryReader<Object, ConfigEntry<Object>>) inner;
@@ -261,11 +249,10 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
return TweedReadResult.ok(validationResult.value()); return TweedReadResult.ok(validationResult.value());
} }
String path = patherExtension.getPath(readContext); validationIssues.issuesByPath().put(
validationIssues.issuesByPath().put(path, new ValidationIssues.EntryIssues( readContext.currentEntryPath().toString(),
entry, new ValidationIssues.EntryIssues(entry, validationResult.issues())
validationResult.issues() );
));
if (validationResult.hasError()) { if (validationResult.hasError()) {
return TweedReadResult.failed( return TweedReadResult.failed(
mapValidationIssuesToReadIssues(validationResult.issues(), readContext) mapValidationIssuesToReadIssues(validationResult.issues(), readContext)
@@ -6,7 +6,6 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.impl.DefaultConfigContainer; import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl; import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl; import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
import de.siphalor.tweed5.defaultextensions.pather.api.PatherExtension;
import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension; import de.siphalor.tweed5.defaultextensions.presets.api.PresetsExtension;
import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension; import de.siphalor.tweed5.defaultextensions.readfallback.api.ReadFallbackExtension;
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension; import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
@@ -77,7 +76,6 @@ class ReadFallbackExtensionImplTest {
void nestedWithPather(LogsCaptor<ReadFallbackExtensionImpl> logsCaptor) { void nestedWithPather(LogsCaptor<ReadFallbackExtensionImpl> logsCaptor) {
DefaultConfigContainer<Map<String, Object>> configContainer = new DefaultConfigContainer<>(); DefaultConfigContainer<Map<String, Object>> configContainer = new DefaultConfigContainer<>();
configContainer.registerExtension(ReadWriteExtension.class); configContainer.registerExtension(ReadWriteExtension.class);
configContainer.registerExtension(PatherExtension.class);
configContainer.registerExtension(PresetsExtension.class); configContainer.registerExtension(PresetsExtension.class);
configContainer.registerExtension(ReadFallbackExtension.DEFAULT); configContainer.registerExtension(ReadFallbackExtension.DEFAULT);
configContainer.finishExtensionSetup(); configContainer.finishExtensionSetup();
@@ -3,6 +3,7 @@ package de.siphalor.tweed5.serde.extension.api;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.entry.SubEntryKey; import de.siphalor.tweed5.core.api.entry.SubEntryKey;
import de.siphalor.tweed5.patchwork.api.Patchwork; import de.siphalor.tweed5.patchwork.api.Patchwork;
import de.siphalor.tweed5.serde.extension.api.path.EntryPath;
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult; import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
import de.siphalor.tweed5.serde_api.api.TweedDataReader; import de.siphalor.tweed5.serde_api.api.TweedDataReader;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
@@ -10,6 +11,8 @@ import org.jspecify.annotations.Nullable;
public interface TweedReadContext { public interface TweedReadContext {
ReadWriteExtension readWriteExtension(); ReadWriteExtension readWriteExtension();
Patchwork extensionsData(); Patchwork extensionsData();
EntryPath currentEntryPath();
EntryPath currentValuePath();
<T extends @Nullable Object, C extends ConfigEntry<T>> TweedReadResult<T> readSubEntry( <T extends @Nullable Object, C extends ConfigEntry<T>> TweedReadResult<T> readSubEntry(
TweedDataReader reader, C entry, SubEntryKey key TweedDataReader reader, C entry, SubEntryKey key
@@ -3,12 +3,15 @@ package de.siphalor.tweed5.serde.extension.api;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.entry.SubEntryKey; import de.siphalor.tweed5.core.api.entry.SubEntryKey;
import de.siphalor.tweed5.patchwork.api.Patchwork; import de.siphalor.tweed5.patchwork.api.Patchwork;
import de.siphalor.tweed5.serde.extension.api.path.EntryPath;
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor; import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
import de.siphalor.tweed5.serde_api.api.TweedDataWriteException; import de.siphalor.tweed5.serde_api.api.TweedDataWriteException;
import org.jspecify.annotations.Nullable; import org.jspecify.annotations.Nullable;
public interface TweedWriteContext { public interface TweedWriteContext {
Patchwork extensionsData(); Patchwork extensionsData();
EntryPath currentEntryPath();
EntryPath currentValuePath();
<T extends @Nullable Object, C extends ConfigEntry<T>> void writeSubEntry( <T extends @Nullable Object, C extends ConfigEntry<T>> void writeSubEntry(
TweedDataVisitor writer, C entry, SubEntryKey key, @Nullable T value TweedDataVisitor writer, C entry, SubEntryKey key, @Nullable T value
@@ -0,0 +1,19 @@
package de.siphalor.tweed5.serde.extension.api.path;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jspecify.annotations.Nullable;
import java.util.List;
@RequiredArgsConstructor
public class EntryPath {
@Getter
private final List<@Nullable String> parts;
private final String string;
@Override
public String toString() {
return string;
}
}
@@ -89,4 +89,9 @@ public class TweedEntryReaderWriters {
//noinspection unchecked //noinspection unchecked
return (TweedEntryReaderWriter<T, @NonNull CompoundConfigEntry<T>>) (TweedEntryReaderWriter<?, ?>) TweedEntryReaderWriterImpls.COMPOUND_READER_WRITER; return (TweedEntryReaderWriter<T, @NonNull CompoundConfigEntry<T>>) (TweedEntryReaderWriter<?, ?>) TweedEntryReaderWriterImpls.COMPOUND_READER_WRITER;
} }
public static <T extends @Nullable Object> TweedEntryReaderWriter<T, ConfigEntry<T>> noopReaderWriter() {
//noinspection unchecked
return (TweedEntryReaderWriter<T, ConfigEntry<T>>) (TweedEntryReaderWriter<?, ?>) TweedEntryReaderWriterImpls.NOOP_READER_WRITER;
}
} }
@@ -3,8 +3,10 @@ package de.siphalor.tweed5.serde.extension.impl;
import de.siphalor.tweed5.core.api.entry.ConfigEntry; import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.entry.SubEntryKey; import de.siphalor.tweed5.core.api.entry.SubEntryKey;
import de.siphalor.tweed5.serde.extension.api.*; import de.siphalor.tweed5.serde.extension.api.*;
import de.siphalor.tweed5.serde.extension.api.path.EntryPath;
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult; import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
import de.siphalor.tweed5.patchwork.api.Patchwork; import de.siphalor.tweed5.patchwork.api.Patchwork;
import de.siphalor.tweed5.serde.extension.impl.path.ReadWritePathTracking;
import de.siphalor.tweed5.serde_api.api.TweedDataReader; import de.siphalor.tweed5.serde_api.api.TweedDataReader;
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor; import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
import de.siphalor.tweed5.serde_api.api.TweedDataWriteException; import de.siphalor.tweed5.serde_api.api.TweedDataWriteException;
@@ -19,17 +21,44 @@ class TweedReadWriteContextImpl implements TweedReadContext, TweedWriteContext {
@Getter @Getter
private final Patchwork extensionsData; private final Patchwork extensionsData;
private final ReadWritePathTracking entryPathTracking = new ReadWritePathTracking();
private final ReadWritePathTracking valuePathTracking = new ReadWritePathTracking();
@Override
public EntryPath currentEntryPath() {
return new EntryPath(entryPathTracking.currentPathParts(), entryPathTracking.currentPath());
}
@Override
public EntryPath currentValuePath() {
return new EntryPath(valuePathTracking.currentPathParts(), valuePathTracking.currentPath());
}
@Override @Override
public <T extends @Nullable Object, C extends ConfigEntry<T>> TweedReadResult<T> readSubEntry( public <T extends @Nullable Object, C extends ConfigEntry<T>> TweedReadResult<T> readSubEntry(
TweedDataReader reader, C entry, SubEntryKey key TweedDataReader reader, C entry, SubEntryKey key
) { ) {
return readWriteExtension.getReaderChain(entry).read(reader, entry, this); try {
entryPathTracking.push(key.entry());
valuePathTracking.push(key.value());
return readWriteExtension.getReaderChain(entry).read(reader, entry, this);
} finally {
entryPathTracking.pop();
valuePathTracking.pop();
}
} }
@Override @Override
public <T extends @Nullable Object, C extends ConfigEntry<T>> void writeSubEntry( public <T extends @Nullable Object, C extends ConfigEntry<T>> void writeSubEntry(
TweedDataVisitor writer, C entry, SubEntryKey key, @Nullable T value TweedDataVisitor writer, C entry, SubEntryKey key, @Nullable T value
) throws TweedEntryWriteException, TweedDataWriteException { ) throws TweedEntryWriteException, TweedDataWriteException {
readWriteExtension.getWriterChain(entry).write(writer, value, entry, this); try {
entryPathTracking.push(key.entry());
valuePathTracking.push(key.value());
readWriteExtension.getWriterChain(entry).write(writer, value, entry, this);
} finally {
entryPathTracking.pop();
valuePathTracking.pop();
}
} }
} }
@@ -0,0 +1,36 @@
package de.siphalor.tweed5.serde.extension.impl.path;
import org.jspecify.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ReadWritePathTracking {
private final StringBuilder pathBuilder = new StringBuilder(256);
private final List<@Nullable String> pathParts = new ArrayList<>(50);
public void push(@Nullable String part) {
pathParts.add(part);
if (part != null) {
pathBuilder.append(".").append(part);
}
}
public void pop() {
if (!pathParts.isEmpty()) {
String poppedPart = pathParts.remove(pathParts.size() - 1);
if (poppedPart != null) {
pathBuilder.setLength(pathBuilder.length() - poppedPart.length() - 1);
}
}
}
public String currentPath() {
return pathBuilder.toString();
}
public List<@Nullable String> currentPathParts() {
return Collections.unmodifiableList(new ArrayList<>(pathParts));
}
}
@@ -3,30 +3,30 @@ package de.siphalor.tweed5.serde.extension.impl;
import de.siphalor.tweed5.core.api.container.ConfigContainer; import de.siphalor.tweed5.core.api.container.ConfigContainer;
import de.siphalor.tweed5.core.api.entry.CollectionConfigEntry; import de.siphalor.tweed5.core.api.entry.CollectionConfigEntry;
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry; import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
import de.siphalor.tweed5.core.api.entry.ConfigEntryValueVisitor;
import de.siphalor.tweed5.core.api.entry.ConfigEntryVisitor;
import de.siphalor.tweed5.core.api.entry.MutableStructuredConfigEntry; import de.siphalor.tweed5.core.api.entry.MutableStructuredConfigEntry;
import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry; import de.siphalor.tweed5.core.api.entry.SimpleConfigEntry;
import de.siphalor.tweed5.core.impl.DefaultConfigContainer; import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
import de.siphalor.tweed5.core.impl.entry.CollectionConfigEntryImpl; import de.siphalor.tweed5.core.impl.entry.CollectionConfigEntryImpl;
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl; import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl; import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
import de.siphalor.tweed5.patchwork.api.Patchwork;
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension; import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
import de.siphalor.tweed5.serde.hjson.HjsonLexer; import de.siphalor.tweed5.serde.hjson.HjsonLexer;
import de.siphalor.tweed5.serde.hjson.HjsonReader; import de.siphalor.tweed5.serde.hjson.HjsonReader;
import de.siphalor.tweed5.serde.hjson.HjsonWriter; import de.siphalor.tweed5.serde.hjson.HjsonWriter;
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor; import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
import org.jspecify.annotations.NonNull; import de.siphalor.tweed5.testutils.generic.entry.TestMapConfigEntry;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.io.StringReader; import java.io.StringReader;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.entryReaderWriter; import static de.siphalor.tweed5.serde.extension.api.ReadWriteExtension.entryReaderWriter;