From e4ea5fdfc278c0cb6b16ded64c086ece95c4b979 Mon Sep 17 00:00:00 2001 From: Siphalor Date: Mon, 21 Jul 2025 23:17:50 +0200 Subject: [PATCH] [serde-*, read-write-*] Support for visiting arbitrary decorations and values --- .../comment/impl/CommentExtensionImpl.java | 10 +- .../TweedEntryWriterCommentMiddleware.java | 149 +++++++----------- .../pather/api/PathTrackingDataVisitor.java | 13 +- .../pather/impl/PatherExtensionImpl.java | 15 +- .../impl/ValidationExtensionImpl.java | 6 +- .../api/DelegatingTweedDataVisitor.java | 118 ++++++++++++++ .../TweedDataUnsupportedValueException.java | 13 ++ .../tweed5/dataapi/api/TweedDataVisitor.java | 45 +++++- .../TweedDataCommentDecoration.java | 5 + .../api/decoration/TweedDataDecoration.java | 7 + .../dataapi/api/decoration/package-info.java | 4 + .../data/extension/api/TweedEntryWriter.java | 3 +- .../ReadWriteExtensionSetupContext.java | 5 + .../extension/ReadWriteRelatedExtension.java | 16 -- .../impl/ReadWriteExtensionImpl.java | 34 ++-- .../tweed5/data/hjson/HjsonWriter.java | 10 +- 16 files changed, 299 insertions(+), 154 deletions(-) create mode 100644 tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/DelegatingTweedDataVisitor.java create mode 100644 tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/TweedDataUnsupportedValueException.java create mode 100644 tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/TweedDataCommentDecoration.java create mode 100644 tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/TweedDataDecoration.java create mode 100644 tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/package-info.java diff --git a/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/comment/impl/CommentExtensionImpl.java b/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/comment/impl/CommentExtensionImpl.java index fd1e0be..57c5899 100644 --- a/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/comment/impl/CommentExtensionImpl.java +++ b/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/comment/impl/CommentExtensionImpl.java @@ -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.TweedExtensionSetupContext; import de.siphalor.tweed5.core.api.middleware.DefaultMiddlewareContainer; -import de.siphalor.tweed5.core.api.middleware.Middleware; -import de.siphalor.tweed5.data.extension.api.TweedEntryWriter; +import de.siphalor.tweed5.data.extension.api.extension.ReadWriteExtensionSetupContext; import de.siphalor.tweed5.data.extension.api.extension.ReadWriteRelatedExtension; import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension; import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension; @@ -24,6 +23,8 @@ public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentE @Getter private final PatchworkPartAccess customEntryDataAccess; private final DefaultMiddlewareContainer middlewareContainer; + @Getter + private @Nullable PatchworkPartAccess writerInstalledReadWriteContextAccess; public CommentExtensionImpl(ConfigContainer configContainer, TweedExtensionSetupContext context) { this.configContainer = configContainer; @@ -47,8 +48,9 @@ public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentE } @Override - public @Nullable Middleware> entryWriterMiddleware() { - return new TweedEntryWriterCommentMiddleware(this); + public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) { + writerInstalledReadWriteContextAccess = context.registerReadWriteContextExtensionData(Boolean.class); + context.registerWriterMiddleware(new TweedEntryWriterCommentMiddleware(this)); } @Override diff --git a/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/comment/impl/TweedEntryWriterCommentMiddleware.java b/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/comment/impl/TweedEntryWriterCommentMiddleware.java index afe6716..e70b3d6 100644 --- a/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/comment/impl/TweedEntryWriterCommentMiddleware.java +++ b/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/comment/impl/TweedEntryWriterCommentMiddleware.java @@ -1,18 +1,24 @@ 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.middleware.Middleware; 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.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.Value; import org.jspecify.annotations.NonNull; import org.jspecify.annotations.Nullable; +import java.util.ArrayDeque; +import java.util.Deque; + @RequiredArgsConstructor class TweedEntryWriterCommentMiddleware implements Middleware> { - private final CommentExtension commentExtension; + private final CommentExtensionImpl commentExtension; @Override public String id() { @@ -21,122 +27,73 @@ class TweedEntryWriterCommentMiddleware implements Middleware process(TweedEntryWriter inner) { + PatchworkPartAccess writerInstalledAccess = commentExtension.writerInstalledReadWriteContextAccess(); + assert writerInstalledAccess != null; + //noinspection unchecked TweedEntryWriter> innerCasted = (TweedEntryWriter>) inner; return (TweedEntryWriter>) (writer, value, entry, context) -> { - if (writer instanceof CompoundDataVisitor) { - // Comment is already written in front of the key by the CompoundDataWriter, - // so we don't have to write it here. - // We also want to unwrap the original 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 (!Boolean.TRUE.equals(context.extensionsData().get(writerInstalledAccess))) { + context.extensionsData().set(writerInstalledAccess, Boolean.TRUE); + + writer = new MapEntryKeyDeferringWriter(writer); } - if (entry instanceof CompoundConfigEntry) { - innerCasted.write( - new CompoundDataVisitor(writer, ((CompoundConfigEntry) entry)), - value, - entry, - context - ); - } else { - innerCasted.write(writer, value, entry, context); + String comment = commentExtension.getFullComment(entry); + if (comment != null) { + writer.visitDecoration(new PiercingCommentDecoration(() -> comment)); } + + innerCasted.write(writer, value, entry, context); }; } - @RequiredArgsConstructor - private class CompoundDataVisitor implements TweedDataVisitor { - private final TweedDataVisitor delegate; - private final CompoundConfigEntry compoundConfigEntry; + private static class MapEntryKeyDeferringWriter extends DelegatingTweedDataVisitor { + private final Deque decorationQueue = new ArrayDeque<>(); + private @Nullable String mapEntryKey; - @Override - public void visitNull() { - 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(); + protected MapEntryKeyDeferringWriter(TweedDataVisitor delegate) { + super(delegate); } @Override public void visitMapEntryKey(String key) { - ConfigEntry subEntry = compoundConfigEntry.subEntries().get(key); - String subEntryComment = getEntryComment(subEntry); - if (subEntryComment != null) { - delegate.visitComment(subEntryComment); + if (mapEntryKey != null) { + throw new IllegalStateException("Map entry key already visited"); + } else { + mapEntryKey = key; } - delegate.visitMapEntryKey(key); } @Override - public void visitMapEnd() { - delegate.visitMapEnd(); + public void visitDecoration(TweedDataDecoration decoration) { + if (decoration instanceof PiercingCommentDecoration) { + super.visitDecoration(((PiercingCommentDecoration) decoration).commentDecoration()); + return; + } + if (mapEntryKey != null) { + decorationQueue.addLast(decoration); + } else { + super.visitDecoration(decoration); + } } @Override - public void visitComment(String comment) { - delegate.visitComment(comment); + protected void beforeValueWrite() { + 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) { - return commentExtension.getFullComment(entry); + @Value + private static class PiercingCommentDecoration implements TweedDataDecoration { + TweedDataCommentDecoration commentDecoration; } } diff --git a/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/pather/api/PathTrackingDataVisitor.java b/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/pather/api/PathTrackingDataVisitor.java index e2f6605..934f2db 100644 --- a/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/pather/api/PathTrackingDataVisitor.java +++ b/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/pather/api/PathTrackingDataVisitor.java @@ -1,7 +1,10 @@ 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.decoration.TweedDataDecoration; import lombok.RequiredArgsConstructor; +import org.jspecify.annotations.Nullable; @RequiredArgsConstructor public class PathTrackingDataVisitor implements TweedDataVisitor { @@ -62,6 +65,12 @@ public class PathTrackingDataVisitor implements TweedDataVisitor { valueVisited(); } + @Override + public void visitValue(@Nullable Object value) throws TweedDataUnsupportedValueException { + TweedDataVisitor.super.visitValue(value); + valueVisited(); + } + private void valueVisited() { if (pathTracking.currentContext() == PathTracking.Context.LIST) { pathTracking.incrementListIndex(); @@ -103,7 +112,7 @@ public class PathTrackingDataVisitor implements TweedDataVisitor { } @Override - public void visitComment(String comment) { - delegate.visitComment(comment); + public void visitDecoration(TweedDataDecoration decoration) { + delegate.visitDecoration(decoration); } } diff --git a/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/pather/impl/PatherExtensionImpl.java b/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/pather/impl/PatherExtensionImpl.java index 40eb42e..abdac95 100644 --- a/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/pather/impl/PatherExtensionImpl.java +++ b/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/pather/impl/PatherExtensionImpl.java @@ -23,9 +23,6 @@ import org.jspecify.annotations.Nullable; public class PatherExtensionImpl implements PatherExtension, TweedExtension, ReadWriteRelatedExtension { private static final String PATHER_ID = "pather"; - private final Middleware> entryReaderMiddleware = createEntryReaderMiddleware(); - private final Middleware> entryWriterMiddleware = createEntryWriterMiddleware(); - private @Nullable PatchworkPartAccess rwContextPathTrackingAccess; @Override @@ -36,6 +33,8 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea @Override public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) { rwContextPathTrackingAccess = context.registerReadWriteContextExtensionData(PathTracking.class); + context.registerReaderMiddleware(createEntryReaderMiddleware()); + context.registerWriterMiddleware(createEntryWriterMiddleware()); } @Override @@ -144,14 +143,4 @@ public class PatherExtensionImpl implements PatherExtension, TweedExtension, Rea } }; } - - @Override - public @Nullable Middleware> entryReaderMiddleware() { - return entryReaderMiddleware; - } - - @Override - public @Nullable Middleware> entryWriterMiddleware() { - return entryWriterMiddleware; - } } diff --git a/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/validation/impl/ValidationExtensionImpl.java b/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/validation/impl/ValidationExtensionImpl.java index 8628a78..a3b61f7 100644 --- a/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/validation/impl/ValidationExtensionImpl.java +++ b/tweed5-default-extensions/src/main/java/de/siphalor/tweed5/defaultextensions/validation/impl/ValidationExtensionImpl.java @@ -134,6 +134,7 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid @Override public void setupReadWriteExtension(ReadWriteExtensionSetupContext context) { readContextValidationIssuesAccess = context.registerReadWriteContextExtensionData(ValidationIssues.class); + context.registerReaderMiddleware(new EntryValidationReaderMiddleware()); } @Override @@ -173,11 +174,6 @@ public class ValidationExtensionImpl implements ReadWriteRelatedExtension, Valid return entryData; } - @Override - public @Nullable Middleware> entryReaderMiddleware() { - return new EntryValidationReaderMiddleware(); - } - @Override public ValidationIssues validate(ConfigEntry entry, @Nullable T value) { PathTracking pathTracking = new PathTracking(); diff --git a/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/DelegatingTweedDataVisitor.java b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/DelegatingTweedDataVisitor.java new file mode 100644 index 0000000..eed38d8 --- /dev/null +++ b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/DelegatingTweedDataVisitor.java @@ -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); + } +} diff --git a/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/TweedDataUnsupportedValueException.java b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/TweedDataUnsupportedValueException.java new file mode 100644 index 0000000..7478eb9 --- /dev/null +++ b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/TweedDataUnsupportedValueException.java @@ -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; + } +} diff --git a/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/TweedDataVisitor.java b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/TweedDataVisitor.java index f59639c..c64dbf9 100644 --- a/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/TweedDataVisitor.java +++ b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/TweedDataVisitor.java @@ -1,5 +1,8 @@ package de.siphalor.tweed5.dataapi.api; +import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration; +import org.jspecify.annotations.Nullable; + public interface TweedDataVisitor { void visitNull(); void visitBoolean(boolean value); @@ -11,6 +14,43 @@ public interface TweedDataVisitor { void visitDouble(double value); void visitString(String value); + /** + * Visits an arbitrary value. + *
+ * This method is allowed to throw a {@link TweedDataUnsupportedValueException} for any value, + * so call sites should always 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() { visitListStart(); visitListEnd(); @@ -26,5 +66,8 @@ public interface TweedDataVisitor { void visitMapEntryKey(String key); void visitMapEnd(); - void visitComment(String comment); + /** + * Visits a decoration. The implementation may choose to ignore the decoration. + */ + void visitDecoration(TweedDataDecoration decoration); } diff --git a/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/TweedDataCommentDecoration.java b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/TweedDataCommentDecoration.java new file mode 100644 index 0000000..8f442a7 --- /dev/null +++ b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/TweedDataCommentDecoration.java @@ -0,0 +1,5 @@ +package de.siphalor.tweed5.dataapi.api.decoration; + +public interface TweedDataCommentDecoration extends TweedDataDecoration { + String comment(); +} diff --git a/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/TweedDataDecoration.java b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/TweedDataDecoration.java new file mode 100644 index 0000000..e52be32 --- /dev/null +++ b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/TweedDataDecoration.java @@ -0,0 +1,7 @@ +package de.siphalor.tweed5.dataapi.api.decoration; + +/** + * Marker interface for "decorative" information during (de)serialization. + */ +public interface TweedDataDecoration { +} diff --git a/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/package-info.java b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/package-info.java new file mode 100644 index 0000000..406c9d2 --- /dev/null +++ b/tweed5-serde-api/src/main/java/de/siphalor/tweed5/dataapi/api/decoration/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package de.siphalor.tweed5.dataapi.api.decoration; + +import org.jspecify.annotations.NullMarked; diff --git a/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/TweedEntryWriter.java b/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/TweedEntryWriter.java index 295ab44..b5d33b1 100644 --- a/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/TweedEntryWriter.java +++ b/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/TweedEntryWriter.java @@ -7,5 +7,6 @@ import org.jspecify.annotations.Nullable; @FunctionalInterface public interface TweedEntryWriter> { - 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; } diff --git a/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/extension/ReadWriteExtensionSetupContext.java b/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/extension/ReadWriteExtensionSetupContext.java index 8eac58a..2a7c993 100644 --- a/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/extension/ReadWriteExtensionSetupContext.java +++ b/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/extension/ReadWriteExtensionSetupContext.java @@ -1,7 +1,12 @@ 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; public interface ReadWriteExtensionSetupContext { PatchworkPartAccess registerReadWriteContextExtensionData(Class extensionDataClass); + void registerReaderMiddleware(Middleware> middleware); + void registerWriterMiddleware(Middleware> middleware); } diff --git a/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/extension/ReadWriteRelatedExtension.java b/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/extension/ReadWriteRelatedExtension.java index 39573a8..5222fae 100644 --- a/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/extension/ReadWriteRelatedExtension.java +++ b/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/api/extension/ReadWriteRelatedExtension.java @@ -1,22 +1,6 @@ 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 { default void setupReadWriteExtension(ReadWriteExtensionSetupContext context) { - - } - - @Nullable - default Middleware> entryReaderMiddleware() { - return null; - } - - @Nullable - default Middleware> entryWriterMiddleware() { - return null; } } diff --git a/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/impl/ReadWriteExtensionImpl.java b/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/impl/ReadWriteExtensionImpl.java index 71efe12..1f8a303 100644 --- a/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/impl/ReadWriteExtensionImpl.java +++ b/tweed5-serde-extension/src/main/java/de/siphalor/tweed5/data/extension/impl/ReadWriteExtensionImpl.java @@ -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.TweedExtensionSetupContext; 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.extension.ReadWriteExtensionSetupContext; 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.PatchworkPartAccess; import lombok.Data; -import lombok.val; import org.jspecify.annotations.Nullable; import java.util.Collection; @@ -48,25 +48,29 @@ public class ReadWriteExtensionImpl implements ReadWriteExtension { Collection extensions = configContainer.extensions(); PatchworkFactory.Builder readWriteContextPatchworkFactorBuilder = PatchworkFactory.builder(); - ReadWriteExtensionSetupContext setupContext = readWriteContextPatchworkFactorBuilder::registerPart; - entryReaderMiddlewareContainer = new DefaultMiddlewareContainer<>(); entryWriterMiddlewareContainer = new DefaultMiddlewareContainer<>(); + ReadWriteExtensionSetupContext setupContext = new ReadWriteExtensionSetupContext() { + @Override + public PatchworkPartAccess registerReadWriteContextExtensionData(Class extensionDataClass) { + return readWriteContextPatchworkFactorBuilder.registerPart(extensionDataClass); + } + + @Override + public void registerReaderMiddleware(Middleware> middleware) { + entryReaderMiddlewareContainer.register(middleware); + } + + @Override + public void registerWriterMiddleware(Middleware> middleware) { + entryWriterMiddlewareContainer.register(middleware); + } + }; + for (TweedExtension extension : extensions) { if (extension instanceof ReadWriteRelatedExtension) { - ReadWriteRelatedExtension rwExtension = (ReadWriteRelatedExtension) extension; - - rwExtension.setupReadWriteExtension(setupContext); - - val readerMiddleware = rwExtension.entryReaderMiddleware(); - if (readerMiddleware != null) { - entryReaderMiddlewareContainer.register(readerMiddleware); - } - val writerMiddleware = rwExtension.entryWriterMiddleware(); - if (writerMiddleware != null) { - entryWriterMiddlewareContainer.register(writerMiddleware); - } + ((ReadWriteRelatedExtension) extension).setupReadWriteExtension(setupContext); } } diff --git a/tweed5-serde-hjson/src/main/java/de/siphalor/tweed5/data/hjson/HjsonWriter.java b/tweed5-serde-hjson/src/main/java/de/siphalor/tweed5/data/hjson/HjsonWriter.java index ef562dc..4a44b84 100644 --- a/tweed5-serde-hjson/src/main/java/de/siphalor/tweed5/data/hjson/HjsonWriter.java +++ b/tweed5-serde-hjson/src/main/java/de/siphalor/tweed5/data/hjson/HjsonWriter.java @@ -2,6 +2,8 @@ package de.siphalor.tweed5.data.hjson; import de.siphalor.tweed5.dataapi.api.TweedDataWriteException; 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 java.io.IOException; @@ -237,7 +239,13 @@ public class HjsonWriter implements TweedDataVisitor { } @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); if (lineFeedMatcher.find()) { // Multiline