[serde-*, read-write-*] Support for visiting arbitrary decorations and values

This commit is contained in:
2025-07-21 23:17:50 +02:00
parent 22bccfe525
commit e4ea5fdfc2
16 changed files with 299 additions and 154 deletions

View File

@@ -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

View File

@@ -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;
} }
} }

View File

@@ -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);
} }
} }

View File

@@ -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;
}
} }

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
} }

View File

@@ -0,0 +1,5 @@
package de.siphalor.tweed5.dataapi.api.decoration;
public interface TweedDataCommentDecoration extends TweedDataDecoration {
String comment();
}

View File

@@ -0,0 +1,7 @@
package de.siphalor.tweed5.dataapi.api.decoration;
/**
* Marker interface for "decorative" information during (de)serialization.
*/
public interface TweedDataDecoration {
}

View File

@@ -0,0 +1,4 @@
@NullMarked
package de.siphalor.tweed5.dataapi.api.decoration;
import org.jspecify.annotations.NullMarked;

View File

@@ -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;
} }

View File

@@ -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);
} }

View File

@@ -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;
} }
} }

View File

@@ -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);
}
} }
} }

View File

@@ -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