diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2907a20 --- /dev/null +++ b/pom.xml @@ -0,0 +1,87 @@ + + 4.0.0 + + JsonToy2 + + + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + + + nl.sander + jsontoy2 + 0.1-SNAPSHOT + jar + + + 1.8 + 1.8 + UTF-8 + + + + + commons-io + commons-io + 2.6 + + + + org.javassist + javassist + 3.26.0-GA + + + + ch.qos.logback + logback-core + 1.2.3 + + + + org.slf4j + slf4j-api + 1.7.30 + + + + ch.qos.logback + logback-classic + 1.2.3 + + + + + junit + junit + 4.13 + test + + + org.assertj + assertj-core + 1.6.0 + test + + + org.mockito + mockito-all + 1.10.19 + test + + + + com.fasterxml.jackson.core + jackson-databind + 2.10.3 + test + + + diff --git a/src/main/java/nl/sander/jsontoy2/IoReader.java b/src/main/java/nl/sander/jsontoy2/IoReader.java index 69a412e..4fa4f23 100644 --- a/src/main/java/nl/sander/jsontoy2/IoReader.java +++ b/src/main/java/nl/sander/jsontoy2/IoReader.java @@ -16,7 +16,6 @@ public class IoReader { private boolean encoded = false; private byte current; private int linecount = 0; - private long charcount = 0; protected IoReader(InputStream inputStream) { this.inputStream = inputStream; @@ -93,11 +92,11 @@ public class IoReader { } public List readList() { - List list = new ArrayList<>(); - + skipWhitespace(); if (current != '[') { throw new JsonReadException("no list found"); } + List list = new ArrayList<>(); advance(); while (current != -1 && current != ']') { Optional maybeValue = readValue(); @@ -105,17 +104,39 @@ public class IoReader { break; } else { list.add(maybeValue.get()); - eatUntilAny(','); + eatUntil(','); } } return list; } + public Map readMap() { + HashMap map = new HashMap<>(); + skipWhitespace(); + if (current != '{') { + throw new JsonReadException("no map found"); + } + while (current != -1 && current != '}') { + skipWhitespace(); + if (current == '"') { + String key = readString(); + eatUntil(':'); + skipWhitespace(); + Optional maybeValue = readValue(); + maybeValue.ifPresent(o -> map.put(key, o)); + eatUntil(','); + } else { + advance(); + } + } + return map; + } + private Optional readValue() { Object value; skipWhitespace(); - if (current == ']') { + if (current == ']' || current == '}') { return Optional.empty(); } else if (current == '[') { value = readList(); @@ -137,10 +158,6 @@ public class IoReader { return Optional.of(value); } - private Map readMap() { - return new HashMap<>(); - } - public String readString() { eatUntil('\"'); @@ -158,7 +175,7 @@ public class IoReader { endOfString = true; } } else { - // json encoded string + // unicode codepoint if (current == 'u') { encoded = true; } else if (current == 'n') { @@ -172,7 +189,7 @@ public class IoReader { throw new JsonReadException("illegal escaped quote in line " + linecount); } else { if (encoded) { - // load next 4 characters in special buffer + // load next 4 characters in special buffer to convert to int encodedCodePointBuffer.add(current); if (encodedCodePointBuffer.length() == 4) { byte[] bytes = parseCodePoint(); @@ -201,7 +218,6 @@ public class IoReader { void advance() { try { current = (byte) inputStream.read(); - System.out.println((charcount++) + ":" + (char) current); } catch (IOException e) { throw new IllegalStateException(e); } @@ -230,24 +246,4 @@ public class IoReader { advance(); return characterBuffer.toString(); } - - String eatUntilAny(char... untilOrrChars) { - characterBuffer.clear(); - - while (current > -1 && (!contains(untilOrrChars, current) | Character.isWhitespace(current))) { - characterBuffer.add(current); - advance(); - } - advance(); - return characterBuffer.toString(); - } - - private boolean contains(char[] chars, byte search) { - for (char aChar : chars) { - if (search == aChar) { - return true; - } - } - return false; - } } diff --git a/src/main/java/nl/sander/jsontoy2/JsonReader.java b/src/main/java/nl/sander/jsontoy2/JsonReader.java index 0e306eb..f2aeae6 100644 --- a/src/main/java/nl/sander/jsontoy2/JsonReader.java +++ b/src/main/java/nl/sander/jsontoy2/JsonReader.java @@ -6,6 +6,7 @@ import java.io.InputStream; import java.time.LocalDateTime; import java.util.Date; import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -13,7 +14,7 @@ import java.util.concurrent.ConcurrentMap; * public facade */ public class JsonReader { - private static final ConcurrentMap, JsonObjectReader> readers = new ConcurrentHashMap<>(); + private static final ConcurrentMap, JsonValueReader> readers = new ConcurrentHashMap<>(); public static T read(Class type, InputStream reader) { return read(type, new IoReader(reader)); @@ -29,11 +30,11 @@ public class JsonReader { // class.cast() does not work for primitives; } - private static JsonObjectReader getReader(Class type) { + private static JsonValueReader getReader(Class type) { return readers.get(type); } - static void register(Class type, JsonObjectReader objectReader) { + static void register(Class type, JsonValueReader objectReader) { readers.put(type, objectReader); } @@ -58,5 +59,6 @@ public class JsonReader { register(String.class, new StringReader()); register(LocalDateTime.class, new LocalDateTimeReader()); register(List.class, new ListReader()); + register(Map.class, new MapReader()); } } diff --git a/src/main/java/nl/sander/jsontoy2/JsonObjectReader.java b/src/main/java/nl/sander/jsontoy2/JsonValueReader.java similarity index 68% rename from src/main/java/nl/sander/jsontoy2/JsonObjectReader.java rename to src/main/java/nl/sander/jsontoy2/JsonValueReader.java index eba65f1..18e2cd7 100644 --- a/src/main/java/nl/sander/jsontoy2/JsonObjectReader.java +++ b/src/main/java/nl/sander/jsontoy2/JsonValueReader.java @@ -2,6 +2,6 @@ package nl.sander.jsontoy2; import java.io.Reader; -public interface JsonObjectReader { +public interface JsonValueReader { T read(IoReader ioReader); } diff --git a/src/main/java/nl/sander/jsontoy2/readers/BooleanReader.java b/src/main/java/nl/sander/jsontoy2/readers/BooleanReader.java index 7e9e846..7b71a53 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/BooleanReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/BooleanReader.java @@ -1,8 +1,9 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; +import nl.sander.jsontoy2.JsonValueReader; -public class BooleanReader implements nl.sander.jsontoy2.JsonObjectReader { +public class BooleanReader implements JsonValueReader { @Override public Boolean read(IoReader ioReader) { return ioReader.readBoolean(); diff --git a/src/main/java/nl/sander/jsontoy2/readers/ByteReader.java b/src/main/java/nl/sander/jsontoy2/readers/ByteReader.java index d62b031..b5c1264 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/ByteReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/ByteReader.java @@ -1,9 +1,9 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; -public class ByteReader implements JsonObjectReader { +public class ByteReader implements JsonValueReader { @Override public Byte read(IoReader ioReader) { return ioReader.readByte(); diff --git a/src/main/java/nl/sander/jsontoy2/readers/CharReader.java b/src/main/java/nl/sander/jsontoy2/readers/CharReader.java index 4f5abd9..081593f 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/CharReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/CharReader.java @@ -1,9 +1,9 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; -public class CharReader implements JsonObjectReader { +public class CharReader implements JsonValueReader { @Override public Character read(IoReader ioReader) { return ioReader.readCharacter(); diff --git a/src/main/java/nl/sander/jsontoy2/readers/DateReader.java b/src/main/java/nl/sander/jsontoy2/readers/DateReader.java index 6c6de0f..1caad35 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/DateReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/DateReader.java @@ -1,17 +1,12 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; -import java.time.LocalDateTime; -import java.time.ZoneId; import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.temporal.ChronoField; import java.util.Date; -public class DateReader extends AbstractDatesReader implements JsonObjectReader { +public class DateReader extends AbstractDatesReader implements JsonValueReader { @Override public Date read(IoReader ioReader) { diff --git a/src/main/java/nl/sander/jsontoy2/readers/DoubleReader.java b/src/main/java/nl/sander/jsontoy2/readers/DoubleReader.java index 14c51d0..ada38c2 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/DoubleReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/DoubleReader.java @@ -1,11 +1,9 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; -import java.io.Reader; - -public class DoubleReader implements JsonObjectReader { +public class DoubleReader implements JsonValueReader { @Override public Double read(IoReader ioReader) { return ioReader.readDouble(); diff --git a/src/main/java/nl/sander/jsontoy2/readers/FloatReader.java b/src/main/java/nl/sander/jsontoy2/readers/FloatReader.java index 889027a..a060397 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/FloatReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/FloatReader.java @@ -1,9 +1,9 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; -public class FloatReader implements JsonObjectReader { +public class FloatReader implements JsonValueReader { @Override public Float read(IoReader ioReader) { return ioReader.readFloat(); diff --git a/src/main/java/nl/sander/jsontoy2/readers/IntegerReader.java b/src/main/java/nl/sander/jsontoy2/readers/IntegerReader.java index 2716b27..f417fc3 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/IntegerReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/IntegerReader.java @@ -1,9 +1,9 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; -public class IntegerReader implements JsonObjectReader { +public class IntegerReader implements JsonValueReader { @Override public Integer read(IoReader ioReader) { return ioReader.readInteger(); diff --git a/src/main/java/nl/sander/jsontoy2/readers/ListReader.java b/src/main/java/nl/sander/jsontoy2/readers/ListReader.java index 419a8bd..e603b3e 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/ListReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/ListReader.java @@ -1,12 +1,12 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; import java.util.List; @SuppressWarnings("rawtypes") -public class ListReader implements JsonObjectReader { +public class ListReader implements JsonValueReader { @Override public List read(IoReader ioReader) { return ioReader.readList(); diff --git a/src/main/java/nl/sander/jsontoy2/readers/LocalDateTimeReader.java b/src/main/java/nl/sander/jsontoy2/readers/LocalDateTimeReader.java index 49366ad..1d07380 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/LocalDateTimeReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/LocalDateTimeReader.java @@ -1,12 +1,12 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; import java.time.LocalDateTime; import java.time.ZonedDateTime; -public class LocalDateTimeReader extends AbstractDatesReader implements JsonObjectReader { +public class LocalDateTimeReader extends AbstractDatesReader implements JsonValueReader { @Override public LocalDateTime read(IoReader ioReader) { diff --git a/src/main/java/nl/sander/jsontoy2/readers/LongReader.java b/src/main/java/nl/sander/jsontoy2/readers/LongReader.java index dac9f43..7192521 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/LongReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/LongReader.java @@ -1,9 +1,9 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; -public class LongReader implements JsonObjectReader { +public class LongReader implements JsonValueReader { @Override public Long read(IoReader ioReader) { return ioReader.readLong(); diff --git a/src/main/java/nl/sander/jsontoy2/readers/MapReader.java b/src/main/java/nl/sander/jsontoy2/readers/MapReader.java new file mode 100644 index 0000000..db7a485 --- /dev/null +++ b/src/main/java/nl/sander/jsontoy2/readers/MapReader.java @@ -0,0 +1,13 @@ +package nl.sander.jsontoy2.readers; + +import nl.sander.jsontoy2.IoReader; +import nl.sander.jsontoy2.JsonValueReader; + +import java.util.Map; + +public class MapReader implements JsonValueReader { + @Override + public Map read(IoReader ioReader) { + return ioReader.readMap(); + } +} diff --git a/src/main/java/nl/sander/jsontoy2/readers/ShortReader.java b/src/main/java/nl/sander/jsontoy2/readers/ShortReader.java index 70c79f8..9bb320e 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/ShortReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/ShortReader.java @@ -1,9 +1,9 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; -public class ShortReader implements JsonObjectReader { +public class ShortReader implements JsonValueReader { @Override public Short read(IoReader ioReader) { diff --git a/src/main/java/nl/sander/jsontoy2/readers/StringReader.java b/src/main/java/nl/sander/jsontoy2/readers/StringReader.java index c5cea13..421f734 100644 --- a/src/main/java/nl/sander/jsontoy2/readers/StringReader.java +++ b/src/main/java/nl/sander/jsontoy2/readers/StringReader.java @@ -1,9 +1,9 @@ package nl.sander.jsontoy2.readers; import nl.sander.jsontoy2.IoReader; -import nl.sander.jsontoy2.JsonObjectReader; +import nl.sander.jsontoy2.JsonValueReader; -public class StringReader implements JsonObjectReader { +public class StringReader implements JsonValueReader { @Override public String read(IoReader ioReader) { diff --git a/src/test/java/nl/sander/jsontoy2/Lists.java b/src/test/java/nl/sander/jsontoy2/Lists.java index cd77529..190c335 100644 --- a/src/test/java/nl/sander/jsontoy2/Lists.java +++ b/src/test/java/nl/sander/jsontoy2/Lists.java @@ -2,10 +2,7 @@ package nl.sander.jsontoy2; import org.junit.jupiter.api.Test; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -15,54 +12,61 @@ public class Lists { @Test public void emptyList() { List list = JsonReader.read(List.class, "[]"); - assertEquals(new ArrayList<>(), list); + assertEquals(List.of(), list); } @Test public void singleStringList() { List list = JsonReader.read(List.class, "[\"hello jason\"]"); - assertEquals(Collections.singletonList("hello jason"), list); + assertEquals(List.of("hello jason"), list); } @Test public void multipleStringList() { List list = JsonReader.read(List.class, "[\"hello\" , \"jason\"]"); - List expected = Arrays.asList("hello", "jason"); + List expected = List.of("hello", "jason"); assertEquals(expected, list); } @Test public void multipleStrings_noComma_error() { - List list = JsonReader.read(List.class, "[\"hello\" \"jason\"]"); - List expected = Collections.singletonList("hello"); + List list = JsonReader.read(List.class, " [\"hello\" \"jason\"]"); + List expected = List.of("hello"); assertEquals(expected, list); } @Test public void singleInt() { - List list = JsonReader.read(List.class, "[1]"); - List expected = Collections.singletonList(1); + List list = JsonReader.read(List.class, " [ 1 ]"); + List expected = List.of(1); assertEquals(expected, list); } @Test public void multipleInts() { List list = JsonReader.read(List.class, "[1,2]"); - List expected = Arrays.asList(1,2); + List expected = List.of(1, 2); assertEquals(expected, list); } @Test public void intDoubleBooleanString() { - List list = JsonReader.read(List.class, "[1,2.5,false,\"hello jason\"]"); - List expected = Arrays.asList(1,2.5,false,"hello jason"); + List list = JsonReader.read(List.class, "[1, 2.5,false, \"hello jason\"]"); + List expected = List.of(1, 2.5, false, "hello jason"); assertEquals(expected, list); } @Test public void nestedList() { List list = JsonReader.read(List.class, "[[],[]]"); - List expected = Arrays.asList(List.of(), List.of()); + List expected = List.of(List.of(), List.of()); + assertEquals(expected, list); + } + + @Test + public void mapInList() { + List list = JsonReader.read(List.class, "[[],{\"list\":[]]}]"); + List expected = List.of(List.of(), Map.of("list",List.of())); assertEquals(expected, list); } } \ No newline at end of file diff --git a/src/test/java/nl/sander/jsontoy2/Maps.java b/src/test/java/nl/sander/jsontoy2/Maps.java new file mode 100644 index 0000000..79fcba1 --- /dev/null +++ b/src/test/java/nl/sander/jsontoy2/Maps.java @@ -0,0 +1,66 @@ +package nl.sander.jsontoy2; + +import org.junit.jupiter.api.Test; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +@SuppressWarnings("unchecked") +public class Maps { + + @Test + public void emptyMap() { + Map map = JsonReader.read(Map.class, "{}"); + assertEquals(new HashMap<>(), map); + } + + @Test + public void singleStringKeyValueMap() { + Map map = JsonReader.read(Map.class, "{\"message\": \"hello jason\"}"); + assertEquals(Collections.singletonMap("message", "hello jason"), map); + } + + @Test + public void multipleValues() { + Map map = JsonReader.read(Map.class, "{\"value1\" : \"jason\" ,\n \"value2\":1}"); + Map expected = new HashMap<>(); + expected.put("value1", "jason"); + expected.put("value2", 1); + assertEquals(expected, map); + } + + @Test + public void multipleStrings_noColon_error() { + assertThrows(JsonReadException.class, () -> JsonReader.read(Map.class, " {\"hello\" \"jason\"}")); + } + + @Test + public void singleInts() { + Map map = JsonReader.read(Map.class, " { \"1\":2 }"); + Map expected = Collections.singletonMap("1",2); + assertEquals(expected, map); + } + + @Test + @SuppressWarnings("raw") + public void nestedMap() { + Map list = JsonReader.read(Map.class, "{\"map\": {\"map\":{}}}"); + Map expected = new HashMap<>(); + HashMap n1 = new HashMap<>(); + n1.put("map",new HashMap<>()); + expected.put("map", n1); + + assertEquals(expected, list); + } + + @Test + public void listInMap(){ + Map list = JsonReader.read(Map.class, " { \"list\" : [ 1 ] } "); + Map expected = new HashMap<>(); + expected.put("list", List.of(1)); + + assertEquals(expected, list); + } +} \ No newline at end of file diff --git a/src/test/java/nl/sander/jsontoy2/Strings.java b/src/test/java/nl/sander/jsontoy2/Strings.java index e16f694..2db72ed 100644 --- a/src/test/java/nl/sander/jsontoy2/Strings.java +++ b/src/test/java/nl/sander/jsontoy2/Strings.java @@ -2,12 +2,7 @@ package nl.sander.jsontoy2; import org.junit.jupiter.api.Test; -import java.lang.reflect.Field; -import java.nio.ByteBuffer; import java.nio.charset.CharacterCodingException; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CodingErrorAction; -import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -29,7 +24,7 @@ public class Strings { @Test public void incompleteSurrogateAndEscapeValid() { - String value = JsonReader.read(String.class, "\"\\uD800\n\""); + String value = JsonReader.read(String.class, " \"\\uD800\n\""); assertEquals("\u0000\u0000�\u0000\n", value); } @@ -37,18 +32,18 @@ public class Strings { public void firstValidSurrogateSecondInvalid() throws CharacterCodingException { String value = JsonReader.read(String.class, "\"\\uD888\\u1334\""); - assertEquals("\u0000\u0000؈\u0000\u0000\u00134",value); + assertEquals("\u0000\u0000؈\u0000\u0000\u00134", value); } @Test public void escapedDoubleQuote() { - String value = JsonReader.read(String.class, "\"\\\"\""); + String value = JsonReader.read(String.class, " \"\\\"\""); assertEquals("\"", value); } @Test public void escapedSingleQuote() { - assertThrows(JsonReadException.class, () -> JsonReader.read(String.class, "\"\\\'\"")); + assertThrows(JsonReadException.class, () -> JsonReader.read(String.class, "\"\\'\"")); } } diff --git a/src/test/java/nl/sander/jsontoy2/StringsWithJackson.java b/src/test/java/nl/sander/jsontoy2/StringsWithJackson.java new file mode 100644 index 0000000..f798ebe --- /dev/null +++ b/src/test/java/nl/sander/jsontoy2/StringsWithJackson.java @@ -0,0 +1,51 @@ +package nl.sander.jsontoy2; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; + +import java.nio.charset.CharacterCodingException; + +import static org.junit.jupiter.api.Assertions.*; + +public class StringsWithJackson { + + ObjectMapper jackson = new ObjectMapper(); + + @Test + public void regular() throws JsonProcessingException { + assertEquals("DADA", jackson.readValue("\"DADA\"", String.class)); + } + + @Test + public void firstSurrogateButSecondMissing() throws NoSuchFieldException, IllegalAccessException, JsonProcessingException { + String value =jackson.readValue("\"\\uDADA\"", String.class); + + assertTrue(true); + } + + + @Test + public void incompleteSurrogateAndEscapeValid() throws JsonProcessingException { + assertThrows(JsonParseException.class, () -> jackson.readValue("\"\\uD800\n\"", String.class)); + } + + @Test + public void firstValidSurrogateSecondInvalid() throws JsonProcessingException { + String value =jackson.readValue("\"\\uD888\\u1334\"", String.class); + assertTrue(true); + } + + @Test + public void escapedDoubleQuote() throws JsonProcessingException { + String value =jackson.readValue("\"\\\"\"", String.class); + assertEquals("\"", value); + } + + @Test + public void escapedSingleQuote() { + assertThrows(JsonParseException.class, () -> jackson.readValue("\"\\'\"", String.class)); + } + +}