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
This commit is contained in:
Marcono1234 2022-12-14 17:33:33 +01:00 committed by GitHub
parent 6c3cf22435
commit f63a1b85ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 22 deletions

View File

@ -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<JsonElement> {
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 final class JsonStreamParser implements Iterator<JsonElement> {
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 final class JsonStreamParser implements Iterator<JsonElement> {
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

View File

@ -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 class JsonStreamParserTest extends TestCase {
assertEquals("two", actualTwo);
}
@Test
public void testIterator() {
assertTrue(parser.hasNext());
assertEquals("one", parser.next().getAsString());
@ -48,20 +55,22 @@ public class JsonStreamParserTest extends TestCase {
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 class JsonStreamParserTest extends TestCase {
} 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) {
}
}
}