diff --git a/moshi/src/main/java/com/squareup/moshi/JsonReader.java b/moshi/src/main/java/com/squareup/moshi/JsonReader.java
index 3f70b6b..d26d563 100644
--- a/moshi/src/main/java/com/squareup/moshi/JsonReader.java
+++ b/moshi/src/main/java/com/squareup/moshi/JsonReader.java
@@ -23,7 +23,7 @@ import okio.BufferedSource;
import okio.ByteString;
/**
- * Reads a JSON (RFC 4627)
+ * Reads a JSON (RFC 7159)
* encoded value as a stream of tokens. This stream includes both literal
* values (strings, numbers, booleans, and nulls) as well as the begin and
* end delimiters of objects and arrays. The tokens are traversed in
@@ -272,7 +272,7 @@ public class JsonReader implements Closeable {
/**
* Configure this parser to be liberal in what it accepts. By default
* this parser is strict and only accepts JSON as specified by RFC 4627. Setting the
+ * href="http://www.ietf.org/rfc/rfc7159.txt">RFC 7159. Setting the
* parser to lenient causes it to ignore the following syntax errors:
*
*
@@ -568,9 +568,6 @@ public class JsonReader implements Closeable {
buffer.readByte(); // Consume '\''.
return peeked = PEEKED_SINGLE_QUOTED;
case '"':
- if (stackSize == 1) {
- checkLenient();
- }
buffer.readByte(); // Consume '\"'.
return peeked = PEEKED_DOUBLE_QUOTED;
case '[':
@@ -582,10 +579,6 @@ public class JsonReader implements Closeable {
default:
}
- if (stackSize == 1) {
- checkLenient(); // Top-level value isn't an array or an object.
- }
-
int result = peekKeyword();
if (result != PEEKED_NONE) {
return result;
diff --git a/moshi/src/main/java/com/squareup/moshi/JsonWriter.java b/moshi/src/main/java/com/squareup/moshi/JsonWriter.java
index b67903c..5eba247 100644
--- a/moshi/src/main/java/com/squareup/moshi/JsonWriter.java
+++ b/moshi/src/main/java/com/squareup/moshi/JsonWriter.java
@@ -30,7 +30,7 @@ import static com.squareup.moshi.JsonScope.NONEMPTY_DOCUMENT;
import static com.squareup.moshi.JsonScope.NONEMPTY_OBJECT;
/**
- * Writes a JSON (RFC 4627)
+ * Writes a JSON (RFC 7159)
* encoded value to a stream, one token at a time. The stream includes both
* literal values (strings, numbers, booleans and nulls) as well as the begin
* and end delimiters of objects and arrays.
@@ -127,7 +127,7 @@ import static com.squareup.moshi.JsonScope.NONEMPTY_OBJECT;
public class JsonWriter implements Closeable, Flushable {
/*
- * From RFC 4627, "All Unicode characters may be placed within the
+ * From RFC 7159, "All Unicode characters may be placed within the
* quotation marks except for the characters that must be escaped:
* quotation mark, reverse solidus, and the control characters
* (U+0000 through U+001F)."
@@ -217,7 +217,7 @@ public class JsonWriter implements Closeable, Flushable {
/**
* Configure this writer to relax its syntax rules. By default, this writer
* only emits well-formed JSON as specified by RFC 4627. Setting the writer
+ * href="http://www.ietf.org/rfc/rfc7159.txt">RFC 7159. Setting the writer
* to lenient permits the following:
*
* - Top-level values of any type. With strict writing, the top-level
@@ -299,7 +299,7 @@ public class JsonWriter implements Closeable, Flushable {
* bracket.
*/
private JsonWriter open(int empty, String openBracket) throws IOException {
- beforeValue(true);
+ beforeValue();
pathIndices[stackSize] = 0;
push(empty);
sink.writeUtf8(openBracket);
@@ -400,7 +400,7 @@ public class JsonWriter implements Closeable, Flushable {
return name(value);
}
writeDeferredName();
- beforeValue(false);
+ beforeValue();
string(value);
pathIndices[stackSize - 1]++;
return this;
@@ -420,7 +420,7 @@ public class JsonWriter implements Closeable, Flushable {
return this; // skip the name and the value
}
}
- beforeValue(false);
+ beforeValue();
sink.writeUtf8("null");
pathIndices[stackSize - 1]++;
return this;
@@ -433,7 +433,7 @@ public class JsonWriter implements Closeable, Flushable {
*/
public JsonWriter value(boolean value) throws IOException {
writeDeferredName();
- beforeValue(false);
+ beforeValue();
sink.writeUtf8(value ? "true" : "false");
pathIndices[stackSize - 1]++;
return this;
@@ -454,7 +454,7 @@ public class JsonWriter implements Closeable, Flushable {
return name(Double.toString(value));
}
writeDeferredName();
- beforeValue(false);
+ beforeValue();
sink.writeUtf8(Double.toString(value));
pathIndices[stackSize - 1]++;
return this;
@@ -470,7 +470,7 @@ public class JsonWriter implements Closeable, Flushable {
return name(Long.toString(value));
}
writeDeferredName();
- beforeValue(false);
+ beforeValue();
sink.writeUtf8(Long.toString(value));
pathIndices[stackSize - 1]++;
return this;
@@ -497,7 +497,7 @@ public class JsonWriter implements Closeable, Flushable {
return name(string);
}
writeDeferredName();
- beforeValue(false);
+ beforeValue();
sink.writeUtf8(string);
pathIndices[stackSize - 1]++;
return this;
@@ -591,12 +591,9 @@ public class JsonWriter implements Closeable, Flushable {
* Inserts any necessary separators and whitespace before a literal value,
* inline array, or inline object. Also adjusts the stack to expect either a
* closing bracket or another element.
- *
- * @param root true if the value is a new array or object, the two values
- * permitted as top-level elements.
*/
@SuppressWarnings("fallthrough")
- private void beforeValue(boolean root) throws IOException {
+ private void beforeValue() throws IOException {
switch (peek()) {
case NONEMPTY_DOCUMENT:
if (!lenient) {
@@ -605,10 +602,6 @@ public class JsonWriter implements Closeable, Flushable {
}
// fall-through
case EMPTY_DOCUMENT: // first in document
- if (!lenient && !root) {
- throw new IllegalStateException(
- "JSON must start with an array or an object.");
- }
replaceTop(NONEMPTY_DOCUMENT);
break;
diff --git a/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java b/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java
index 03eb5a8..2ca3b3a 100644
--- a/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java
+++ b/moshi/src/test/java/com/squareup/moshi/JsonReaderTest.java
@@ -264,14 +264,6 @@ public final class JsonReaderTest {
}
}
- @Test public void noTopLevelObject() {
- try {
- newReader("true").nextBoolean();
- fail();
- } catch (IOException expected) {
- }
- }
-
@Test public void characterUnescaping() throws IOException {
String json = "[\"a\","
+ "\"a\\\"\","
@@ -1341,46 +1333,38 @@ public final class JsonReaderTest {
}
}
- @Test public void strictTopLevelString() {
- JsonReader reader = newReader("\"a\"");
- try {
- reader.nextString();
- fail();
- } catch (IOException expected) {
- }
+ @Test public void topLevelValueTypes() throws IOException {
+ JsonReader reader1 = newReader("true");
+ assertThat(reader1.nextBoolean()).isTrue();
+ assertThat(reader1.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
+
+ JsonReader reader2 = newReader("false");
+ assertThat(reader2.nextBoolean()).isFalse();
+ assertThat(reader2.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
+
+ JsonReader reader3 = newReader("null");
+ assertThat(reader3.nextNull()).isNull();
+ assertThat(reader3.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
+
+ JsonReader reader4 = newReader("123");
+ assertThat(reader4.nextInt()).isEqualTo(123);
+ assertThat(reader4.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
+
+ JsonReader reader5 = newReader("123.4");
+ assertThat(reader5.nextDouble()).isEqualTo(123.4);
+ assertThat(reader5.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
+
+ JsonReader reader6 = newReader("\"a\"");
+ assertThat(reader6.nextString()).isEqualTo("a");
+ assertThat(reader6.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
}
- @Test public void lenientTopLevelString() throws IOException {
- JsonReader reader = newReader("\"a\"");
- reader.setLenient(true);
- assertThat(reader.nextString()).isEqualTo("a");
+ @Test public void topLevelValueTypeWithSkipValue() throws IOException {
+ JsonReader reader = newReader("true");
+ reader.skipValue();
assertThat(reader.peek()).isEqualTo(JsonReader.Token.END_DOCUMENT);
}
- @Test public void strictTopLevelValueType() {
- JsonReader reader = newReader("true");
- try {
- reader.nextBoolean();
- fail();
- } catch (IOException expected) {
- }
- }
-
- @Test public void lenientTopLevelValueType() throws IOException {
- JsonReader reader = newReader("true");
- reader.setLenient(true);
- assertThat(reader.nextBoolean()).isTrue();
- }
-
- @Test public void strictTopLevelValueTypeWithSkipValue() {
- JsonReader reader = newReader("true");
- try {
- reader.skipValue();
- fail();
- } catch (IOException expected) {
- }
- }
-
@Test @Ignore public void bomIgnoredAsFirstCharacterOfDocument() throws IOException {
JsonReader reader = newReader("\ufeff[]");
reader.beginArray();
diff --git a/moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java b/moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java
index 58efad9..ba4a8fe 100644
--- a/moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java
+++ b/moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java
@@ -48,11 +48,41 @@ public final class JsonWriterTest {
assertThat(buffer.readUtf8()).isEqualTo("{\"a\":null}");
}
- @Test public void wrongTopLevelType() throws IOException {
+ @Test public void topLevelValueTypes() throws IOException {
Buffer buffer = new Buffer();
- JsonWriter jsonWriter = JsonWriter.of(buffer);
+
+ JsonWriter writer1 = JsonWriter.of(buffer);
+ writer1.value(true);
+ writer1.close();
+ assertThat(buffer.readUtf8()).isEqualTo("true");
+
+ JsonWriter writer2 = JsonWriter.of(buffer);
+ writer2.nullValue();
+ writer2.close();
+ assertThat(buffer.readUtf8()).isEqualTo("null");
+
+ JsonWriter writer3 = JsonWriter.of(buffer);
+ writer3.value(123);
+ writer3.close();
+ assertThat(buffer.readUtf8()).isEqualTo("123");
+
+ JsonWriter writer4 = JsonWriter.of(buffer);
+ writer4.value(123.4);
+ writer4.close();
+ assertThat(buffer.readUtf8()).isEqualTo("123.4");
+
+ JsonWriter writer5 = JsonWriter.of(buffer);
+ writer5.value("a");
+ writer5.close();
+ assertThat(buffer.readUtf8()).isEqualTo("\"a\"");
+ }
+
+ @Test public void invalidTopLevelTypes() throws IOException {
+ Buffer buffer = new Buffer();
+ JsonWriter writer = JsonWriter.of(buffer);
+ writer.name("hello");
try {
- jsonWriter.value("a");
+ writer.value("world");
fail();
} catch (IllegalStateException expected) {
}