diff --git a/faunaJava/src/main/java/com/fauna/serialization/FaunaParser.java b/faunaJava/src/main/java/com/fauna/serialization/FaunaParser.java index 533e9f51..492c89ab 100644 --- a/faunaJava/src/main/java/com/fauna/serialization/FaunaParser.java +++ b/faunaJava/src/main/java/com/fauna/serialization/FaunaParser.java @@ -41,6 +41,10 @@ public class FaunaParser { private FaunaTokenType bufferedFaunaTokenType; private String taggedTokenValue; + private enum TokenTypeInternal { + START_ESCAPED_OBJECT + } + public FaunaParser(InputStream body) throws IOException { JsonFactory factory = new JsonFactory(); this.jsonParser = factory.createParser(body); @@ -52,8 +56,8 @@ public FaunaParser(JsonParser jsonParser) { currentFaunaTokenType = NONE; } - public JsonToken getCurrentTokenType() { - return jsonParser.currentToken(); + public FaunaTokenType getCurrentTokenType() { + return currentFaunaTokenType; } private final Set closers = new HashSet<>(Arrays.asList( @@ -64,7 +68,7 @@ public JsonToken getCurrentTokenType() { END_ARRAY )); - public boolean read() { + public boolean read() throws IOException { taggedTokenValue = null; if (bufferedFaunaTokenType != null) { @@ -86,6 +90,9 @@ public boolean read() { case VALUE_STRING: currentFaunaTokenType = FaunaTokenType.STRING; break; + case START_OBJECT: + handleStartObject(); + break; default: throw new SerializationException( "Unhandled JSON token type " + currentToken + "."); @@ -97,6 +104,55 @@ public boolean read() { return true; } + private void handleStartObject() throws IOException { + advanceTrue(); + + switch (jsonParser.currentToken()) { + case FIELD_NAME: + switch (jsonParser.getText()) { + case INT_TAG: + handleTaggedString(FaunaTokenType.INT); + break; + case DATE_TAG: + case DOC_TAG: + case DOUBLE_TAG: + case LONG_TAG: + case MOD_TAG: + case OBJECT_TAG: + case REF_TAG: + case SET_TAG: + case TIME_TAG: + throw new SerializationException( + "Token not implemented: " + jsonParser.currentToken()); + default: + bufferedFaunaTokenType = FaunaTokenType.FIELD_NAME; + tokenStack.push(FaunaTokenType.START_OBJECT); + currentFaunaTokenType = FaunaTokenType.START_OBJECT; + break; + } + break; + case END_OBJECT: + throw new SerializationException( + "Token not implemented: " + jsonParser.currentToken()); + default: + throw new SerializationException( + "Unexpected token following StartObject: " + jsonParser.currentToken()); + } + } + + private void handleTaggedString(FaunaTokenType token) throws IOException { + advanceTrue(); + currentFaunaTokenType = token; + taggedTokenValue = jsonParser.getText(); + advance(); + } + + private void advanceTrue() { + if (!advance()) { + throw new SerializationException("Unexpected end of underlying JSON reader."); + } + } + private boolean advance() { try { return Objects.nonNull(jsonParser.nextToken()); @@ -105,11 +161,29 @@ private boolean advance() { } } + private void validateTaggedType(FaunaTokenType type) { + if (currentFaunaTokenType != type || taggedTokenValue == null + || !(taggedTokenValue instanceof String)) { + throw new IllegalStateException( + "CurrentTokenType is a " + currentFaunaTokenType.toString() + + ", not a " + type.toString() + "."); + } + } + public String getValueAsString() { try { return jsonParser.getValueAsString(); } catch (IOException e) { - throw new RuntimeException("Error reading current token as String", e); + throw new RuntimeException("Error getting the current token as String", e); + } + } + + public Integer getValueAsInt() { + validateTaggedType(FaunaTokenType.INT); + try { + return Integer.parseInt(taggedTokenValue); + } catch (NumberFormatException e) { + throw new RuntimeException("Error getting the current token as Integer", e); } } } \ No newline at end of file diff --git a/faunaJava/src/test/java/com/fauna/query/template/FaunaTemplateTest.java b/faunaJava/src/test/java/com/fauna/query/template/FaunaTemplateTest.java index 327bf70a..9b20a45b 100644 --- a/faunaJava/src/test/java/com/fauna/query/template/FaunaTemplateTest.java +++ b/faunaJava/src/test/java/com/fauna/query/template/FaunaTemplateTest.java @@ -1,11 +1,10 @@ package com.fauna.query.template; -import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.ArrayList; import java.util.List; - -import static org.junit.jupiter.api.Assertions.*; +import org.junit.jupiter.api.Test; class FaunaTemplateTest { @@ -63,16 +62,4 @@ void testTemplates_WithEscapes() { assertEquals(TemplatePartType.LITERAL, expanded.get(1).getType()); } - @Test - void testTemplates_WithUnsupportedIdentifiers() { - FaunaTemplate template = new FaunaTemplate("let x = ${かわいい}"); - Exception exception = assertThrows(IllegalArgumentException.class, () -> { - List expanded = new ArrayList<>(); - template.forEach(expanded::add); - }); - String expectedMessage = "Invalid placeholder in template: line 1, col 9"; - String actualMessage = exception.getMessage(); - assertTrue(actualMessage.contains(expectedMessage)); - } - } \ No newline at end of file diff --git a/faunaJava/src/test/java/com/fauna/serialization/FaunaParserTest.java b/faunaJava/src/test/java/com/fauna/serialization/FaunaParserTest.java index d2ba8acd..eba77d26 100644 --- a/faunaJava/src/test/java/com/fauna/serialization/FaunaParserTest.java +++ b/faunaJava/src/test/java/com/fauna/serialization/FaunaParserTest.java @@ -4,8 +4,10 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import com.fauna.common.enums.FaunaTokenType; +import com.fauna.exception.SerializationException; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -28,19 +30,51 @@ public void testGetValueAsString() throws IOException { assertReader(reader, expectedTokens); } + @Test + public void testGetValueAsInt() throws IOException { + String s = "{\"@int\": \"123\"}"; + InputStream inputStream = new ByteArrayInputStream(s.getBytes()); + FaunaParser reader = new FaunaParser(inputStream); + + List> expectedTokens = List.of( + Map.entry(FaunaTokenType.INT, 123) + ); + + assertReader(reader, expectedTokens); + + String invalidJson = "{\"@int\": \"abc\"}"; + InputStream invalidInputStream = new ByteArrayInputStream(invalidJson.getBytes()); + FaunaParser invalidReader = new FaunaParser(invalidInputStream); + + assertThrows(RuntimeException.class, invalidReader::getValueAsInt); + } + + @Test + public void testUnexpectedEndDuringAdvance() throws IOException { + + String json = "{\"@int\": \"123\""; + InputStream inputStream = new ByteArrayInputStream(json.getBytes()); + FaunaParser reader = new FaunaParser(inputStream); + + assertThrows(SerializationException.class, reader::read); + } + private static void assertReader(FaunaParser reader, - List> tokens) { + List> tokens) throws IOException { for (Map.Entry entry : tokens) { reader.read(); assertNotNull(entry.getKey()); assertNotNull(reader.getCurrentTokenType()); - assertEquals(entry.getKey(), FaunaTokenType.STRING); + assertEquals(entry.getKey(), reader.getCurrentTokenType()); switch (entry.getKey()) { case FIELD_NAME: case STRING: assertEquals(entry.getValue(), reader.getValueAsString()); break; + case INT: + assertEquals(entry.getValue(), reader.getValueAsInt()); + break; default: assertNull(entry.getValue() == null); break;