[serde-*, read-write-*] Support for visiting arbitrary decorations and values
This commit is contained in:
@@ -7,8 +7,7 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
|||||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||||
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer;
|
import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
||||||
@@ -24,6 +23,8 @@ public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentE
|
|||||||
@Getter
|
@Getter
|
||||||
private final PatchworkPartAccess<CustomEntryData> customEntryDataAccess;
|
private final PatchworkPartAccess<CustomEntryData> customEntryDataAccess;
|
||||||
private final DefaultMiddlewareContainer<CommentProducer> middlewareContainer;
|
private final DefaultMiddlewareContainer<CommentProducer> middlewareContainer;
|
||||||
|
@Getter
|
||||||
|
private @Nullable PatchworkPartAccess<Boolean> writerInstalledReadWriteContextAccess;
|
||||||
|
|
||||||
public CommentExtensionImpl(ConfigContainer<?> configContainer, TweedExtensionSetupContext context) {
|
public CommentExtensionImpl(ConfigContainer<?> configContainer, TweedExtensionSetupContext context) {
|
||||||
this.configContainer = configContainer;
|
this.configContainer = configContainer;
|
||||||
@@ -47,8 +48,9 @@ public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentE
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Middleware<TweedEntryWriter<?, ?>> entryWriterMiddleware() {
|
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
||||||
return new TweedEntryWriterCommentMiddleware(this);
|
writerInstalledReadWriteContextAccess = context.registerReadWriteContextExtensionData(Boolean.class);
|
||||||
|
context.registerWriterMiddleware(new TweedEntryWriterCommentMiddleware(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,18 +1,24 @@
|
|||||||
package de.siphalor.tweed5.defaultextensions.comment.impl;
|
package de.siphalor.tweed5.defaultextensions.comment.impl;
|
||||||
|
|
||||||
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
|
||||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.DelegatingTweedDataVisitor;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
||||||
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataCommentDecoration;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
||||||
|
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.Value;
|
||||||
import org.jspecify.annotations.NonNull;
|
import org.jspecify.annotations.NonNull;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?, ?>> {
|
class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?, ?>> {
|
||||||
private final CommentExtension commentExtension;
|
private final CommentExtensionImpl commentExtension;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String id() {
|
public String id() {
|
||||||
@@ -21,122 +27,73 @@ class TweedEntryWriterCommentMiddleware implements Middleware<TweedEntryWriter<?
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) {
|
public TweedEntryWriter<?, ?> process(TweedEntryWriter<?, ?> inner) {
|
||||||
|
PatchworkPartAccess<Boolean> writerInstalledAccess = commentExtension.writerInstalledReadWriteContextAccess();
|
||||||
|
assert writerInstalledAccess != null;
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
TweedEntryWriter<Object, ConfigEntry<Object>> innerCasted = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
|
TweedEntryWriter<Object, ConfigEntry<Object>> innerCasted = (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) inner;
|
||||||
return (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) (writer, value, entry, context) -> {
|
return (TweedEntryWriter<Object, @NonNull ConfigEntry<Object>>) (writer, value, entry, context) -> {
|
||||||
if (writer instanceof CompoundDataVisitor) {
|
if (!Boolean.TRUE.equals(context.extensionsData().get(writerInstalledAccess))) {
|
||||||
// Comment is already written in front of the key by the CompoundDataWriter,
|
context.extensionsData().set(writerInstalledAccess, Boolean.TRUE);
|
||||||
// so we don't have to write it here.
|
|
||||||
// We also want to unwrap the original writer,
|
writer = new MapEntryKeyDeferringWriter(writer);
|
||||||
// so that the special comment writing is limited to compounds.
|
|
||||||
writer = ((CompoundDataVisitor) writer).delegate;
|
|
||||||
} else {
|
|
||||||
String comment = getEntryComment(entry);
|
|
||||||
if (comment != null) {
|
|
||||||
writer.visitComment(comment);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry instanceof CompoundConfigEntry) {
|
String comment = commentExtension.getFullComment(entry);
|
||||||
innerCasted.write(
|
if (comment != null) {
|
||||||
new CompoundDataVisitor(writer, ((CompoundConfigEntry<?>) entry)),
|
writer.visitDecoration(new PiercingCommentDecoration(() -> comment));
|
||||||
value,
|
|
||||||
entry,
|
|
||||||
context
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
innerCasted.write(writer, value, entry, context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
innerCasted.write(writer, value, entry, context);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
private static class MapEntryKeyDeferringWriter extends DelegatingTweedDataVisitor {
|
||||||
private class CompoundDataVisitor implements TweedDataVisitor {
|
private final Deque<TweedDataDecoration> decorationQueue = new ArrayDeque<>();
|
||||||
private final TweedDataVisitor delegate;
|
private @Nullable String mapEntryKey;
|
||||||
private final CompoundConfigEntry<?> compoundConfigEntry;
|
|
||||||
|
|
||||||
@Override
|
protected MapEntryKeyDeferringWriter(TweedDataVisitor delegate) {
|
||||||
public void visitNull() {
|
super(delegate);
|
||||||
delegate.visitNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitBoolean(boolean value) {
|
|
||||||
delegate.visitBoolean(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitByte(byte value) {
|
|
||||||
delegate.visitByte(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitShort(short value) {
|
|
||||||
delegate.visitShort(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitInt(int value) {
|
|
||||||
delegate.visitInt(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitLong(long value) {
|
|
||||||
delegate.visitLong(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitFloat(float value) {
|
|
||||||
delegate.visitFloat(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitDouble(double value) {
|
|
||||||
delegate.visitDouble(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitString(String value) {
|
|
||||||
delegate.visitString(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitListStart() {
|
|
||||||
delegate.visitListStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitListEnd() {
|
|
||||||
delegate.visitListEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitMapStart() {
|
|
||||||
delegate.visitMapStart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMapEntryKey(String key) {
|
public void visitMapEntryKey(String key) {
|
||||||
ConfigEntry<?> subEntry = compoundConfigEntry.subEntries().get(key);
|
if (mapEntryKey != null) {
|
||||||
String subEntryComment = getEntryComment(subEntry);
|
throw new IllegalStateException("Map entry key already visited");
|
||||||
if (subEntryComment != null) {
|
} else {
|
||||||
delegate.visitComment(subEntryComment);
|
mapEntryKey = key;
|
||||||
}
|
}
|
||||||
delegate.visitMapEntryKey(key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitMapEnd() {
|
public void visitDecoration(TweedDataDecoration decoration) {
|
||||||
delegate.visitMapEnd();
|
if (decoration instanceof PiercingCommentDecoration) {
|
||||||
|
super.visitDecoration(((PiercingCommentDecoration) decoration).commentDecoration());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mapEntryKey != null) {
|
||||||
|
decorationQueue.addLast(decoration);
|
||||||
|
} else {
|
||||||
|
super.visitDecoration(decoration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitComment(String comment) {
|
protected void beforeValueWrite() {
|
||||||
delegate.visitComment(comment);
|
if (mapEntryKey != null) {
|
||||||
|
super.visitMapEntryKey(mapEntryKey);
|
||||||
|
mapEntryKey = null;
|
||||||
|
TweedDataDecoration decoration;
|
||||||
|
while ((decoration = decorationQueue.pollFirst()) != null) {
|
||||||
|
super.visitDecoration(decoration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.beforeValueWrite();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable String getEntryComment(ConfigEntry<?> entry) {
|
@Value
|
||||||
return commentExtension.getFullComment(entry);
|
private static class PiercingCommentDecoration implements TweedDataDecoration {
|
||||||
|
TweedDataCommentDecoration commentDecoration;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package de.siphalor.tweed5.defaultextensions.pather.api;
|
package de.siphalor.tweed5.defaultextensions.pather.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataUnsupportedValueException;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class PathTrackingDataVisitor implements TweedDataVisitor {
|
public class PathTrackingDataVisitor implements TweedDataVisitor {
|
||||||
@@ -62,6 +65,12 @@ public class PathTrackingDataVisitor implements TweedDataVisitor {
|
|||||||
valueVisited();
|
valueVisited();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitValue(@Nullable Object value) throws TweedDataUnsupportedValueException {
|
||||||
|
TweedDataVisitor.super.visitValue(value);
|
||||||
|
valueVisited();
|
||||||
|
}
|
||||||
|
|
||||||
private void valueVisited() {
|
private void valueVisited() {
|
||||||
if (pathTracking.currentContext() == PathTracking.Context.LIST) {
|
if (pathTracking.currentContext() == PathTracking.Context.LIST) {
|
||||||
pathTracking.incrementListIndex();
|
pathTracking.incrementListIndex();
|
||||||
@@ -103,7 +112,7 @@ public class PathTrackingDataVisitor implements TweedDataVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitComment(String comment) {
|
public void visitDecoration(TweedDataDecoration decoration) {
|
||||||
delegate.visitComment(comment);
|
delegate.visitDecoration(decoration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,6 @@ import org.jspecify.annotations.Nullable;
|
|||||||
public class PatherExtensionImpl implements PatherExtension, TweedExtension, ReadWriteRelatedExtension {
|
public class PatherExtensionImpl implements PatherExtension, TweedExtension, ReadWriteRelatedExtension {
|
||||||
private static final String PATHER_ID = "pather";
|
private static final String PATHER_ID = "pather";
|
||||||
|
|
||||||
private final Middleware<TweedEntryReader<?, ?>> entryReaderMiddleware = createEntryReaderMiddleware();
|
|
||||||
private final Middleware<TweedEntryWriter<?, ?>> entryWriterMiddleware = createEntryWriterMiddleware();
|
|
||||||
|
|
||||||
private @Nullable PatchworkPartAccess<PathTracking> rwContextPathTrackingAccess;
|
private @Nullable PatchworkPartAccess<PathTracking> rwContextPathTrackingAccess;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -36,6 +33,8 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
|
|||||||
@Override
|
@Override
|
||||||
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
||||||
rwContextPathTrackingAccess = context.registerReadWriteContextExtensionData(PathTracking.class);
|
rwContextPathTrackingAccess = context.registerReadWriteContextExtensionData(PathTracking.class);
|
||||||
|
context.registerReaderMiddleware(createEntryReaderMiddleware());
|
||||||
|
context.registerWriterMiddleware(createEntryWriterMiddleware());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -144,14 +143,4 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable Middleware<TweedEntryReader<?, ?>> entryReaderMiddleware() {
|
|
||||||
return entryReaderMiddleware;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable Middleware<TweedEntryWriter<?, ?>> entryWriterMiddleware() {
|
|
||||||
return entryWriterMiddleware;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
@Override
|
@Override
|
||||||
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
||||||
readContextValidationIssuesAccess = context.registerReadWriteContextExtensionData(ValidationIssues.class);
|
readContextValidationIssuesAccess = context.registerReadWriteContextExtensionData(ValidationIssues.class);
|
||||||
|
context.registerReaderMiddleware(new EntryValidationReaderMiddleware());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -173,11 +174,6 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid
|
|||||||
return entryData;
|
return entryData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable Middleware<TweedEntryReader<?, ?>> entryReaderMiddleware() {
|
|
||||||
return new EntryValidationReaderMiddleware();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> ValidationIssues validate(ConfigEntry<T> entry, @Nullable T value) {
|
public <T> ValidationIssues validate(ConfigEntry<T> entry, @Nullable T value) {
|
||||||
PathTracking pathTracking = new PathTracking();
|
PathTracking pathTracking = new PathTracking();
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package de.siphalor.tweed5.dataapi.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
public class DelegatingTweedDataVisitor implements TweedDataVisitor {
|
||||||
|
protected final TweedDataVisitor delegate;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitNull() {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitBoolean(boolean value) {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitBoolean(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitByte(byte value) {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitByte(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitShort(short value) {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitShort(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInt(int value) {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitInt(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitLong(long value) {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitLong(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitFloat(float value) {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitFloat(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDouble(double value) {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitDouble(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitString(String value) {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitString(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEmptyList() {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitEmptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitListStart() {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitListStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitListEnd() {
|
||||||
|
delegate.visitListEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitEmptyMap() {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitEmptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapStart() {
|
||||||
|
beforeValueWrite();
|
||||||
|
delegate.visitMapStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapEntryKey(String key) {
|
||||||
|
delegate.visitMapEntryKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapEnd() {
|
||||||
|
delegate.visitMapEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitValue(@Nullable Object value) throws TweedDataUnsupportedValueException {
|
||||||
|
delegate.visitValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void beforeValueWrite() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDecoration(TweedDataDecoration decoration) {
|
||||||
|
delegate.visitDecoration(decoration);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package de.siphalor.tweed5.dataapi.api;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class TweedDataUnsupportedValueException extends Exception {
|
||||||
|
private final Object value;
|
||||||
|
|
||||||
|
public TweedDataUnsupportedValueException(Object value) {
|
||||||
|
super("Unsupported value " + value + " of type " + value.getClass().getName());
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
package de.siphalor.tweed5.dataapi.api;
|
package de.siphalor.tweed5.dataapi.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
public interface TweedDataVisitor {
|
public interface TweedDataVisitor {
|
||||||
void visitNull();
|
void visitNull();
|
||||||
void visitBoolean(boolean value);
|
void visitBoolean(boolean value);
|
||||||
@@ -11,6 +14,43 @@ public interface TweedDataVisitor {
|
|||||||
void visitDouble(double value);
|
void visitDouble(double value);
|
||||||
void visitString(String value);
|
void visitString(String value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visits an arbitrary value.
|
||||||
|
* <br />
|
||||||
|
* This method is allowed to throw a {@link TweedDataUnsupportedValueException} for any value,
|
||||||
|
* so call sites should <b>always</b> provide a fallback based on the primitive visitor methods.
|
||||||
|
* @param value the value to visit. May be {@code null}.
|
||||||
|
* @throws TweedDataUnsupportedValueException if the value is not supported by this visitor.
|
||||||
|
* The visitor should then proceed to write the value with the primitive visitor methods.
|
||||||
|
* @apiNote Please use the specific visitor methods if possible.
|
||||||
|
* This method is mainly provided for extensibility beyond the standard data types.
|
||||||
|
* This could, for example, be used to allow native support for {@link java.math.BigDecimal}
|
||||||
|
* or {@link java.util.UUID} values.
|
||||||
|
*/
|
||||||
|
default void visitValue(@Nullable Object value) throws TweedDataUnsupportedValueException {
|
||||||
|
if (value == null) {
|
||||||
|
visitNull();
|
||||||
|
} else if (value instanceof Boolean) {
|
||||||
|
visitBoolean((Boolean) value);
|
||||||
|
} else if (value instanceof Byte) {
|
||||||
|
visitByte((Byte) value);
|
||||||
|
} else if (value instanceof Short) {
|
||||||
|
visitShort((Short) value);
|
||||||
|
} else if (value instanceof Integer) {
|
||||||
|
visitInt((Integer) value);
|
||||||
|
} else if (value instanceof Long) {
|
||||||
|
visitLong((Long) value);
|
||||||
|
} else if (value instanceof Float) {
|
||||||
|
visitFloat((Float) value);
|
||||||
|
} else if (value instanceof Double) {
|
||||||
|
visitDouble((Double) value);
|
||||||
|
} else if (value instanceof String) {
|
||||||
|
visitString((String) value);
|
||||||
|
} else {
|
||||||
|
throw new TweedDataUnsupportedValueException(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
default void visitEmptyList() {
|
default void visitEmptyList() {
|
||||||
visitListStart();
|
visitListStart();
|
||||||
visitListEnd();
|
visitListEnd();
|
||||||
@@ -26,5 +66,8 @@ public interface TweedDataVisitor {
|
|||||||
void visitMapEntryKey(String key);
|
void visitMapEntryKey(String key);
|
||||||
void visitMapEnd();
|
void visitMapEnd();
|
||||||
|
|
||||||
void visitComment(String comment);
|
/**
|
||||||
|
* Visits a decoration. The implementation <b>may</b> choose to ignore the decoration.
|
||||||
|
*/
|
||||||
|
void visitDecoration(TweedDataDecoration decoration);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package de.siphalor.tweed5.dataapi.api.decoration;
|
||||||
|
|
||||||
|
public interface TweedDataCommentDecoration extends TweedDataDecoration {
|
||||||
|
String comment();
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package de.siphalor.tweed5.dataapi.api.decoration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker interface for "decorative" information during (de)serialization.
|
||||||
|
*/
|
||||||
|
public interface TweedDataDecoration {
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@NullMarked
|
||||||
|
package de.siphalor.tweed5.dataapi.api.decoration;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -7,5 +7,6 @@ import org.jspecify.annotations.Nullable;
|
|||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface TweedEntryWriter<T extends @Nullable Object, C extends ConfigEntry<T>> {
|
public interface TweedEntryWriter<T extends @Nullable Object, C extends ConfigEntry<T>> {
|
||||||
void write(TweedDataVisitor writer, @Nullable T value, C entry, TweedWriteContext context) throws TweedEntryWriteException, TweedDataWriteException;
|
void write(TweedDataVisitor writer, @Nullable T value, C entry, TweedWriteContext context)
|
||||||
|
throws TweedEntryWriteException, TweedDataWriteException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
package de.siphalor.tweed5.data.extension.api.extension;
|
package de.siphalor.tweed5.data.extension.api.extension;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
|
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
||||||
|
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
||||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||||
|
|
||||||
public interface ReadWriteExtensionSetupContext {
|
public interface ReadWriteExtensionSetupContext {
|
||||||
<E> PatchworkPartAccess<E> registerReadWriteContextExtensionData(Class<E> extensionDataClass);
|
<E> PatchworkPartAccess<E> registerReadWriteContextExtensionData(Class<E> extensionDataClass);
|
||||||
|
void registerReaderMiddleware(Middleware<TweedEntryReader<?, ?>> middleware);
|
||||||
|
void registerWriterMiddleware(Middleware<TweedEntryWriter<?, ?>> middleware);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,6 @@
|
|||||||
package de.siphalor.tweed5.data.extension.api.extension;
|
package de.siphalor.tweed5.data.extension.api.extension;
|
||||||
|
|
||||||
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryReader;
|
|
||||||
import de.siphalor.tweed5.data.extension.api.TweedEntryWriter;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
|
||||||
|
|
||||||
public interface ReadWriteRelatedExtension {
|
public interface ReadWriteRelatedExtension {
|
||||||
default void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
default void setupReadWriteExtension(ReadWriteExtensionSetupContext context) {
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
default Middleware<TweedEntryReader<?, ?>> entryReaderMiddleware() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
default Middleware<TweedEntryWriter<?, ?>> entryWriterMiddleware() {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
|||||||
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||||
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer;
|
import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer;
|
||||||
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
import de.siphalor.tweed5.data.extension.api.*;
|
import de.siphalor.tweed5.data.extension.api.*;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext;
|
||||||
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension;
|
||||||
@@ -16,7 +17,6 @@ import de.siphalor.tweed5.patchwork.api.Patchwork;
|
|||||||
import de.siphalor.tweed5.patchwork.api.PatchworkFactory;
|
import de.siphalor.tweed5.patchwork.api.PatchworkFactory;
|
||||||
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.val;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -48,25 +48,29 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension {
|
|||||||
Collection<TweedExtension> extensions = configContainer.extensions();
|
Collection<TweedExtension> extensions = configContainer.extensions();
|
||||||
|
|
||||||
PatchworkFactory.Builder readWriteContextPatchworkFactorBuilder = PatchworkFactory.builder();
|
PatchworkFactory.Builder readWriteContextPatchworkFactorBuilder = PatchworkFactory.builder();
|
||||||
ReadWriteExtensionSetupContext setupContext = readWriteContextPatchworkFactorBuilder::registerPart;
|
|
||||||
|
|
||||||
entryReaderMiddlewareContainer = new DefaultMiddlewareContainer<>();
|
entryReaderMiddlewareContainer = new DefaultMiddlewareContainer<>();
|
||||||
entryWriterMiddlewareContainer = new DefaultMiddlewareContainer<>();
|
entryWriterMiddlewareContainer = new DefaultMiddlewareContainer<>();
|
||||||
|
|
||||||
|
ReadWriteExtensionSetupContext setupContext = new ReadWriteExtensionSetupContext() {
|
||||||
|
@Override
|
||||||
|
public <E> PatchworkPartAccess<E> registerReadWriteContextExtensionData(Class<E> extensionDataClass) {
|
||||||
|
return readWriteContextPatchworkFactorBuilder.registerPart(extensionDataClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerReaderMiddleware(Middleware<TweedEntryReader<?, ?>> middleware) {
|
||||||
|
entryReaderMiddlewareContainer.register(middleware);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerWriterMiddleware(Middleware<TweedEntryWriter<?, ?>> middleware) {
|
||||||
|
entryWriterMiddlewareContainer.register(middleware);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for (TweedExtension extension : extensions) {
|
for (TweedExtension extension : extensions) {
|
||||||
if (extension instanceof ReadWriteRelatedExtension) {
|
if (extension instanceof ReadWriteRelatedExtension) {
|
||||||
ReadWriteRelatedExtension rwExtension = (ReadWriteRelatedExtension) extension;
|
((ReadWriteRelatedExtension) extension).setupReadWriteExtension(setupContext);
|
||||||
|
|
||||||
rwExtension.setupReadWriteExtension(setupContext);
|
|
||||||
|
|
||||||
val readerMiddleware = rwExtension.entryReaderMiddleware();
|
|
||||||
if (readerMiddleware != null) {
|
|
||||||
entryReaderMiddlewareContainer.register(readerMiddleware);
|
|
||||||
}
|
|
||||||
val writerMiddleware = rwExtension.entryWriterMiddleware();
|
|
||||||
if (writerMiddleware != null) {
|
|
||||||
entryWriterMiddlewareContainer.register(writerMiddleware);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package de.siphalor.tweed5.data.hjson;
|
|||||||
|
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataWriteException;
|
import de.siphalor.tweed5.dataapi.api.TweedDataWriteException;
|
||||||
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataCommentDecoration;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -237,7 +239,13 @@ public class HjsonWriter implements TweedDataVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitComment(String comment) {
|
public void visitDecoration(TweedDataDecoration decoration) {
|
||||||
|
if (decoration instanceof TweedDataCommentDecoration) {
|
||||||
|
visitComment(((TweedDataCommentDecoration) decoration).comment());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visitComment(String comment) {
|
||||||
Matcher lineFeedMatcher = LINE_FEED_PATTERN.matcher(comment);
|
Matcher lineFeedMatcher = LINE_FEED_PATTERN.matcher(comment);
|
||||||
if (lineFeedMatcher.find()) {
|
if (lineFeedMatcher.find()) {
|
||||||
// Multiline
|
// Multiline
|
||||||
|
|||||||
Reference in New Issue
Block a user