[comment-loader-extension] Introduce comment loader extension
This commit is contained in:
@@ -3,6 +3,7 @@ rootProject.name = "tweed5"
|
|||||||
include("test-utils")
|
include("test-utils")
|
||||||
include("tweed5-annotation-inheritance")
|
include("tweed5-annotation-inheritance")
|
||||||
include("tweed5-attributes-extension")
|
include("tweed5-attributes-extension")
|
||||||
|
include("tweed5-comment-loader-extension")
|
||||||
include("tweed5-construct")
|
include("tweed5-construct")
|
||||||
include("tweed5-core")
|
include("tweed5-core")
|
||||||
include("tweed5-default-extensions")
|
include("tweed5-default-extensions")
|
||||||
|
|||||||
12
tweed5-comment-loader-extension/build.gradle.kts
Normal file
12
tweed5-comment-loader-extension/build.gradle.kts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
plugins {
|
||||||
|
id("de.siphalor.tweed5.base-module")
|
||||||
|
id("de.siphalor.tweed5.minecraft.mod.dummy")
|
||||||
|
id("de.siphalor.tweed5.shadow.explicit")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(project(":tweed5-core"))
|
||||||
|
implementation(project(":tweed5-default-extensions"))
|
||||||
|
|
||||||
|
testImplementation(project(":tweed5-serde-gson"))
|
||||||
|
}
|
||||||
2
tweed5-comment-loader-extension/gradle.properties
Normal file
2
tweed5-comment-loader-extension/gradle.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
minecraft.mod.name = Tweed 5 Comment Loader Extension
|
||||||
|
minecraft.mod.description = Tweed 5 module that allows dynamically loading comments from data files, e.g., for i18n
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package de.siphalor.tweed5.commentloaderextension.api;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.commentloaderextension.impl.CommentLoaderExtensionImpl;
|
||||||
|
import de.siphalor.tweed5.core.api.extension.TweedExtension;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||||
|
|
||||||
|
public interface CommentLoaderExtension extends TweedExtension {
|
||||||
|
Class<? extends CommentLoaderExtension> DEFAULT = CommentLoaderExtensionImpl.class;
|
||||||
|
String EXTENSION_ID = "comment-loader";
|
||||||
|
|
||||||
|
void loadComments(TweedDataReader reader, CommentPathProcessor pathProcessor);
|
||||||
|
|
||||||
|
default String getId() {
|
||||||
|
return EXTENSION_ID;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package de.siphalor.tweed5.commentloaderextension.api;
|
||||||
|
|
||||||
|
public interface CommentPathProcessor {
|
||||||
|
MatchStatus matches(String path);
|
||||||
|
String process(String path);
|
||||||
|
|
||||||
|
enum MatchStatus {
|
||||||
|
YES,
|
||||||
|
NO,
|
||||||
|
MAYBE_DEEPER,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@NullMarked
|
||||||
|
package de.siphalor.tweed5.commentloaderextension.api;
|
||||||
|
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
package de.siphalor.tweed5.commentloaderextension.impl;
|
||||||
|
|
||||||
|
import de.siphalor.tweed5.commentloaderextension.api.CommentLoaderExtension;
|
||||||
|
import de.siphalor.tweed5.commentloaderextension.api.CommentPathProcessor;
|
||||||
|
import de.siphalor.tweed5.core.api.container.ConfigContainer;
|
||||||
|
import de.siphalor.tweed5.core.api.container.ConfigContainerSetupPhase;
|
||||||
|
import de.siphalor.tweed5.core.api.extension.TweedExtensionSetupContext;
|
||||||
|
import de.siphalor.tweed5.core.api.middleware.Middleware;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.IntuitiveVisitingTweedDataReader;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataReadException;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataReader;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.TweedDataVisitor;
|
||||||
|
import de.siphalor.tweed5.dataapi.api.decoration.TweedDataDecoration;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentModifyingExtension;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentProducer;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.pather.api.PathTracking;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.pather.api.PathTrackingConfigEntryVisitor;
|
||||||
|
import de.siphalor.tweed5.patchwork.api.PatchworkPartAccess;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Value;
|
||||||
|
import lombok.extern.apachecommons.CommonsLog;
|
||||||
|
import org.jspecify.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@CommonsLog
|
||||||
|
public class CommentLoaderExtensionImpl implements CommentLoaderExtension, CommentModifyingExtension {
|
||||||
|
private final ConfigContainer<?> configContainer;
|
||||||
|
private final PatchworkPartAccess<String> loadedCommentAccess;
|
||||||
|
private @Nullable CommentExtension commentExtension;
|
||||||
|
|
||||||
|
public CommentLoaderExtensionImpl(ConfigContainer<?> configContainer, TweedExtensionSetupContext setupContext) {
|
||||||
|
this.configContainer = configContainer;
|
||||||
|
setupContext.registerExtension(CommentExtension.class);
|
||||||
|
|
||||||
|
loadedCommentAccess = setupContext.registerEntryExtensionData(String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void extensionsFinalized() {
|
||||||
|
commentExtension = configContainer.extension(CommentExtension.class)
|
||||||
|
.orElseThrow(() -> new IllegalStateException("CommentExtension not found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Middleware<CommentProducer> commentMiddleware() {
|
||||||
|
return new Middleware<CommentProducer>() {
|
||||||
|
@Override
|
||||||
|
public String id() {
|
||||||
|
return EXTENSION_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> mustComeBefore() {
|
||||||
|
return Collections.singleton(Middleware.DEFAULT_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> mustComeAfter() {
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommentProducer process(CommentProducer inner) {
|
||||||
|
return entry -> {
|
||||||
|
String loadedComment = entry.extensionsData().get(loadedCommentAccess);
|
||||||
|
String innerComment = inner.createComment(entry);
|
||||||
|
if (loadedComment != null) {
|
||||||
|
if (innerComment.isEmpty()) {
|
||||||
|
return loadedComment;
|
||||||
|
} else {
|
||||||
|
return innerComment + loadedComment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return innerComment;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadComments(TweedDataReader reader, CommentPathProcessor pathProcessor) {
|
||||||
|
if (configContainer.setupPhase().compareTo(ConfigContainerSetupPhase.EXTENSIONS_SETUP) <= 0) {
|
||||||
|
throw new IllegalStateException("Comments cannot be loaded before the extensions are finalized");
|
||||||
|
}
|
||||||
|
|
||||||
|
CollectingCommentsVisitor collectingCommentsVisitor = new CollectingCommentsVisitor(pathProcessor);
|
||||||
|
try {
|
||||||
|
new IntuitiveVisitingTweedDataReader(collectingCommentsVisitor).readMap(reader);
|
||||||
|
} catch (TweedDataReadException e) {
|
||||||
|
log.error("Failed to load comments", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> commentsByKey = collectingCommentsVisitor.commentsByKey();
|
||||||
|
PathTracking pathTracking = new PathTracking();
|
||||||
|
configContainer.rootEntry().visitInOrder(new PathTrackingConfigEntryVisitor(
|
||||||
|
entry -> {
|
||||||
|
String key = pathTracking.currentPath();
|
||||||
|
if (!key.isEmpty() && key.charAt(0) == '.') {
|
||||||
|
key = key.substring(1);
|
||||||
|
}
|
||||||
|
entry.extensionsData().set(loadedCommentAccess, commentsByKey.get(key));
|
||||||
|
},
|
||||||
|
pathTracking
|
||||||
|
));
|
||||||
|
|
||||||
|
if (configContainer.setupPhase().compareTo(ConfigContainerSetupPhase.INITIALIZED) >= 0) {
|
||||||
|
assert commentExtension != null;
|
||||||
|
commentExtension.recomputeFullComments();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CollectingCommentsVisitor implements TweedDataVisitor {
|
||||||
|
private final CommentPathProcessor pathProcessor;
|
||||||
|
@Getter
|
||||||
|
private final Map<String, String> commentsByKey = new HashMap<>();
|
||||||
|
private final Deque<State> stateStack = new ArrayDeque<>();
|
||||||
|
private State currentState = new State(CommentPathProcessor.MatchStatus.MAYBE_DEEPER, "");
|
||||||
|
|
||||||
|
public CollectingCommentsVisitor(CommentPathProcessor pathProcessor) {
|
||||||
|
this.pathProcessor = pathProcessor;
|
||||||
|
stateStack.push(currentState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitNull() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitBoolean(boolean value) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitByte(byte value) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitShort(short value) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitInt(int value) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitLong(long value) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitFloat(float value) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDouble(double value) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitString(String value) {
|
||||||
|
if (currentState.matchStatus() == CommentPathProcessor.MatchStatus.YES) {
|
||||||
|
commentsByKey.put(pathProcessor.process(currentState.key()), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitListStart() {
|
||||||
|
stateStack.push(State.IGNORED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitListEnd() {
|
||||||
|
stateStack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapStart() {
|
||||||
|
stateStack.push(currentState);
|
||||||
|
currentState = State.IGNORED;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapEntryKey(String key) {
|
||||||
|
State state = stateStack.peek();
|
||||||
|
assert state != null;
|
||||||
|
if (state.matchStatus() == CommentPathProcessor.MatchStatus.NO) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String fullPath;
|
||||||
|
if (state.key().isEmpty()) {
|
||||||
|
fullPath = key;
|
||||||
|
} else {
|
||||||
|
fullPath = state.key() + "." + key;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommentPathProcessor.MatchStatus matchStatus = pathProcessor.matches(fullPath);
|
||||||
|
if (matchStatus == CommentPathProcessor.MatchStatus.NO) {
|
||||||
|
currentState = State.IGNORED;
|
||||||
|
} else {
|
||||||
|
currentState = new State(matchStatus, fullPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMapEnd() {
|
||||||
|
currentState = stateStack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitDecoration(TweedDataDecoration decoration) {}
|
||||||
|
|
||||||
|
@Value
|
||||||
|
private static class State {
|
||||||
|
private static final State IGNORED = new State(CommentPathProcessor.MatchStatus.NO, "");
|
||||||
|
|
||||||
|
CommentPathProcessor.MatchStatus matchStatus;
|
||||||
|
String key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
@ApiStatus.Internal
|
||||||
|
@NullMarked
|
||||||
|
package de.siphalor.tweed5.commentloaderextension.impl;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jspecify.annotations.NullMarked;
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package de.siphalor.tweed5.commentloaderextension.impl;
|
||||||
|
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import de.siphalor.tweed5.commentloaderextension.api.CommentLoaderExtension;
|
||||||
|
import de.siphalor.tweed5.commentloaderextension.api.CommentPathProcessor;
|
||||||
|
import de.siphalor.tweed5.core.impl.DefaultConfigContainer;
|
||||||
|
import de.siphalor.tweed5.core.impl.entry.SimpleConfigEntryImpl;
|
||||||
|
import de.siphalor.tweed5.core.impl.entry.StaticMapCompoundConfigEntryImpl;
|
||||||
|
import de.siphalor.tweed5.defaultextensions.comment.api.CommentExtension;
|
||||||
|
import de.siphaolor.tweed5.data.gson.GsonReader;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static de.siphalor.tweed5.testutils.generic.MapTestUtils.sequencedMap;
|
||||||
|
import static java.util.Map.entry;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
class CommentLoaderExtensionImplTest {
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
@Test
|
||||||
|
@SneakyThrows
|
||||||
|
void test() {
|
||||||
|
var configContainer = new DefaultConfigContainer<Map<String, Object>>();
|
||||||
|
configContainer.registerExtension(CommentLoaderExtension.class);
|
||||||
|
configContainer.finishExtensionSetup();
|
||||||
|
|
||||||
|
var nestedIntEntry = new SimpleConfigEntryImpl<>(configContainer, Integer.class);
|
||||||
|
var nestedEntry = new StaticMapCompoundConfigEntryImpl<>(
|
||||||
|
configContainer,
|
||||||
|
(Class<Map<String, Object>>) (Class) Map.class,
|
||||||
|
HashMap::newHashMap,
|
||||||
|
sequencedMap(List.of(
|
||||||
|
entry("int", nestedIntEntry)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
var intEntry = new SimpleConfigEntryImpl<>(configContainer, Integer.class);
|
||||||
|
var rootEntry = new StaticMapCompoundConfigEntryImpl<>(
|
||||||
|
configContainer,
|
||||||
|
(Class<Map<String, Object>>)(Class) Map.class,
|
||||||
|
HashMap::newHashMap,
|
||||||
|
sequencedMap(List.of(
|
||||||
|
entry("nested", nestedEntry),
|
||||||
|
entry("int", intEntry)
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
configContainer.attachTree(rootEntry);
|
||||||
|
configContainer.initialize();
|
||||||
|
|
||||||
|
CommentLoaderExtension extension = configContainer.extension(CommentLoaderExtension.class).orElseThrow();
|
||||||
|
|
||||||
|
// language=json
|
||||||
|
var text = """
|
||||||
|
{
|
||||||
|
"test": {
|
||||||
|
"description": "Root comment"
|
||||||
|
},
|
||||||
|
"test.int.description": "What an int!",
|
||||||
|
"test.nested": {
|
||||||
|
"description": "Comment for nested entry",
|
||||||
|
"int.description": "A cool nested entry"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
try (var reader = new GsonReader(new GsonBuilder().create().newJsonReader(new StringReader(text)))) {
|
||||||
|
extension.loadComments(
|
||||||
|
reader,
|
||||||
|
new CommentPathProcessor() {
|
||||||
|
private static final String PREFIX_RAW = "test";
|
||||||
|
private static final String PREFIX = PREFIX_RAW + ".";
|
||||||
|
private static final String SUFFIX = ".description";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MatchStatus matches(String path) {
|
||||||
|
if (path.equals(PREFIX_RAW)) {
|
||||||
|
return MatchStatus.MAYBE_DEEPER;
|
||||||
|
} else if (path.startsWith(PREFIX)) {
|
||||||
|
if (path.endsWith(SUFFIX)) {
|
||||||
|
return MatchStatus.YES;
|
||||||
|
} else {
|
||||||
|
return MatchStatus.MAYBE_DEEPER;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return MatchStatus.NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String process(String path) {
|
||||||
|
return path.substring(
|
||||||
|
PREFIX.length(),
|
||||||
|
Math.max(PREFIX.length(), path.length() - SUFFIX.length())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CommentExtension commentExtension = configContainer.extension(CommentExtension.class).orElseThrow();
|
||||||
|
|
||||||
|
assertThat(commentExtension.getFullComment(rootEntry)).isEqualTo("Root comment");
|
||||||
|
assertThat(commentExtension.getFullComment(nestedEntry)).isEqualTo("Comment for nested entry");
|
||||||
|
assertThat(commentExtension.getFullComment(nestedIntEntry)).isEqualTo("A cool nested entry");
|
||||||
|
assertThat(commentExtension.getFullComment(intEntry)).isEqualTo("What an int!");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,5 +21,7 @@ public interface CommentExtension extends TweedExtension {
|
|||||||
|
|
||||||
void setBaseComment(ConfigEntry<?> configEntry, String baseComment);
|
void setBaseComment(ConfigEntry<?> configEntry, String baseComment);
|
||||||
|
|
||||||
|
void recomputeFullComments();
|
||||||
|
|
||||||
@Nullable String getFullComment(ConfigEntry<?> configEntry);
|
@Nullable String getFullComment(ConfigEntry<?> configEntry);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,9 +65,16 @@ public class CommentExtensionImpl implements ReadWriteRelatedExtension, CommentE
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initEntry(ConfigEntry<?> configEntry) {
|
public void initialize() {
|
||||||
CustomEntryData entryData = getOrCreateCustomEntryData(configEntry);
|
recomputeFullComments();
|
||||||
entryData.commentProducer(middlewareContainer.process(entry -> entryData.baseComment()));
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void recomputeFullComments() {
|
||||||
|
configContainer.rootEntry().visitInOrder(entry -> {
|
||||||
|
CustomEntryData entryData = getOrCreateCustomEntryData(entry);
|
||||||
|
entryData.commentProducer(middlewareContainer.process(_entry -> entryData.baseComment()));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private CustomEntryData getOrCreateCustomEntryData(ConfigEntry<?> entry) {
|
private CustomEntryData getOrCreateCustomEntryData(ConfigEntry<?> entry) {
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package de.siphalor.tweed5.dataapi.api;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class IntuitiveVisitingTweedDataReader {
|
||||||
|
private final TweedDataVisitor visitor;
|
||||||
|
|
||||||
|
public void readValue(TweedDataReader reader) throws TweedDataReadException {
|
||||||
|
TweedDataToken token = reader.peekToken();
|
||||||
|
if (token.isNull()) {
|
||||||
|
reader.readToken();
|
||||||
|
visitor.visitNull();
|
||||||
|
} else if (token.isListStart()) {
|
||||||
|
readList(reader);
|
||||||
|
} else if (token.isMapStart()) {
|
||||||
|
readMap(reader);
|
||||||
|
} else if (token.canReadAsByte()) {
|
||||||
|
visitor.visitByte(reader.readToken().readAsByte());
|
||||||
|
} else if (token.canReadAsShort()) {
|
||||||
|
visitor.visitShort(reader.readToken().readAsShort());
|
||||||
|
} else if (token.canReadAsInt()) {
|
||||||
|
visitor.visitInt(reader.readToken().readAsInt());
|
||||||
|
} else if (token.canReadAsLong()) {
|
||||||
|
visitor.visitLong(reader.readToken().readAsLong());
|
||||||
|
} else if (token.canReadAsFloat()) {
|
||||||
|
visitor.visitFloat(reader.readToken().readAsFloat());
|
||||||
|
} else if (token.canReadAsDouble()) {
|
||||||
|
visitor.visitDouble(reader.readToken().readAsDouble());
|
||||||
|
} else if (token.canReadAsBoolean()) {
|
||||||
|
visitor.visitBoolean(reader.readToken().readAsBoolean());
|
||||||
|
} else if (token.canReadAsString()) {
|
||||||
|
visitor.visitString(reader.readToken().readAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readList(TweedDataReader reader) throws TweedDataReadException {
|
||||||
|
TweedDataToken token = reader.readToken();
|
||||||
|
if (!token.isListStart()) {
|
||||||
|
throw TweedDataReadException.builder().message("Expected list but got " + token).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
visitor.visitListStart();
|
||||||
|
while (true) {
|
||||||
|
token = reader.peekToken();
|
||||||
|
if (token.isListEnd()) {
|
||||||
|
visitor.visitListEnd();
|
||||||
|
reader.readToken();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
readValue(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readMap(TweedDataReader reader) throws TweedDataReadException {
|
||||||
|
TweedDataToken token = reader.readToken();
|
||||||
|
if (!token.isMapStart()) {
|
||||||
|
throw TweedDataReadException.builder().message("Expected map but got " + token).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
visitor.visitMapStart();
|
||||||
|
while (true) {
|
||||||
|
token = reader.peekToken();
|
||||||
|
if (token.isMapEnd()) {
|
||||||
|
reader.readToken();
|
||||||
|
visitor.visitMapEnd();
|
||||||
|
break;
|
||||||
|
} else if (token.isMapEntryKey()) {
|
||||||
|
visitor.visitMapEntryKey(reader.readToken().readAsString());
|
||||||
|
readValue(reader);
|
||||||
|
} else {
|
||||||
|
throw TweedDataReadException.builder().message("Expected map end or entry key but got " + token).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ plugins {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(project(":tweed5-serde-api"))
|
implementation(project(":tweed5-serde-api"))
|
||||||
implementation(libs.gson)
|
api(libs.gson)
|
||||||
|
|
||||||
testImplementation(project(":serde-json-test-utils"))
|
testImplementation(project(":serde-json-test-utils"))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user