mirror of
https://github.com/fankes/moshi.git
synced 2025-10-19 16:09:21 +08:00
@@ -188,7 +188,7 @@ final class BufferedSinkJsonWriter extends JsonWriter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value on the top of the stack.
|
||||
* Returns the scope on the top of the stack.
|
||||
*/
|
||||
private int peek() {
|
||||
if (stackSize == 0) {
|
||||
@@ -212,7 +212,7 @@ final class BufferedSinkJsonWriter extends JsonWriter {
|
||||
throw new IllegalStateException("JsonWriter is closed.");
|
||||
}
|
||||
if (deferredName != null) {
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException("Nesting problem.");
|
||||
}
|
||||
deferredName = name;
|
||||
pathNames[stackSize - 1] = name;
|
||||
|
@@ -69,7 +69,7 @@ final class MapJsonAdapter<K, V> extends JsonAdapter<Map<K, V>> {
|
||||
V replaced = result.put(name, value);
|
||||
if (replaced != null) {
|
||||
throw new JsonDataException("Map key '" + name + "' has multiple values at path "
|
||||
+ reader.getPath());
|
||||
+ reader.getPath() + ": " + replaced + " and " + value);
|
||||
}
|
||||
}
|
||||
reader.endObject();
|
||||
|
237
moshi/src/main/java/com/squareup/moshi/ObjectJsonWriter.java
Normal file
237
moshi/src/main/java/com/squareup/moshi/ObjectJsonWriter.java
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.squareup.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.squareup.moshi.JsonScope.EMPTY_ARRAY;
|
||||
import static com.squareup.moshi.JsonScope.EMPTY_DOCUMENT;
|
||||
import static com.squareup.moshi.JsonScope.EMPTY_OBJECT;
|
||||
import static com.squareup.moshi.JsonScope.NONEMPTY_DOCUMENT;
|
||||
|
||||
/** Writes JSON by building a Java object comprising maps, lists, and JSON primitives. */
|
||||
final class ObjectJsonWriter extends JsonWriter {
|
||||
private String indent;
|
||||
private boolean lenient;
|
||||
private boolean serializeNulls;
|
||||
|
||||
private final Object[] stack = new Object[32];
|
||||
private final int[] scopes = new int[32];
|
||||
private final String[] pathNames = new String[32];
|
||||
private final int[] pathIndices = new int[32];
|
||||
private int stackSize = 0;
|
||||
private String deferredName;
|
||||
|
||||
ObjectJsonWriter() {
|
||||
scopes[stackSize++] = EMPTY_DOCUMENT;
|
||||
}
|
||||
|
||||
public Object root() {
|
||||
int size = stackSize;
|
||||
if (size > 1 || size == 1 && scopes[size - 1] != NONEMPTY_DOCUMENT) {
|
||||
throw new IllegalStateException("Incomplete document");
|
||||
}
|
||||
return stack[0];
|
||||
}
|
||||
|
||||
@Override public void setIndent(String indent) {
|
||||
this.indent = indent;
|
||||
}
|
||||
|
||||
@Override public String getIndent() {
|
||||
return indent;
|
||||
}
|
||||
|
||||
@Override public void setLenient(boolean lenient) {
|
||||
this.lenient = lenient;
|
||||
}
|
||||
|
||||
@Override public boolean isLenient() {
|
||||
return lenient;
|
||||
}
|
||||
|
||||
@Override public void setSerializeNulls(boolean serializeNulls) {
|
||||
this.serializeNulls = serializeNulls;
|
||||
}
|
||||
|
||||
@Override public boolean getSerializeNulls() {
|
||||
return serializeNulls;
|
||||
}
|
||||
|
||||
@Override public JsonWriter beginArray() throws IOException {
|
||||
if (stackSize == stack.length) {
|
||||
throw new JsonDataException("Nesting too deep at " + getPath() + ": circular reference?");
|
||||
}
|
||||
List<Object> list = new ArrayList<>();
|
||||
add(list);
|
||||
stack[stackSize] = list;
|
||||
scopes[stackSize] = EMPTY_ARRAY;
|
||||
pathIndices[stackSize] = 0;
|
||||
stackSize++;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter endArray() throws IOException {
|
||||
if (peek() != EMPTY_ARRAY) {
|
||||
throw new IllegalStateException("Nesting problem.");
|
||||
}
|
||||
stackSize--;
|
||||
stack[stackSize] = null;
|
||||
pathIndices[stackSize - 1]++;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter beginObject() throws IOException {
|
||||
if (stackSize == stack.length) {
|
||||
throw new JsonDataException("Nesting too deep at " + getPath() + ": circular reference?");
|
||||
}
|
||||
Map<String, Object> map = new LinkedHashTreeMap<>();
|
||||
add(map);
|
||||
stack[stackSize] = map;
|
||||
scopes[stackSize] = EMPTY_OBJECT;
|
||||
stackSize++;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter endObject() throws IOException {
|
||||
if (peek() != EMPTY_OBJECT || deferredName != null) {
|
||||
throw new IllegalStateException("Nesting problem.");
|
||||
}
|
||||
stackSize--;
|
||||
stack[stackSize] = null;
|
||||
pathNames[stackSize] = null; // Free the last path name so that it can be garbage collected!
|
||||
pathIndices[stackSize - 1]++;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter name(String name) throws IOException {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name == null");
|
||||
}
|
||||
if (stackSize == 0) {
|
||||
throw new IllegalStateException("JsonWriter is closed.");
|
||||
}
|
||||
if (peek() != EMPTY_OBJECT || deferredName != null) {
|
||||
throw new IllegalStateException("Nesting problem.");
|
||||
}
|
||||
pathNames[stackSize - 1] = name;
|
||||
deferredName = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(String value) throws IOException {
|
||||
return add(value);
|
||||
}
|
||||
|
||||
@Override public JsonWriter nullValue() throws IOException {
|
||||
return add(null);
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(boolean value) throws IOException {
|
||||
return add(value);
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(Boolean value) throws IOException {
|
||||
return add(value);
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(double value) throws IOException {
|
||||
return value(Double.valueOf(value));
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(long value) throws IOException {
|
||||
return add(value);
|
||||
}
|
||||
|
||||
@Override public JsonWriter value(Number value) throws IOException {
|
||||
if (!lenient) {
|
||||
double d = value.doubleValue();
|
||||
if (d == Double.POSITIVE_INFINITY || d == Double.NEGATIVE_INFINITY || Double.isNaN(d)) {
|
||||
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
|
||||
}
|
||||
}
|
||||
return add(value);
|
||||
}
|
||||
|
||||
@Override void promoteNameToValue() throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override public String getPath() {
|
||||
return JsonScope.getPath(stackSize, scopes, pathNames, pathIndices);
|
||||
}
|
||||
|
||||
@Override public void close() throws IOException {
|
||||
int size = stackSize;
|
||||
if (size > 1 || size == 1 && scopes[size - 1] != NONEMPTY_DOCUMENT) {
|
||||
throw new IOException("Incomplete document");
|
||||
}
|
||||
stackSize = 0;
|
||||
}
|
||||
|
||||
@Override public void flush() throws IOException {
|
||||
if (stackSize == 0) {
|
||||
throw new IllegalStateException("JsonWriter is closed.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scope on the top of the stack.
|
||||
*/
|
||||
private int peek() {
|
||||
if (stackSize == 0) {
|
||||
throw new IllegalStateException("JsonWriter is closed.");
|
||||
}
|
||||
return scopes[stackSize - 1];
|
||||
}
|
||||
|
||||
private ObjectJsonWriter add(Object newTop) {
|
||||
int scope = peek();
|
||||
|
||||
if (stackSize == 1) {
|
||||
if (scope != EMPTY_DOCUMENT) {
|
||||
throw new IllegalStateException("JSON must have only one top-level value.");
|
||||
}
|
||||
scopes[stackSize - 1] = NONEMPTY_DOCUMENT;
|
||||
stack[stackSize - 1] = newTop;
|
||||
|
||||
} else if (scope == EMPTY_OBJECT && deferredName != null) {
|
||||
if (newTop != null || serializeNulls) {
|
||||
@SuppressWarnings("unchecked") // Our maps always have string keys and object values.
|
||||
Map<String, Object> map = (Map<String, Object>) stack[stackSize - 1];
|
||||
Object replaced = map.put(deferredName, newTop);
|
||||
if (replaced != null) {
|
||||
throw new IllegalArgumentException("Map key '" + deferredName
|
||||
+ "' has multiple values at path " + getPath() + ": " + replaced + " and " + newTop);
|
||||
}
|
||||
}
|
||||
deferredName = null;
|
||||
|
||||
} else if (scope == EMPTY_ARRAY) {
|
||||
@SuppressWarnings("unchecked") // Our lists always have object values.
|
||||
List<Object> list = (List<Object>) stack[stackSize - 1];
|
||||
list.add(newTop);
|
||||
|
||||
} else {
|
||||
throw new IllegalStateException("Nesting problem.");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
@@ -286,7 +286,13 @@ final class StandardJsonAdapters {
|
||||
Map<String, Object> map = new LinkedHashTreeMap<>();
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
map.put(reader.nextName(), fromJson(reader));
|
||||
String name = reader.nextName();
|
||||
Object value = fromJson(reader);
|
||||
Object replaced = map.put(name, value);
|
||||
if (replaced != null) {
|
||||
throw new JsonDataException("Map key '" + name + "' has multiple values at path "
|
||||
+ reader.getPath() + ": " + replaced + " and " + value);
|
||||
}
|
||||
}
|
||||
reader.endObject();
|
||||
return map;
|
||||
|
@@ -16,468 +16,15 @@
|
||||
package com.squareup.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import okio.Buffer;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public final class BufferedSinkJsonWriterTest {
|
||||
@Parameter public JsonWriterFactory factory;
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static List<Object[]> parameters() {
|
||||
return JsonWriterFactory.factories();
|
||||
}
|
||||
|
||||
@Test public void nullsValuesNotSerializedByDefault() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
writer.nullValue();
|
||||
writer.endObject();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("{}");
|
||||
}
|
||||
|
||||
@Test public void nullsValuesSerializedWhenConfigured() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.setSerializeNulls(true);
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
writer.nullValue();
|
||||
writer.endObject();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("{\"a\":null}");
|
||||
}
|
||||
|
||||
@Test public void topLevelBoolean() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.value(true);
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("true");
|
||||
}
|
||||
|
||||
@Test public void topLevelNull() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.nullValue();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("null");
|
||||
}
|
||||
|
||||
@Test public void topLevelInt() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.value(123);
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("123");
|
||||
}
|
||||
|
||||
@Test public void topLevelDouble() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.value(123.4);
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("123.4");
|
||||
}
|
||||
|
||||
@Test public void topLevelString() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.value("a");
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("\"a\"");
|
||||
}
|
||||
|
||||
@Test public void invalidTopLevelTypes() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.name("hello");
|
||||
try {
|
||||
writer.value("world");
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void twoNames() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
try {
|
||||
writer.name("a");
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void nameWithoutValue() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
try {
|
||||
writer.endObject();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void valueWithoutName() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
try {
|
||||
writer.value(true);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void multipleTopLevelValues() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray().endArray();
|
||||
try {
|
||||
writer.beginArray();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void badNestingObject() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.beginObject();
|
||||
try {
|
||||
writer.endArray();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void badNestingArray() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.beginArray();
|
||||
try {
|
||||
writer.endObject();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void nullName() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
try {
|
||||
writer.name(null);
|
||||
fail();
|
||||
} catch (NullPointerException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void nullStringValue() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.setSerializeNulls(true);
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
writer.value((String) null);
|
||||
writer.endObject();
|
||||
assertThat(factory.json()).isEqualTo("{\"a\":null}");
|
||||
}
|
||||
|
||||
@Test public void nonFiniteDoubles() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
try {
|
||||
writer.value(Double.NaN);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
writer.value(Double.NEGATIVE_INFINITY);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
writer.value(Double.POSITIVE_INFINITY);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void nonFiniteBoxedDoubles() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
try {
|
||||
writer.value(new Double(Double.NaN));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
writer.value(new Double(Double.NEGATIVE_INFINITY));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
writer.value(new Double(Double.POSITIVE_INFINITY));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void doubles() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value(-0.0);
|
||||
writer.value(1.0);
|
||||
writer.value(Double.MAX_VALUE);
|
||||
writer.value(Double.MIN_VALUE);
|
||||
writer.value(0.0);
|
||||
writer.value(-0.5);
|
||||
writer.value(2.2250738585072014E-308);
|
||||
writer.value(Math.PI);
|
||||
writer.value(Math.E);
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("[-0.0,"
|
||||
+ "1.0,"
|
||||
+ "1.7976931348623157E308,"
|
||||
+ "4.9E-324,"
|
||||
+ "0.0,"
|
||||
+ "-0.5,"
|
||||
+ "2.2250738585072014E-308,"
|
||||
+ "3.141592653589793,"
|
||||
+ "2.718281828459045]");
|
||||
}
|
||||
|
||||
@Test public void longs() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value(0);
|
||||
writer.value(1);
|
||||
writer.value(-1);
|
||||
writer.value(Long.MIN_VALUE);
|
||||
writer.value(Long.MAX_VALUE);
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("[0,"
|
||||
+ "1,"
|
||||
+ "-1,"
|
||||
+ "-9223372036854775808,"
|
||||
+ "9223372036854775807]");
|
||||
}
|
||||
|
||||
@Test public void numbers() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value(new BigInteger("0"));
|
||||
writer.value(new BigInteger("9223372036854775808"));
|
||||
writer.value(new BigInteger("-9223372036854775809"));
|
||||
writer.value(new BigDecimal("3.141592653589793238462643383"));
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("[0,"
|
||||
+ "9223372036854775808,"
|
||||
+ "-9223372036854775809,"
|
||||
+ "3.141592653589793238462643383]");
|
||||
}
|
||||
|
||||
@Test public void booleans() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value(true);
|
||||
writer.value(false);
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[true,false]");
|
||||
}
|
||||
|
||||
@Test public void boxedBooleans() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value((Boolean) true);
|
||||
writer.value((Boolean) false);
|
||||
writer.value((Boolean) null);
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[true,false,null]");
|
||||
}
|
||||
|
||||
@Test public void nulls() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.nullValue();
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[null]");
|
||||
}
|
||||
|
||||
@Test public void strings() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value("a");
|
||||
writer.value("a\"");
|
||||
writer.value("\"");
|
||||
writer.value(":");
|
||||
writer.value(",");
|
||||
writer.value("\b");
|
||||
writer.value("\f");
|
||||
writer.value("\n");
|
||||
writer.value("\r");
|
||||
writer.value("\t");
|
||||
writer.value(" ");
|
||||
writer.value("\\");
|
||||
writer.value("{");
|
||||
writer.value("}");
|
||||
writer.value("[");
|
||||
writer.value("]");
|
||||
writer.value("\0");
|
||||
writer.value("\u0019");
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[\"a\","
|
||||
+ "\"a\\\"\","
|
||||
+ "\"\\\"\","
|
||||
+ "\":\","
|
||||
+ "\",\","
|
||||
+ "\"\\b\","
|
||||
+ "\"\\f\","
|
||||
+ "\"\\n\","
|
||||
+ "\"\\r\","
|
||||
+ "\"\\t\","
|
||||
+ "\" \","
|
||||
+ "\"\\\\\","
|
||||
+ "\"{\","
|
||||
+ "\"}\","
|
||||
+ "\"[\","
|
||||
+ "\"]\","
|
||||
+ "\"\\u0000\","
|
||||
+ "\"\\u0019\"]");
|
||||
}
|
||||
|
||||
@Test public void unicodeLineBreaksEscaped() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value("\u2028 \u2029");
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[\"\\u2028 \\u2029\"]");
|
||||
}
|
||||
|
||||
@Test public void emptyArray() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[]");
|
||||
}
|
||||
|
||||
@Test public void emptyObject() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.endObject();
|
||||
assertThat(factory.json()).isEqualTo("{}");
|
||||
}
|
||||
|
||||
@Test public void objectsInArrays() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.beginObject();
|
||||
writer.name("a").value(5);
|
||||
writer.name("b").value(false);
|
||||
writer.endObject();
|
||||
writer.beginObject();
|
||||
writer.name("c").value(6);
|
||||
writer.name("d").value(true);
|
||||
writer.endObject();
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[{\"a\":5,\"b\":false},"
|
||||
+ "{\"c\":6,\"d\":true}]");
|
||||
}
|
||||
|
||||
@Test public void arraysInObjects() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
writer.beginArray();
|
||||
writer.value(5);
|
||||
writer.value(false);
|
||||
writer.endArray();
|
||||
writer.name("b");
|
||||
writer.beginArray();
|
||||
writer.value(6);
|
||||
writer.value(true);
|
||||
writer.endArray();
|
||||
writer.endObject();
|
||||
assertThat(factory.json()).isEqualTo("{\"a\":[5,false],"
|
||||
+ "\"b\":[6,true]}");
|
||||
}
|
||||
|
||||
@Test public void deepNestingArrays() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.beginArray();
|
||||
}
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.endArray();
|
||||
}
|
||||
assertThat(factory.json())
|
||||
.isEqualTo("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]");
|
||||
}
|
||||
|
||||
@Test public void tooDeepNestingArrays() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.beginArray();
|
||||
}
|
||||
try {
|
||||
writer.beginArray();
|
||||
fail();
|
||||
} catch (JsonDataException expected) {
|
||||
assertThat(expected).hasMessage("Nesting too deep at $[0][0][0][0][0][0][0][0][0][0][0][0][0]"
|
||||
+ "[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]: circular reference?");
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void deepNestingObjects() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
}
|
||||
writer.value(true);
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.endObject();
|
||||
}
|
||||
assertThat(factory.json()).isEqualTo(""
|
||||
+ "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":"
|
||||
+ "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":"
|
||||
+ "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":true}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}");
|
||||
}
|
||||
|
||||
@Test public void tooDeepNestingObjects() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
}
|
||||
try {
|
||||
writer.beginObject();
|
||||
fail();
|
||||
} catch (JsonDataException expected) {
|
||||
assertThat(expected).hasMessage("Nesting too deep at $.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a."
|
||||
+ "a.a.a.a.a.a.a.a.a.a.a.a: circular reference?");
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void repeatedName() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.name("a").value(true);
|
||||
writer.name("a").value(false);
|
||||
writer.endObject();
|
||||
// JsonWriter doesn't attempt to detect duplicate names
|
||||
assertThat(factory.json()).isEqualTo("{\"a\":true,\"a\":false}");
|
||||
}
|
||||
|
||||
@Test public void prettyPrintObject() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
Buffer buffer = new Buffer();
|
||||
JsonWriter writer = JsonWriter.of(buffer);
|
||||
writer.setSerializeNulls(true);
|
||||
writer.setIndent(" ");
|
||||
|
||||
@@ -510,11 +57,12 @@ public final class BufferedSinkJsonWriterTest {
|
||||
+ " \"i\": 9.0\n"
|
||||
+ " }\n"
|
||||
+ "}";
|
||||
assertThat(factory.json()).isEqualTo(expected);
|
||||
assertThat(buffer.readUtf8()).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test public void prettyPrintArray() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
Buffer buffer = new Buffer();
|
||||
JsonWriter writer = JsonWriter.of(buffer);
|
||||
writer.setIndent(" ");
|
||||
|
||||
writer.beginArray();
|
||||
@@ -546,99 +94,17 @@ public final class BufferedSinkJsonWriterTest {
|
||||
+ " 9.0\n"
|
||||
+ " ]\n"
|
||||
+ "]";
|
||||
assertThat(factory.json()).isEqualTo(expected);
|
||||
assertThat(buffer.readUtf8()).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test public void lenientWriterPermitsMultipleTopLevelValues() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.setLenient(true);
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("[][]");
|
||||
}
|
||||
|
||||
@Test public void strictWriterDoesNotPermitMultipleTopLevelValues() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
try {
|
||||
writer.beginArray();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void closedWriterThrowsOnStructure() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
try {
|
||||
writer.beginArray();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
try {
|
||||
writer.endArray();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
try {
|
||||
@Test public void repeatedNameIgnored() throws IOException {
|
||||
Buffer buffer = new Buffer();
|
||||
JsonWriter writer = JsonWriter.of(buffer);
|
||||
writer.beginObject();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
try {
|
||||
writer.name("a").value(1);
|
||||
writer.name("a").value(2);
|
||||
writer.endObject();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void closedWriterThrowsOnName() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
try {
|
||||
writer.name("a");
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void closedWriterThrowsOnValue() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
try {
|
||||
writer.value("a");
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void closedWriterThrowsOnFlush() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
try {
|
||||
writer.flush();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void writerCloseIsIdempotent() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
writer.close();
|
||||
// JsonWriter doesn't attempt to detect duplicate names
|
||||
assertThat(buffer.readUtf8()).isEqualTo("{\"a\":1,\"a\":2}");
|
||||
}
|
||||
}
|
||||
|
@@ -28,7 +28,7 @@ abstract class JsonReaderFactory {
|
||||
return JsonReader.of(buffer);
|
||||
}
|
||||
|
||||
@Override public boolean supportsMultipleTopLevelValuesInOneDocument() {
|
||||
@Override boolean supportsMultipleTopLevelValuesInOneDocument() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ abstract class JsonReaderFactory {
|
||||
}
|
||||
|
||||
// TODO(jwilson): fix precision checks and delete his method.
|
||||
@Override public boolean implementsStrictPrecision() {
|
||||
@Override boolean implementsStrictPrecision() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -61,11 +61,11 @@ abstract class JsonReaderFactory {
|
||||
|
||||
abstract JsonReader newReader(String json) throws IOException;
|
||||
|
||||
public boolean supportsMultipleTopLevelValuesInOneDocument() {
|
||||
boolean supportsMultipleTopLevelValuesInOneDocument() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean implementsStrictPrecision() {
|
||||
boolean implementsStrictPrecision() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -15,11 +15,15 @@
|
||||
*/
|
||||
package com.squareup.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import okio.Buffer;
|
||||
|
||||
abstract class JsonWriterFactory {
|
||||
private static final Moshi MOSHI = new Moshi.Builder().build();
|
||||
private static final JsonAdapter<Object> OBJECT_ADAPTER = MOSHI.adapter(Object.class);
|
||||
|
||||
static List<Object[]> factories() {
|
||||
final JsonWriterFactory bufferedSink = new JsonWriterFactory() {
|
||||
Buffer buffer;
|
||||
@@ -35,15 +39,59 @@ abstract class JsonWriterFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override boolean supportsMultipleTopLevelValuesInOneDocument() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "BufferedSinkJsonWriter";
|
||||
}
|
||||
};
|
||||
|
||||
return Arrays.<Object[]>asList(
|
||||
new Object[] { bufferedSink });
|
||||
final JsonWriterFactory object = new JsonWriterFactory() {
|
||||
ObjectJsonWriter writer;
|
||||
|
||||
@Override JsonWriter newWriter() {
|
||||
writer = new ObjectJsonWriter();
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override String json() {
|
||||
// This writer writes a DOM. Use other Moshi features to serialize it as a string.
|
||||
try {
|
||||
Buffer buffer = new Buffer();
|
||||
JsonWriter bufferedSinkWriter = JsonWriter.of(buffer);
|
||||
bufferedSinkWriter.setSerializeNulls(true);
|
||||
OBJECT_ADAPTER.toJson(bufferedSinkWriter, writer.root());
|
||||
return buffer.readUtf8();
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jwilson): support BigDecimal and BigInteger and delete his method.
|
||||
@Override boolean supportsBigNumbers() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "ObjectJsonWriter";
|
||||
}
|
||||
};
|
||||
|
||||
return Arrays.asList(
|
||||
new Object[] { bufferedSink },
|
||||
new Object[] { object });
|
||||
}
|
||||
|
||||
abstract JsonWriter newWriter();
|
||||
abstract String json();
|
||||
|
||||
boolean supportsMultipleTopLevelValuesInOneDocument() {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean supportsBigNumbers() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
565
moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java
Normal file
565
moshi/src/test/java/com/squareup/moshi/JsonWriterTest.java
Normal file
@@ -0,0 +1,565 @@
|
||||
/*
|
||||
* Copyright (C) 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.squareup.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameter;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
@RunWith(Parameterized.class)
|
||||
public final class JsonWriterTest {
|
||||
@Parameter public JsonWriterFactory factory;
|
||||
|
||||
@Parameters(name = "{0}")
|
||||
public static List<Object[]> parameters() {
|
||||
return JsonWriterFactory.factories();
|
||||
}
|
||||
|
||||
@Test public void nullsValuesNotSerializedByDefault() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
writer.nullValue();
|
||||
writer.endObject();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("{}");
|
||||
}
|
||||
|
||||
@Test public void nullsValuesSerializedWhenConfigured() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.setSerializeNulls(true);
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
writer.nullValue();
|
||||
writer.endObject();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("{\"a\":null}");
|
||||
}
|
||||
|
||||
@Test public void topLevelBoolean() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.value(true);
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("true");
|
||||
}
|
||||
|
||||
@Test public void topLevelNull() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.nullValue();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("null");
|
||||
}
|
||||
|
||||
@Test public void topLevelInt() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.value(123);
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("123");
|
||||
}
|
||||
|
||||
@Test public void topLevelDouble() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.value(123.4);
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("123.4");
|
||||
}
|
||||
|
||||
@Test public void topLevelString() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.value("a");
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("\"a\"");
|
||||
}
|
||||
|
||||
@Test public void invalidTopLevelTypes() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
try {
|
||||
writer.name("hello").value("world");
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void twoNames() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
try {
|
||||
writer.name("a");
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void nameWithoutValue() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
try {
|
||||
writer.endObject();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void valueWithoutName() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
try {
|
||||
writer.value(true);
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void multipleTopLevelValues() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray().endArray();
|
||||
try {
|
||||
writer.beginArray();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void badNestingObject() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.beginObject();
|
||||
try {
|
||||
writer.endArray();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void badNestingArray() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.beginArray();
|
||||
try {
|
||||
writer.endObject();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void nullName() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
try {
|
||||
writer.name(null);
|
||||
fail();
|
||||
} catch (NullPointerException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void nullStringValue() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.setSerializeNulls(true);
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
writer.value((String) null);
|
||||
writer.endObject();
|
||||
assertThat(factory.json()).isEqualTo("{\"a\":null}");
|
||||
}
|
||||
|
||||
@Test public void nonFiniteDoubles() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
try {
|
||||
writer.value(Double.NaN);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
writer.value(Double.NEGATIVE_INFINITY);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
writer.value(Double.POSITIVE_INFINITY);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void nonFiniteBoxedDoubles() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
try {
|
||||
writer.value(new Double(Double.NaN));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
writer.value(new Double(Double.NEGATIVE_INFINITY));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
try {
|
||||
writer.value(new Double(Double.POSITIVE_INFINITY));
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void doubles() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value(-0.0);
|
||||
writer.value(1.0);
|
||||
writer.value(Double.MAX_VALUE);
|
||||
writer.value(Double.MIN_VALUE);
|
||||
writer.value(0.0);
|
||||
writer.value(-0.5);
|
||||
writer.value(2.2250738585072014E-308);
|
||||
writer.value(Math.PI);
|
||||
writer.value(Math.E);
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("[-0.0,"
|
||||
+ "1.0,"
|
||||
+ "1.7976931348623157E308,"
|
||||
+ "4.9E-324,"
|
||||
+ "0.0,"
|
||||
+ "-0.5,"
|
||||
+ "2.2250738585072014E-308,"
|
||||
+ "3.141592653589793,"
|
||||
+ "2.718281828459045]");
|
||||
}
|
||||
|
||||
@Test public void longs() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value(0);
|
||||
writer.value(1);
|
||||
writer.value(-1);
|
||||
writer.value(Long.MIN_VALUE);
|
||||
writer.value(Long.MAX_VALUE);
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("[0,"
|
||||
+ "1,"
|
||||
+ "-1,"
|
||||
+ "-9223372036854775808,"
|
||||
+ "9223372036854775807]");
|
||||
}
|
||||
|
||||
@Test public void numbers() throws IOException {
|
||||
assumeTrue(factory.supportsBigNumbers());
|
||||
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value(new BigInteger("0"));
|
||||
writer.value(new BigInteger("9223372036854775808"));
|
||||
writer.value(new BigInteger("-9223372036854775809"));
|
||||
writer.value(new BigDecimal("3.141592653589793238462643383"));
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("[0,"
|
||||
+ "9223372036854775808,"
|
||||
+ "-9223372036854775809,"
|
||||
+ "3.141592653589793238462643383]");
|
||||
}
|
||||
|
||||
@Test public void booleans() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value(true);
|
||||
writer.value(false);
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[true,false]");
|
||||
}
|
||||
|
||||
@Test public void boxedBooleans() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value((Boolean) true);
|
||||
writer.value((Boolean) false);
|
||||
writer.value((Boolean) null);
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[true,false,null]");
|
||||
}
|
||||
|
||||
@Test public void nulls() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.nullValue();
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[null]");
|
||||
}
|
||||
|
||||
@Test public void strings() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value("a");
|
||||
writer.value("a\"");
|
||||
writer.value("\"");
|
||||
writer.value(":");
|
||||
writer.value(",");
|
||||
writer.value("\b");
|
||||
writer.value("\f");
|
||||
writer.value("\n");
|
||||
writer.value("\r");
|
||||
writer.value("\t");
|
||||
writer.value(" ");
|
||||
writer.value("\\");
|
||||
writer.value("{");
|
||||
writer.value("}");
|
||||
writer.value("[");
|
||||
writer.value("]");
|
||||
writer.value("\0");
|
||||
writer.value("\u0019");
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[\"a\","
|
||||
+ "\"a\\\"\","
|
||||
+ "\"\\\"\","
|
||||
+ "\":\","
|
||||
+ "\",\","
|
||||
+ "\"\\b\","
|
||||
+ "\"\\f\","
|
||||
+ "\"\\n\","
|
||||
+ "\"\\r\","
|
||||
+ "\"\\t\","
|
||||
+ "\" \","
|
||||
+ "\"\\\\\","
|
||||
+ "\"{\","
|
||||
+ "\"}\","
|
||||
+ "\"[\","
|
||||
+ "\"]\","
|
||||
+ "\"\\u0000\","
|
||||
+ "\"\\u0019\"]");
|
||||
}
|
||||
|
||||
@Test public void unicodeLineBreaksEscaped() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.value("\u2028 \u2029");
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[\"\\u2028 \\u2029\"]");
|
||||
}
|
||||
|
||||
@Test public void emptyArray() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[]");
|
||||
}
|
||||
|
||||
@Test public void emptyObject() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.endObject();
|
||||
assertThat(factory.json()).isEqualTo("{}");
|
||||
}
|
||||
|
||||
@Test public void objectsInArrays() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.beginObject();
|
||||
writer.name("a").value(5);
|
||||
writer.name("b").value(false);
|
||||
writer.endObject();
|
||||
writer.beginObject();
|
||||
writer.name("c").value(6);
|
||||
writer.name("d").value(true);
|
||||
writer.endObject();
|
||||
writer.endArray();
|
||||
assertThat(factory.json()).isEqualTo("[{\"a\":5,\"b\":false},"
|
||||
+ "{\"c\":6,\"d\":true}]");
|
||||
}
|
||||
|
||||
@Test public void arraysInObjects() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
writer.beginArray();
|
||||
writer.value(5);
|
||||
writer.value(false);
|
||||
writer.endArray();
|
||||
writer.name("b");
|
||||
writer.beginArray();
|
||||
writer.value(6);
|
||||
writer.value(true);
|
||||
writer.endArray();
|
||||
writer.endObject();
|
||||
assertThat(factory.json()).isEqualTo("{\"a\":[5,false],"
|
||||
+ "\"b\":[6,true]}");
|
||||
}
|
||||
|
||||
@Test public void deepNestingArrays() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.beginArray();
|
||||
}
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.endArray();
|
||||
}
|
||||
assertThat(factory.json())
|
||||
.isEqualTo("[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]");
|
||||
}
|
||||
|
||||
@Test public void tooDeepNestingArrays() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.beginArray();
|
||||
}
|
||||
try {
|
||||
writer.beginArray();
|
||||
fail();
|
||||
} catch (JsonDataException expected) {
|
||||
assertThat(expected).hasMessage("Nesting too deep at $[0][0][0][0][0][0][0][0][0][0][0][0][0]"
|
||||
+ "[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]: circular reference?");
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void deepNestingObjects() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
}
|
||||
writer.value(true);
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.endObject();
|
||||
}
|
||||
assertThat(factory.json()).isEqualTo(""
|
||||
+ "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":"
|
||||
+ "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":"
|
||||
+ "{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":true}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}");
|
||||
}
|
||||
|
||||
@Test public void tooDeepNestingObjects() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
for (int i = 0; i < 31; i++) {
|
||||
writer.beginObject();
|
||||
writer.name("a");
|
||||
}
|
||||
try {
|
||||
writer.beginObject();
|
||||
fail();
|
||||
} catch (JsonDataException expected) {
|
||||
assertThat(expected).hasMessage("Nesting too deep at $.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a."
|
||||
+ "a.a.a.a.a.a.a.a.a.a.a.a: circular reference?");
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void lenientWriterPermitsMultipleTopLevelValues() throws IOException {
|
||||
assumeTrue(factory.supportsMultipleTopLevelValuesInOneDocument());
|
||||
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.setLenient(true);
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
assertThat(factory.json()).isEqualTo("[][]");
|
||||
}
|
||||
|
||||
@Test public void strictWriterDoesNotPermitMultipleTopLevelValues() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
try {
|
||||
writer.beginArray();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void closedWriterThrowsOnStructure() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
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) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void closedWriterThrowsOnName() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
try {
|
||||
writer.name("a");
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void closedWriterThrowsOnValue() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
try {
|
||||
writer.value("a");
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void closedWriterThrowsOnFlush() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
try {
|
||||
writer.flush();
|
||||
fail();
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void writerCloseIsIdempotent() throws IOException {
|
||||
JsonWriter writer = factory.newWriter();
|
||||
writer.beginArray();
|
||||
writer.endArray();
|
||||
writer.close();
|
||||
writer.close();
|
||||
}
|
||||
}
|
@@ -105,7 +105,7 @@ public final class MapJsonAdapterTest {
|
||||
fromJson(String.class, Integer.class, "{\"c\":1,\"c\":2}");
|
||||
fail();
|
||||
} catch (JsonDataException expected) {
|
||||
assertThat(expected).hasMessage("Map key 'c' has multiple values at path $.c");
|
||||
assertThat(expected).hasMessage("Map key 'c' has multiple values at path $.c: 1 and 2");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Square, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.squareup.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public final class ObjectJsonWriterTest {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test public void array() throws Exception {
|
||||
ObjectJsonWriter writer = new ObjectJsonWriter();
|
||||
|
||||
writer.beginArray();
|
||||
writer.value("s");
|
||||
writer.value(1.5d);
|
||||
writer.value(true);
|
||||
writer.nullValue();
|
||||
writer.endArray();
|
||||
|
||||
assertThat((List<Object>) writer.root()).containsExactly("s", 1.5d, true, null);
|
||||
}
|
||||
|
||||
@Test public void object() throws Exception {
|
||||
ObjectJsonWriter writer = new ObjectJsonWriter();
|
||||
writer.setSerializeNulls(true);
|
||||
|
||||
writer.beginObject();
|
||||
writer.name("a").value("s");
|
||||
writer.name("b").value(1.5d);
|
||||
writer.name("c").value(true);
|
||||
writer.name("d").nullValue();
|
||||
writer.endObject();
|
||||
|
||||
assertThat((Map<?, ?>) writer.root()).containsExactly(
|
||||
entry("a", "s"), entry("b", 1.5d), entry("c", true), entry("d", null));
|
||||
}
|
||||
|
||||
@Test public void repeatedNameThrows() throws IOException {
|
||||
ObjectJsonWriter writer = new ObjectJsonWriter();
|
||||
writer.beginObject();
|
||||
writer.name("a").value(1L);
|
||||
try {
|
||||
writer.name("a").value(2L);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
assertThat(expected).hasMessage(
|
||||
"Map key 'a' has multiple values at path $.a: 1 and 2");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user