feat(serialize-databind): implement alternate API for parsing via ADTs. Probably still need to figure out how to ensure unchecked exceptions are not propagated
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
Johannes Frohnmeyer 2024-04-30 15:53:01 +02:00
parent 1a09294690
commit 133e1d75f9
Signed by: Johannes
GPG Key ID: E76429612C2929F4
2 changed files with 95 additions and 1 deletions

View File

@ -0,0 +1,12 @@
package io.gitlab.jfronny.commons.serialize;
public sealed interface RToken {
enum Simple implements RToken {
BEGIN_ARRAY, END_ARRAY, BEGIN_OBJECT, END_OBJECT, NULL, END_DOCUMENT
}
record Name(java.lang.String name) implements RToken {}
record String(java.lang.String value) implements RToken {}
record Number(java.lang.Number value) implements RToken {}
record Boolean(boolean value) implements RToken {}
}

View File

@ -1,8 +1,23 @@
package io.gitlab.jfronny.commons.serialize; package io.gitlab.jfronny.commons.serialize;
import io.gitlab.jfronny.commons.SamWithReceiver; import io.gitlab.jfronny.commons.SamWithReceiver;
import io.gitlab.jfronny.commons.throwable.ExceptionWrapper;
import org.jetbrains.annotations.NotNull;
public abstract class SerializeReader<TEx extends Exception, T extends SerializeReader<TEx, T>> implements AutoCloseable { import java.util.Iterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* A reader for serialized data.
* Although it is marked as {@link Iterable}, you should make sure iteration is only done once, since it <b>consumes tokens</b>!
*
* @param <TEx> the exception type
* @param <T> the reader type
*/
public abstract class SerializeReader<TEx extends Exception, T extends SerializeReader<TEx, T>> implements AutoCloseable, Iterable<RToken> {
protected boolean lenient = false; protected boolean lenient = false;
protected boolean serializeSpecialFloatingPointValues = false; protected boolean serializeSpecialFloatingPointValues = false;
@ -67,6 +82,69 @@ public abstract class SerializeReader<TEx extends Exception, T extends Serialize
@Override @Override
public abstract void close() throws TEx; public abstract void close() throws TEx;
/**
* Returns the next token alongside its value as an {@link RToken} and advances the reader.
*
* @return the next token
* @throws TEx if an error occurs
*/
public RToken next() throws TEx {
return switch (peek()) {
case BEGIN_ARRAY -> RToken.Simple.BEGIN_ARRAY;
case END_ARRAY -> RToken.Simple.END_ARRAY;
case BEGIN_OBJECT -> RToken.Simple.BEGIN_OBJECT;
case END_OBJECT -> RToken.Simple.END_OBJECT;
case NAME -> new RToken.Name(nextName());
case STRING -> new RToken.String(nextString());
case NUMBER -> new RToken.Number(nextNumber());
case BOOLEAN -> new RToken.Boolean(nextBoolean());
case NULL -> {
nextNull();
yield RToken.Simple.NULL;
}
case END_DOCUMENT -> RToken.Simple.END_DOCUMENT;
};
}
/**
* Returns a {@link Stream} of the tokens within the current object or array.
* The stream consumes tokens and advances the reader, so it is not possible to iterate over the tokens more than once.
* Additionally, iteration may throw {@link RuntimeException}s created with {@link ExceptionWrapper#wrap(Throwable)} around {@link TEx}.
* @return a stream of the tokens
*/
public @NotNull Stream<RToken> stream() {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator(), Spliterator.NONNULL | Spliterator.ORDERED), false);
}
/**
* Returns an {@link Iterator} over the tokens within the current object or array.
* The iterator consumes tokens and advances the reader, so it is not possible to iterate over the tokens more than once.
* Additionally, iteration may throw {@link RuntimeException}s created with {@link ExceptionWrapper#wrap(Throwable)} around {@link TEx}.
* @return an iterator over the tokens
*/
@Override
public @NotNull Iterator<RToken> iterator() {
return new Iterator<>() {
@Override
public boolean hasNext() {
try {
return SerializeReader.this.hasNext();
} catch (Exception e) {
throw ExceptionWrapper.wrap(e);
}
}
@Override
public RToken next() {
try {
return SerializeReader.this.next();
} catch (Exception e) {
throw ExceptionWrapper.wrap(e);
}
}
};
}
/** /**
* Copies the current element to the writer. * Copies the current element to the writer.
* *
@ -113,6 +191,10 @@ public abstract class SerializeReader<TEx extends Exception, T extends Serialize
return getClass().getSimpleName() + locationString(); return getClass().getSimpleName() + locationString();
} }
/**
* Used to provide toString and location information in error messages. Format should resemble that in {@code serialize-json}.
* @return a string representation of the location of the reader
*/
protected String locationString() { protected String locationString() {
return " at path " + getPath(); return " at path " + getPath();
} }