Permit multiple top-level values in JsonWriter in lenient mode. Also fix some cases where we don't throw the right thing on a closed JsonWriter.
I'd prefer to not support multiple top-level values, but we support it in JsonReader and it's easier to be consistent. Kevin Hayen's patch pointed me in the right direction here, but I needed to do more work to cover some of the edge cases. Fixes issue 397.
This commit is contained in:
parent
5c978948a0
commit
2c8bec27d4
|
@ -314,7 +314,11 @@ public class JsonWriter implements Closeable {
|
||||||
* Returns the value on the top of the stack.
|
* Returns the value on the top of the stack.
|
||||||
*/
|
*/
|
||||||
private JsonScope peek() {
|
private JsonScope peek() {
|
||||||
return stack.get(stack.size() - 1);
|
int size = stack.size();
|
||||||
|
if (size == 0) {
|
||||||
|
throw new IllegalStateException("JsonWriter is closed.");
|
||||||
|
}
|
||||||
|
return stack.get(size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -337,6 +341,9 @@ public class JsonWriter implements Closeable {
|
||||||
if (deferredName != null) {
|
if (deferredName != null) {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
throw new IllegalStateException("JsonWriter is closed.");
|
||||||
|
}
|
||||||
deferredName = name;
|
deferredName = name;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -453,6 +460,9 @@ public class JsonWriter implements Closeable {
|
||||||
* and flushes that writer.
|
* and flushes that writer.
|
||||||
*/
|
*/
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
throw new IllegalStateException("JsonWriter is closed.");
|
||||||
|
}
|
||||||
out.flush();
|
out.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,9 +474,11 @@ public class JsonWriter implements Closeable {
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
out.close();
|
out.close();
|
||||||
|
|
||||||
if (peek() != JsonScope.NONEMPTY_DOCUMENT) {
|
int size = stack.size();
|
||||||
|
if (size > 1 || size == 1 && stack.get(size - 1) != JsonScope.NONEMPTY_DOCUMENT) {
|
||||||
throw new IOException("Incomplete document");
|
throw new IOException("Incomplete document");
|
||||||
}
|
}
|
||||||
|
stack.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void string(String value) throws IOException {
|
private void string(String value) throws IOException {
|
||||||
|
@ -574,8 +586,15 @@ public class JsonWriter implements Closeable {
|
||||||
* @param root true if the value is a new array or object, the two values
|
* @param root true if the value is a new array or object, the two values
|
||||||
* permitted as top-level elements.
|
* permitted as top-level elements.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("fallthrough")
|
||||||
private void beforeValue(boolean root) throws IOException {
|
private void beforeValue(boolean root) throws IOException {
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
|
case NONEMPTY_DOCUMENT:
|
||||||
|
if (!lenient) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"JSON must have only one top-level value.");
|
||||||
|
}
|
||||||
|
// fall-through
|
||||||
case EMPTY_DOCUMENT: // first in document
|
case EMPTY_DOCUMENT: // first in document
|
||||||
if (!lenient && !root) {
|
if (!lenient && !root) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
@ -599,10 +618,6 @@ public class JsonWriter implements Closeable {
|
||||||
replaceTop(JsonScope.NONEMPTY_OBJECT);
|
replaceTop(JsonScope.NONEMPTY_OBJECT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NONEMPTY_DOCUMENT:
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"JSON must have only one top-level value.");
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Nesting problem: " + stack);
|
throw new IllegalStateException("Nesting problem: " + stack);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,11 @@
|
||||||
|
|
||||||
package com.google.gson.stream;
|
package com.google.gson.stream;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
public final class JsonWriterTest extends TestCase {
|
public final class JsonWriterTest extends TestCase {
|
||||||
|
|
||||||
|
@ -464,4 +463,104 @@ public final class JsonWriterTest extends TestCase {
|
||||||
+ "]";
|
+ "]";
|
||||||
assertEquals(expected, stringWriter.toString());
|
assertEquals(expected, stringWriter.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testLenientWriterPermitsMultipleTopLevelValues() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
JsonWriter writer = new JsonWriter(stringWriter);
|
||||||
|
writer.setLenient(true);
|
||||||
|
writer.beginArray();
|
||||||
|
writer.endArray();
|
||||||
|
writer.beginArray();
|
||||||
|
writer.endArray();
|
||||||
|
writer.close();
|
||||||
|
assertEquals("[][]", stringWriter.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testStrictWriterDoesNotPermitMultipleTopLevelValues() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
JsonWriter writer = new JsonWriter(stringWriter);
|
||||||
|
writer.beginArray();
|
||||||
|
writer.endArray();
|
||||||
|
try {
|
||||||
|
writer.beginArray();
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClosedWriterThrowsOnStructure() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
JsonWriter writer = new JsonWriter(stringWriter);
|
||||||
|
writer.beginArray();
|
||||||
|
writer.endArray();
|
||||||
|
writer.close();
|
||||||
|
try {
|
||||||
|
writer.beginArray();
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
writer.endArray();
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
writer.beginObject();
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
writer.endObject();
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClosedWriterThrowsOnName() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
JsonWriter writer = new JsonWriter(stringWriter);
|
||||||
|
writer.beginArray();
|
||||||
|
writer.endArray();
|
||||||
|
writer.close();
|
||||||
|
try {
|
||||||
|
writer.name("a");
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClosedWriterThrowsOnValue() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
JsonWriter writer = new JsonWriter(stringWriter);
|
||||||
|
writer.beginArray();
|
||||||
|
writer.endArray();
|
||||||
|
writer.close();
|
||||||
|
try {
|
||||||
|
writer.value("a");
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClosedWriterThrowsOnFlush() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
JsonWriter writer = new JsonWriter(stringWriter);
|
||||||
|
writer.beginArray();
|
||||||
|
writer.endArray();
|
||||||
|
writer.close();
|
||||||
|
try {
|
||||||
|
writer.flush();
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWriterCloseIsIdempotent() throws IOException {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
JsonWriter writer = new JsonWriter(stringWriter);
|
||||||
|
writer.beginArray();
|
||||||
|
writer.endArray();
|
||||||
|
writer.close();
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user