From f63a1b85aec695f4d464e07a5c13fc038d581527 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Wed, 14 Dec 2022 17:33:33 +0100 Subject: [PATCH] Remove EOFException special casing of JsonStreamParser.next() (#2281) * Remove EOFException special casing of JsonStreamParser.next() The previous behavior violated the Iterator contract where for `JsonStreamParser("[")` a call to `hasNext()` would return true, but `next()` would throw a NoSuchElementException. * Fix incorrect documented thrown exception type for JsonStreamParser --- .../com/google/gson/JsonStreamParser.java | 22 +++--- .../com/google/gson/JsonStreamParserTest.java | 74 ++++++++++++++++--- 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/gson/src/main/java/com/google/gson/JsonStreamParser.java b/gson/src/main/java/com/google/gson/JsonStreamParser.java index 27597da652..2bd86ac59b 100644 --- a/gson/src/main/java/com/google/gson/JsonStreamParser.java +++ b/gson/src/main/java/com/google/gson/JsonStreamParser.java @@ -15,18 +15,16 @@ */ package com.google.gson; -import java.io.EOFException; +import com.google.gson.internal.Streams; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.MalformedJsonException; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.Iterator; import java.util.NoSuchElementException; -import com.google.gson.internal.Streams; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.MalformedJsonException; - /** * A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader * asynchronously. The JSON data is parsed in lenient mode, see also @@ -61,7 +59,7 @@ public final class JsonStreamParser implements Iterator { public JsonStreamParser(String json) { this(new StringReader(json)); } - + /** * @param reader The data stream containing JSON elements concatenated to each other. * @since 1.4 @@ -71,13 +69,13 @@ public JsonStreamParser(Reader reader) { parser.setLenient(true); lock = new Object(); } - + /** * Returns the next available {@link JsonElement} on the reader. Throws a * {@link NoSuchElementException} if no element is available. * * @return the next available {@code JsonElement} on the reader. - * @throws JsonSyntaxException if the incoming stream is malformed JSON. + * @throws JsonParseException if the incoming stream is malformed JSON. * @throws NoSuchElementException if no {@code JsonElement} is available. * @since 1.4 */ @@ -86,22 +84,20 @@ public JsonElement next() throws JsonParseException { if (!hasNext()) { throw new NoSuchElementException(); } - + try { return Streams.parse(parser); } catch (StackOverflowError e) { throw new JsonParseException("Failed parsing JSON source to Json", e); } catch (OutOfMemoryError e) { throw new JsonParseException("Failed parsing JSON source to Json", e); - } catch (JsonParseException e) { - throw e.getCause() instanceof EOFException ? new NoSuchElementException() : e; } } /** * Returns true if a {@link JsonElement} is available on the input for consumption * @return true if a {@link JsonElement} is available on the input, false otherwise - * @throws JsonSyntaxException if the incoming stream is malformed JSON. + * @throws JsonParseException if the incoming stream is malformed JSON. * @since 1.4 */ @Override diff --git a/gson/src/test/java/com/google/gson/JsonStreamParserTest.java b/gson/src/test/java/com/google/gson/JsonStreamParserTest.java index 1b40b58b6f..402b98b432 100644 --- a/gson/src/test/java/com/google/gson/JsonStreamParserTest.java +++ b/gson/src/test/java/com/google/gson/JsonStreamParserTest.java @@ -15,24 +15,30 @@ */ package com.google.gson; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import java.io.EOFException; import java.util.NoSuchElementException; +import org.junit.Before; +import org.junit.Test; /** * Unit tests for {@link JsonStreamParser} - * + * * @author Inderjeet Singh */ -public class JsonStreamParserTest extends TestCase { +public class JsonStreamParserTest { private JsonStreamParser parser; - - @Override - protected void setUp() throws Exception { - super.setUp(); + + @Before + public void setUp() throws Exception { parser = new JsonStreamParser("'one' 'two'"); } + @Test public void testParseTwoStrings() { String actualOne = parser.next().getAsString(); assertEquals("one", actualOne); @@ -40,6 +46,7 @@ public void testParseTwoStrings() { assertEquals("two", actualTwo); } + @Test public void testIterator() { assertTrue(parser.hasNext()); assertEquals("one", parser.next().getAsString()); @@ -48,20 +55,22 @@ public void testIterator() { assertFalse(parser.hasNext()); } + @Test public void testNoSideEffectForHasNext() throws Exception { assertTrue(parser.hasNext()); assertTrue(parser.hasNext()); assertTrue(parser.hasNext()); assertEquals("one", parser.next().getAsString()); - + assertTrue(parser.hasNext()); assertTrue(parser.hasNext()); assertEquals("two", parser.next().getAsString()); - + assertFalse(parser.hasNext()); assertFalse(parser.hasNext()); } + @Test public void testCallingNextBeyondAvailableInput() { parser.next(); parser.next(); @@ -71,4 +80,51 @@ public void testCallingNextBeyondAvailableInput() { } catch (NoSuchElementException expected) { } } + + @Test + public void testEmptyInput() { + JsonStreamParser parser = new JsonStreamParser(""); + try { + parser.next(); + fail(); + } catch (JsonIOException e) { + assertTrue(e.getCause() instanceof EOFException); + } + + parser = new JsonStreamParser(""); + try { + parser.hasNext(); + fail(); + } catch (JsonIOException e) { + assertTrue(e.getCause() instanceof EOFException); + } + } + + @Test + public void testIncompleteInput() { + JsonStreamParser parser = new JsonStreamParser("["); + assertTrue(parser.hasNext()); + try { + parser.next(); + fail(); + } catch (JsonSyntaxException e) { + } + } + + @Test + public void testMalformedInput() { + JsonStreamParser parser = new JsonStreamParser(":"); + try { + parser.hasNext(); + fail(); + } catch (JsonSyntaxException e) { + } + + parser = new JsonStreamParser(":"); + try { + parser.next(); + fail(); + } catch (JsonSyntaxException e) { + } + } }