From e9f73cd652bef7319896aa4da8f729d5c22d8bd7 Mon Sep 17 00:00:00 2001 From: Eric Cochran Date: Wed, 8 May 2024 05:50:45 -0400 Subject: [PATCH 1/2] Ignore JSON object trailing comma in lenient JsonUtf8Reader. Unchanged behavior: Lenient readers treat empty values in JSON arrays as the null value. --- .../java/com/squareup/moshi/JsonUtf8Reader.kt | 12 ++-- .../squareup/moshi/JsonUtf8ReaderTest.java | 57 ++++++++++++++----- 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.kt b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.kt index 6edc159e3..7531b8c3b 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.kt +++ b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.kt @@ -197,11 +197,14 @@ internal class JsonUtf8Reader : JsonReader { PEEKED_SINGLE_QUOTED_NAME } - '}' -> if (peekStack != JsonScope.NONEMPTY_OBJECT) { + '}' -> { + if (peekStack == JsonScope.NONEMPTY_OBJECT && !lenient) { + throw syntaxError( + "Expected name. Use JsonReader.setLenient(true) to accept malformed JSON" + ) + } buffer.readByte() // consume the '}'. PEEKED_END_OBJECT - } else { - throw syntaxError("Expected name") } else -> { @@ -213,8 +216,7 @@ internal class JsonUtf8Reader : JsonReader { } } } - peeked = next - return next + return setPeeked(next) } JsonScope.DANGLING_NAME -> { diff --git a/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java b/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java index 551f3b73a..dc34553ff 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java @@ -1260,20 +1260,6 @@ public void strictExtraCommasInMaps() throws IOException { } } - @Test - public void lenientExtraCommasInMaps() throws IOException { - JsonReader reader = newReader("{\"a\":\"b\",}"); - reader.setLenient(true); - reader.beginObject(); - assertThat(reader.nextName()).isEqualTo("a"); - assertThat(reader.nextString()).isEqualTo("b"); - try { - reader.peek(); - fail(); - } catch (JsonEncodingException expected) { - } - } - @Test public void malformedDocuments() throws IOException { assertDocument("{]", BEGIN_OBJECT, JsonEncodingException.class); @@ -1356,6 +1342,49 @@ public void lenientInvalidEscape() throws IOException { assertThat(reader.nextString()).isEqualTo("string"); } + @Test + public void trailingCommaInJsonObject() throws Exception { + JsonReader reader = newReader("{\"a\":1,}"); + reader.beginObject(); + assertThat(reader.nextName()).isEqualTo("a"); + assertThat(reader.nextInt()).isEqualTo(1); + try { + reader.endObject(); + fail(); + } catch (JsonEncodingException expected) { + assertThat(expected.getMessage()).isEqualTo( + "Expected name. Use JsonReader.setLenient(true) to accept malformed JSON at path $.a"); + } + reader = newReader("{\"a\": 1, }"); + reader.beginObject(); + assertThat(reader.nextName()).isEqualTo("a"); + assertThat(reader.nextInt()).isEqualTo(1); + reader.setLenient(true); + reader.endObject(); + assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); + } + + @Test + public void trailingCommaInJsonArray() throws Exception { + JsonReader reader = newReader("[1, ]"); + reader.beginArray(); + assertThat(reader.nextInt()).isEqualTo(1); + try { + reader.endArray(); + fail(); + } catch (JsonEncodingException expected) { + assertThat(expected.getMessage()) + .isEqualTo("Use JsonReader.setLenient(true) to accept malformed JSON at path $[1]"); + } + reader = newReader("[1,]"); + reader.beginArray(); + assertThat(reader.nextInt()).isEqualTo(1); + reader.setLenient(true); + reader.nextNull(); + reader.endArray(); + assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT); + } + private void assertDocument(String document, Object... expectations) throws IOException { JsonReader reader = newReader(document); reader.setLenient(true); From 34d41b7e4dd8659718dfb7c38d9daf06d0e47818 Mon Sep 17 00:00:00 2001 From: Eric Cochran Date: Wed, 8 May 2024 08:31:12 -0400 Subject: [PATCH 2/2] Fix style --- moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.kt | 3 ++- .../test/java/com/squareup/moshi/JsonUtf8ReaderTest.java | 8 +++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.kt b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.kt index 7531b8c3b..05b106608 100644 --- a/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.kt +++ b/moshi/src/main/java/com/squareup/moshi/JsonUtf8Reader.kt @@ -200,7 +200,8 @@ internal class JsonUtf8Reader : JsonReader { '}' -> { if (peekStack == JsonScope.NONEMPTY_OBJECT && !lenient) { throw syntaxError( - "Expected name. Use JsonReader.setLenient(true) to accept malformed JSON" + "Expected name. Use JsonReader.setLenient(true) to accept " + + "malformed JSON", ) } buffer.readByte() // consume the '}'. diff --git a/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java b/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java index dc34553ff..3205ab381 100644 --- a/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java +++ b/moshi/src/test/java/com/squareup/moshi/JsonUtf8ReaderTest.java @@ -1352,8 +1352,10 @@ public void trailingCommaInJsonObject() throws Exception { reader.endObject(); fail(); } catch (JsonEncodingException expected) { - assertThat(expected.getMessage()).isEqualTo( - "Expected name. Use JsonReader.setLenient(true) to accept malformed JSON at path $.a"); + assertThat(expected.getMessage()) + .isEqualTo( + "Expected name. Use JsonReader.setLenient(true) to accept malformed " + + "JSON at path $.a"); } reader = newReader("{\"a\": 1, }"); reader.beginObject(); @@ -1374,7 +1376,7 @@ public void trailingCommaInJsonArray() throws Exception { fail(); } catch (JsonEncodingException expected) { assertThat(expected.getMessage()) - .isEqualTo("Use JsonReader.setLenient(true) to accept malformed JSON at path $[1]"); + .isEqualTo("Use JsonReader.setLenient(true) to accept malformed JSON at path $[1]"); } reader = newReader("[1,]"); reader.beginArray();