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:
parent
6c3cf22435
commit
f63a1b85ae
@ -15,18 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.gson;
|
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.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.NoSuchElementException;
|
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
|
* 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
|
* 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) {
|
public JsonStreamParser(String json) {
|
||||||
this(new StringReader(json));
|
this(new StringReader(json));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param reader The data stream containing JSON elements concatenated to each other.
|
* @param reader The data stream containing JSON elements concatenated to each other.
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
@ -71,13 +69,13 @@ public final class JsonStreamParser implements Iterator<JsonElement> {
|
|||||||
parser.setLenient(true);
|
parser.setLenient(true);
|
||||||
lock = new Object();
|
lock = new Object();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the next available {@link JsonElement} on the reader. Throws a
|
* Returns the next available {@link JsonElement} on the reader. Throws a
|
||||||
* {@link NoSuchElementException} if no element is available.
|
* {@link NoSuchElementException} if no element is available.
|
||||||
*
|
*
|
||||||
* @return the next available {@code JsonElement} on the reader.
|
* @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.
|
* @throws NoSuchElementException if no {@code JsonElement} is available.
|
||||||
* @since 1.4
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
@ -86,22 +84,20 @@ public final class JsonStreamParser implements Iterator<JsonElement> {
|
|||||||
if (!hasNext()) {
|
if (!hasNext()) {
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return Streams.parse(parser);
|
return Streams.parse(parser);
|
||||||
} catch (StackOverflowError e) {
|
} catch (StackOverflowError e) {
|
||||||
throw new JsonParseException("Failed parsing JSON source to Json", e);
|
throw new JsonParseException("Failed parsing JSON source to Json", e);
|
||||||
} catch (OutOfMemoryError e) {
|
} catch (OutOfMemoryError e) {
|
||||||
throw new JsonParseException("Failed parsing JSON source to Json", 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
|
* 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
|
* @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
|
* @since 1.4
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@ -15,24 +15,30 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.gson;
|
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 java.util.NoSuchElementException;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link JsonStreamParser}
|
* Unit tests for {@link JsonStreamParser}
|
||||||
*
|
*
|
||||||
* @author Inderjeet Singh
|
* @author Inderjeet Singh
|
||||||
*/
|
*/
|
||||||
public class JsonStreamParserTest extends TestCase {
|
public class JsonStreamParserTest {
|
||||||
private JsonStreamParser parser;
|
private JsonStreamParser parser;
|
||||||
|
|
||||||
@Override
|
@Before
|
||||||
protected void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
|
||||||
parser = new JsonStreamParser("'one' 'two'");
|
parser = new JsonStreamParser("'one' 'two'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testParseTwoStrings() {
|
public void testParseTwoStrings() {
|
||||||
String actualOne = parser.next().getAsString();
|
String actualOne = parser.next().getAsString();
|
||||||
assertEquals("one", actualOne);
|
assertEquals("one", actualOne);
|
||||||
@ -40,6 +46,7 @@ public class JsonStreamParserTest extends TestCase {
|
|||||||
assertEquals("two", actualTwo);
|
assertEquals("two", actualTwo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testIterator() {
|
public void testIterator() {
|
||||||
assertTrue(parser.hasNext());
|
assertTrue(parser.hasNext());
|
||||||
assertEquals("one", parser.next().getAsString());
|
assertEquals("one", parser.next().getAsString());
|
||||||
@ -48,20 +55,22 @@ public class JsonStreamParserTest extends TestCase {
|
|||||||
assertFalse(parser.hasNext());
|
assertFalse(parser.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testNoSideEffectForHasNext() throws Exception {
|
public void testNoSideEffectForHasNext() throws Exception {
|
||||||
assertTrue(parser.hasNext());
|
assertTrue(parser.hasNext());
|
||||||
assertTrue(parser.hasNext());
|
assertTrue(parser.hasNext());
|
||||||
assertTrue(parser.hasNext());
|
assertTrue(parser.hasNext());
|
||||||
assertEquals("one", parser.next().getAsString());
|
assertEquals("one", parser.next().getAsString());
|
||||||
|
|
||||||
assertTrue(parser.hasNext());
|
assertTrue(parser.hasNext());
|
||||||
assertTrue(parser.hasNext());
|
assertTrue(parser.hasNext());
|
||||||
assertEquals("two", parser.next().getAsString());
|
assertEquals("two", parser.next().getAsString());
|
||||||
|
|
||||||
assertFalse(parser.hasNext());
|
assertFalse(parser.hasNext());
|
||||||
assertFalse(parser.hasNext());
|
assertFalse(parser.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testCallingNextBeyondAvailableInput() {
|
public void testCallingNextBeyondAvailableInput() {
|
||||||
parser.next();
|
parser.next();
|
||||||
parser.next();
|
parser.next();
|
||||||
@ -71,4 +80,51 @@ public class JsonStreamParserTest extends TestCase {
|
|||||||
} catch (NoSuchElementException expected) {
|
} 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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user