refactor!(core, serde-extension): Extend entry serde to make use of SubEntryKey for structured entries
This commit is contained in:
@@ -21,6 +21,7 @@ import de.siphalor.tweed5.coat.bridge.api.mapping.handler.BasicTweedCoatEntryHan
|
||||
import de.siphalor.tweed5.coat.bridge.api.mapping.handler.ConvertingTweedCoatEntryHandler;
|
||||
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||
import de.siphalor.tweed5.serde.extension.api.ReadWriteExtension;
|
||||
import de.siphalor.tweed5.serde.extension.api.TweedEntryReader;
|
||||
@@ -328,7 +329,8 @@ public class TweedCoatMappersImpl {
|
||||
@Override
|
||||
public <T, C extends ConfigEntry<T>> TweedReadResult<T> readSubEntry(
|
||||
TweedDataReader reader,
|
||||
C entry
|
||||
C entry,
|
||||
SubEntryKey key
|
||||
) {
|
||||
return TweedReadResult.empty();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.siphalor.tweed5.core.api.entry;
|
||||
|
||||
import de.siphalor.tweed5.core.api.Arity;
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -9,6 +10,8 @@ import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface CollectionConfigEntry<E, T extends Collection<E>> extends StructuredConfigEntry<T> {
|
||||
String ELEMENT_KEY = "element";
|
||||
|
||||
@Override
|
||||
default CollectionConfigEntry<E, T> apply(Consumer<ConfigEntry<T>> function) {
|
||||
StructuredConfigEntry.super.apply(function);
|
||||
@@ -37,7 +40,7 @@ public interface CollectionConfigEntry<E, T extends Collection<E>> extends Struc
|
||||
if (visitor.enterStructuredEntry(this, value)) {
|
||||
int index = 0;
|
||||
for (E item : value) {
|
||||
SubEntryKey subEntryKey = SubEntryKey.structured("element", Integer.toString(index));
|
||||
SubEntryKey subEntryKey = SubEntryKey.structured(ELEMENT_KEY, Integer.toString(index));
|
||||
if (visitor.enterSubEntry(subEntryKey)) {
|
||||
elementEntry().visitInOrder(visitor, item);
|
||||
visitor.leaveSubEntry(subEntryKey);
|
||||
@@ -50,10 +53,10 @@ public interface CollectionConfigEntry<E, T extends Collection<E>> extends Struc
|
||||
|
||||
@Override
|
||||
default Map<String, ConfigEntry<?>> subEntries() {
|
||||
return Collections.singletonMap("element", elementEntry());
|
||||
return Collections.singletonMap(ELEMENT_KEY, elementEntry());
|
||||
}
|
||||
|
||||
ConfigEntry<E> elementEntry();
|
||||
|
||||
T instantiateCollection(int size);
|
||||
@NonNull T instantiateCollection(int size);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.function.Consumer;
|
||||
|
||||
public interface NullableConfigEntry<T extends @Nullable Object> extends AddressableStructuredConfigEntry<T> {
|
||||
String NON_NULL_KEY = ":nonNull";
|
||||
SubEntryKey NON_NULL_SUB_ENTRY_KEY = SubEntryKey.transparentAddressable(NON_NULL_KEY, NON_NULL_KEY);
|
||||
|
||||
@Override
|
||||
default NullableConfigEntry<T> apply(Consumer<ConfigEntry<T>> function) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.siphalor.tweed5.serde.extension.api;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||
import de.siphalor.tweed5.serde_api.api.TweedDataReader;
|
||||
@@ -11,6 +12,6 @@ public interface TweedReadContext {
|
||||
Patchwork extensionsData();
|
||||
|
||||
<T extends @Nullable Object, C extends ConfigEntry<T>> TweedReadResult<T> readSubEntry(
|
||||
TweedDataReader reader, C entry
|
||||
TweedDataReader reader, C entry, SubEntryKey key
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.siphalor.tweed5.serde.extension.api;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||
import de.siphalor.tweed5.serde_api.api.TweedDataVisitor;
|
||||
import de.siphalor.tweed5.serde_api.api.TweedDataWriteException;
|
||||
@@ -10,6 +11,6 @@ public interface TweedWriteContext {
|
||||
Patchwork extensionsData();
|
||||
|
||||
<T extends @Nullable Object, C extends ConfigEntry<T>> void writeSubEntry(
|
||||
TweedDataVisitor writer, @Nullable T value, C entry
|
||||
TweedDataVisitor writer, C entry, SubEntryKey key, @Nullable T value
|
||||
) throws TweedEntryWriteException, TweedDataWriteException;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package de.siphalor.tweed5.serde.extension.impl;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.CollectionConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.CompoundConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.NullableConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.*;
|
||||
import de.siphalor.tweed5.serde.extension.api.*;
|
||||
import de.siphalor.tweed5.serde.extension.api.read.result.ThrowingReadFunction;
|
||||
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadIssue;
|
||||
@@ -13,6 +10,7 @@ import de.siphalor.tweed5.serde_api.api.*;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -50,7 +48,7 @@ public class TweedEntryReaderWriterImpls {
|
||||
return TweedReadResult.failed(TweedReadIssue.error(e, context));
|
||||
}
|
||||
|
||||
return context.readSubEntry(reader, entry.nonNullEntry());
|
||||
return context.readSubEntry(reader, entry.nonNullEntry(), NullableConfigEntry.NON_NULL_SUB_ENTRY_KEY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,7 +61,7 @@ public class TweedEntryReaderWriterImpls {
|
||||
if (value == null) {
|
||||
writer.visitNull();
|
||||
} else {
|
||||
context.writeSubEntry(writer, value, entry.nonNullEntry());
|
||||
context.writeSubEntry(writer, entry.nonNullEntry(), NullableConfigEntry.NON_NULL_SUB_ENTRY_KEY, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,7 +122,7 @@ public class TweedEntryReaderWriterImpls {
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public static class EnumReaderWriter<T extends Enum<?>> implements TweedEntryReaderWriter<T, ConfigEntry<T>> {
|
||||
public static class EnumReaderWriter<T extends @Nullable Enum<?>> implements TweedEntryReaderWriter<T, ConfigEntry<T>> {
|
||||
@Override
|
||||
public TweedReadResult<T> read(TweedDataReader reader, ConfigEntry<T> entry, TweedReadContext context) {
|
||||
//noinspection unchecked,rawtypes
|
||||
@@ -140,7 +138,7 @@ public class TweedEntryReaderWriterImpls {
|
||||
@Override
|
||||
public void write(
|
||||
TweedDataVisitor writer,
|
||||
@Nullable T value,
|
||||
T value,
|
||||
ConfigEntry<T> entry,
|
||||
TweedWriteContext context
|
||||
) throws TweedEntryWriteException, TweedDataWriteException {
|
||||
@@ -149,7 +147,7 @@ public class TweedEntryReaderWriterImpls {
|
||||
}
|
||||
}
|
||||
|
||||
public static class CollectionReaderWriter<T extends @Nullable Object, C extends Collection<T>> implements TweedEntryReaderWriter<C, CollectionConfigEntry<T, C>> {
|
||||
public static class CollectionReaderWriter<T extends @Nullable Object, C extends @Nullable Collection<T>> implements TweedEntryReaderWriter<C, CollectionConfigEntry<T, C>> {
|
||||
@Override
|
||||
public TweedReadResult<C> read(TweedDataReader reader, CollectionConfigEntry<T, C> entry, TweedReadContext context) {
|
||||
return requireToken(reader, TweedDataToken::isListStart, "Expected list start", context).andThen(_token -> {
|
||||
@@ -160,6 +158,7 @@ public class TweedEntryReaderWriterImpls {
|
||||
ConfigEntry<T> elementEntry = entry.elementEntry();
|
||||
List<T> list = new ArrayList<>(20);
|
||||
List<TweedReadIssue> issues = new ArrayList<>();
|
||||
int i = 0;
|
||||
while (true) {
|
||||
try {
|
||||
TweedDataToken token = reader.peekToken();
|
||||
@@ -167,7 +166,11 @@ public class TweedEntryReaderWriterImpls {
|
||||
reader.readToken();
|
||||
break;
|
||||
} else if (token.isListValue()) {
|
||||
TweedReadResult<T> elementResult = context.readSubEntry(reader, elementEntry);
|
||||
TweedReadResult<T> elementResult = context.readSubEntry(
|
||||
reader,
|
||||
elementEntry,
|
||||
SubEntryKey.structured(CollectionConfigEntry.ELEMENT_KEY, Integer.toString(i))
|
||||
);
|
||||
issues.addAll(Arrays.asList(elementResult.issues()));
|
||||
if (elementResult.isFailed() || elementResult.isError()) {
|
||||
return TweedReadResult.failed(issues.toArray(new TweedReadIssue[0]));
|
||||
@@ -184,6 +187,7 @@ public class TweedEntryReaderWriterImpls {
|
||||
} catch (TweedDataReadException e) {
|
||||
issues.add(TweedReadIssue.error(e, context));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
C result = entry.instantiateCollection(list.size());
|
||||
result.addAll(list);
|
||||
@@ -201,12 +205,16 @@ public class TweedEntryReaderWriterImpls {
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigEntry<T> elementEntry = entry.elementEntry();
|
||||
|
||||
writer.visitListStart();
|
||||
for (T element : value) {
|
||||
context.writeSubEntry(writer, element, elementEntry);
|
||||
|
||||
visitStructuredEntryShallow(entry, value, new ShallowValueVisitor() {
|
||||
@Override
|
||||
public <U extends @Nullable Object> void visit(ConfigEntry<U> entry, SubEntryKey key, U value)
|
||||
throws TweedDataWriteException, TweedEntryWriteException {
|
||||
context.writeSubEntry(writer, entry, key, value);
|
||||
}
|
||||
});
|
||||
|
||||
writer.visitListEnd();
|
||||
}
|
||||
}
|
||||
@@ -236,7 +244,13 @@ public class TweedEntryReaderWriterImpls {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
TweedReadResult<Object> subEntryResult = context.readSubEntry(reader, subEntry);
|
||||
|
||||
TweedReadResult<Object> subEntryResult = context.readSubEntry(
|
||||
reader,
|
||||
subEntry,
|
||||
SubEntryKey.addressable(key, key, key)
|
||||
);
|
||||
|
||||
issues.addAll(Arrays.asList(subEntryResult.issues()));
|
||||
if (subEntryResult.isFailed() || subEntryResult.isError()) {
|
||||
return TweedReadResult.failed(issues.toArray(new TweedReadIssue[0]));
|
||||
@@ -268,15 +282,16 @@ public class TweedEntryReaderWriterImpls {
|
||||
|
||||
writer.visitMapStart();
|
||||
|
||||
//noinspection unchecked
|
||||
Map<String, ConfigEntry<Object>> compoundEntries = (Map<String, ConfigEntry<Object>>)(Map<?, ?>) entry.subEntries();
|
||||
for (Map.Entry<String, ConfigEntry<Object>> e : compoundEntries.entrySet()) {
|
||||
String key = e.getKey();
|
||||
ConfigEntry<Object> subEntry = e.getValue();
|
||||
|
||||
writer.visitMapEntryKey(key);
|
||||
context.writeSubEntry(writer, entry.get(value, key), subEntry);
|
||||
visitStructuredEntryShallow(entry, value, new ShallowValueVisitor() {
|
||||
@Override
|
||||
public <U extends @Nullable Object> void visit(ConfigEntry<U> subEntry, SubEntryKey key, U subValue)
|
||||
throws TweedDataWriteException, TweedEntryWriteException {
|
||||
if (key.value() != null) {
|
||||
writer.visitMapEntryKey(key.value());
|
||||
context.writeSubEntry(writer, subEntry, key, subValue);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
writer.visitMapEnd();
|
||||
}
|
||||
@@ -284,7 +299,11 @@ public class TweedEntryReaderWriterImpls {
|
||||
|
||||
public static class NoopReaderWriter implements TweedEntryReaderWriter<@Nullable Object, ConfigEntry<Object>> {
|
||||
@Override
|
||||
public TweedReadResult<@Nullable Object> read(TweedDataReader reader, ConfigEntry<Object> entry, TweedReadContext context) {
|
||||
public TweedReadResult<@Nullable Object> read(
|
||||
TweedDataReader reader,
|
||||
ConfigEntry<@Nullable Object> entry,
|
||||
TweedReadContext context
|
||||
) {
|
||||
try {
|
||||
TweedDataToken token = reader.readToken();
|
||||
if (!token.isListStart() && !token.isMapStart()) {
|
||||
@@ -317,7 +336,12 @@ public class TweedEntryReaderWriterImpls {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(TweedDataVisitor writer, @Nullable Object value, ConfigEntry<Object> entry, TweedWriteContext context) throws TweedDataWriteException {
|
||||
public void write(
|
||||
TweedDataVisitor writer,
|
||||
@Nullable Object value,
|
||||
ConfigEntry<@Nullable Object> entry,
|
||||
TweedWriteContext context
|
||||
) throws TweedDataWriteException {
|
||||
writer.visitNull();
|
||||
}
|
||||
|
||||
@@ -326,11 +350,11 @@ public class TweedEntryReaderWriterImpls {
|
||||
}
|
||||
}
|
||||
|
||||
private interface PrimitiveReadFunction<T extends Object> {
|
||||
private interface PrimitiveReadFunction<T> {
|
||||
T read(TweedDataToken token) throws TweedDataReadException;
|
||||
}
|
||||
|
||||
private interface PrimitiveWriteFunction<T extends Object> {
|
||||
private interface PrimitiveWriteFunction<T> {
|
||||
void write(TweedDataVisitor writer, T value) throws TweedDataWriteException;
|
||||
}
|
||||
|
||||
@@ -363,4 +387,44 @@ public class TweedEntryReaderWriterImpls {
|
||||
return TweedReadResult.failed(TweedReadIssue.error(e, context));
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends @Nullable Object> void visitStructuredEntryShallow(
|
||||
StructuredConfigEntry<T> entry,
|
||||
T value,
|
||||
ShallowValueVisitor shallowValueVisitor
|
||||
) throws TweedDataWriteException, TweedEntryWriteException {
|
||||
entry.visitInOrder(new ConfigEntryValueVisitor() {
|
||||
private @Nullable SubEntryKey currentSubEntryKey;
|
||||
|
||||
@Override
|
||||
public <U> boolean enterStructuredEntry(StructuredConfigEntry<U> vEntry, U vValue) {
|
||||
if (entry == vEntry) {
|
||||
return true;
|
||||
}
|
||||
visitEntry(vEntry, vValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enterSubEntry(SubEntryKey subEntryKey) {
|
||||
currentSubEntryKey = subEntryKey;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public <U> void visitEntry(ConfigEntry<U> vEntry, U vValue) {
|
||||
if (currentSubEntryKey != null) {
|
||||
shallowValueVisitor.visit(vEntry, currentSubEntryKey, vValue);
|
||||
currentSubEntryKey = null;
|
||||
}
|
||||
}
|
||||
}, value);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface ShallowValueVisitor {
|
||||
<T extends @Nullable Object> void visit(ConfigEntry<T> entry, SubEntryKey key, T value)
|
||||
throws TweedDataWriteException, TweedEntryWriteException;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package de.siphalor.tweed5.serde.extension.impl;
|
||||
|
||||
import de.siphalor.tweed5.core.api.entry.ConfigEntry;
|
||||
import de.siphalor.tweed5.core.api.entry.SubEntryKey;
|
||||
import de.siphalor.tweed5.serde.extension.api.*;
|
||||
import de.siphalor.tweed5.serde.extension.api.read.result.TweedReadResult;
|
||||
import de.siphalor.tweed5.patchwork.api.Patchwork;
|
||||
@@ -20,14 +21,14 @@ class TweedReadWriteContextImpl implements TweedReadContext, TweedWriteContext {
|
||||
|
||||
@Override
|
||||
public <T extends @Nullable Object, C extends ConfigEntry<T>> TweedReadResult<T> readSubEntry(
|
||||
TweedDataReader reader, C entry
|
||||
TweedDataReader reader, C entry, SubEntryKey key
|
||||
) {
|
||||
return readWriteExtension.getReaderChain(entry).read(reader, entry, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends @Nullable Object, C extends ConfigEntry<T>> void writeSubEntry(
|
||||
TweedDataVisitor writer, @Nullable T value, C entry
|
||||
TweedDataVisitor writer, C entry, SubEntryKey key, @Nullable T value
|
||||
) throws TweedEntryWriteException, TweedDataWriteException {
|
||||
readWriteExtension.getWriterChain(entry).write(writer, value, entry, this);
|
||||
}
|
||||
|
||||
@@ -80,19 +80,21 @@ public class StaticPojoCompoundConfigEntry<T> extends BaseConfigEntry<T> impleme
|
||||
@Override
|
||||
public void visitInOrder(ConfigEntryValueVisitor visitor, T value) {
|
||||
if (visitor.enterStructuredEntry(this, value)) {
|
||||
subEntries.forEach((key, entry) -> {
|
||||
for (Map.Entry<String, SubEntry> entry : subEntries.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
SubEntryKey subEntryKey = SubEntryKey.addressable(key, key, key);
|
||||
if (visitor.enterSubEntry(subEntryKey)) {
|
||||
Object subValue;
|
||||
try {
|
||||
Object subValue = entry.getter().invoke(value);
|
||||
//noinspection unchecked
|
||||
((ConfigEntry<Object>) entry.configEntry()).visitInOrder(visitor, subValue);
|
||||
visitor.leaveSubEntry(subEntryKey);
|
||||
subValue = entry.getValue().getter().invoke(value);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Failed to get compound sub entry value \"" + key + "\"");
|
||||
}
|
||||
//noinspection unchecked
|
||||
((ConfigEntry<Object>) entry.getValue().configEntry()).visitInOrder(visitor, subValue);
|
||||
visitor.leaveSubEntry(subEntryKey);
|
||||
}
|
||||
}
|
||||
});
|
||||
visitor.leaveStructuredEntry(this, value);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user