mirror of
https://github.com/fankes/moshi.git
synced 2025-10-19 16:09:21 +08:00
Merge pull request #708 from square/jwilson.1013.flattening
JSON flattening.
This commit is contained in:
@@ -103,7 +103,7 @@ final class RuntimeJsonAdapterFactory<T> implements JsonAdapter.Factory {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<JsonAdapter<Object>> jsonAdapters = new ArrayList<>();
|
List<JsonAdapter<Object>> jsonAdapters = new ArrayList<>(subtypes.size());
|
||||||
for (int i = 0, size = subtypes.size(); i < size; i++) {
|
for (int i = 0, size = subtypes.size(); i < size; i++) {
|
||||||
jsonAdapters.add(moshi.adapter(subtypes.get(i)));
|
jsonAdapters.add(moshi.adapter(subtypes.get(i)));
|
||||||
}
|
}
|
||||||
|
@@ -83,7 +83,7 @@ final class JsonUtf8Writer extends JsonWriter {
|
|||||||
"Array cannot be used as a map key in JSON at path " + getPath());
|
"Array cannot be used as a map key in JSON at path " + getPath());
|
||||||
}
|
}
|
||||||
writeDeferredName();
|
writeDeferredName();
|
||||||
return open(EMPTY_ARRAY, "[");
|
return open(EMPTY_ARRAY, NONEMPTY_ARRAY, "[");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public JsonWriter endArray() throws IOException {
|
@Override public JsonWriter endArray() throws IOException {
|
||||||
@@ -96,7 +96,7 @@ final class JsonUtf8Writer extends JsonWriter {
|
|||||||
"Object cannot be used as a map key in JSON at path " + getPath());
|
"Object cannot be used as a map key in JSON at path " + getPath());
|
||||||
}
|
}
|
||||||
writeDeferredName();
|
writeDeferredName();
|
||||||
return open(EMPTY_OBJECT, "{");
|
return open(EMPTY_OBJECT, NONEMPTY_OBJECT, "{");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public JsonWriter endObject() throws IOException {
|
@Override public JsonWriter endObject() throws IOException {
|
||||||
@@ -108,7 +108,13 @@ final class JsonUtf8Writer extends JsonWriter {
|
|||||||
* Enters a new scope by appending any necessary whitespace and the given
|
* Enters a new scope by appending any necessary whitespace and the given
|
||||||
* bracket.
|
* bracket.
|
||||||
*/
|
*/
|
||||||
private JsonWriter open(int empty, String openBracket) throws IOException {
|
private JsonWriter open(int empty, int nonempty, String openBracket) throws IOException {
|
||||||
|
if (stackSize == flattenStackSize
|
||||||
|
&& (scopes[stackSize - 1] == empty || scopes[stackSize - 1] == nonempty)) {
|
||||||
|
// Cancel this open. Invert the flatten stack size until this is closed.
|
||||||
|
flattenStackSize = ~flattenStackSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
beforeValue();
|
beforeValue();
|
||||||
checkStack();
|
checkStack();
|
||||||
pushScope(empty);
|
pushScope(empty);
|
||||||
@@ -129,6 +135,11 @@ final class JsonUtf8Writer extends JsonWriter {
|
|||||||
if (deferredName != null) {
|
if (deferredName != null) {
|
||||||
throw new IllegalStateException("Dangling name: " + deferredName);
|
throw new IllegalStateException("Dangling name: " + deferredName);
|
||||||
}
|
}
|
||||||
|
if (stackSize == ~flattenStackSize) {
|
||||||
|
// Cancel this close. Restore the flattenStackSize so we're ready to flatten again!
|
||||||
|
flattenStackSize = ~flattenStackSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
stackSize--;
|
stackSize--;
|
||||||
pathNames[stackSize] = null; // Free the last path name so that it can be garbage collected!
|
pathNames[stackSize] = null; // Free the last path name so that it can be garbage collected!
|
||||||
|
@@ -52,6 +52,11 @@ final class JsonValueWriter extends JsonWriter {
|
|||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Array cannot be used as a map key in JSON at path " + getPath());
|
"Array cannot be used as a map key in JSON at path " + getPath());
|
||||||
}
|
}
|
||||||
|
if (stackSize == flattenStackSize && scopes[stackSize - 1] == EMPTY_ARRAY) {
|
||||||
|
// Cancel this open. Invert the flatten stack size until this is closed.
|
||||||
|
flattenStackSize = ~flattenStackSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
checkStack();
|
checkStack();
|
||||||
List<Object> list = new ArrayList<>();
|
List<Object> list = new ArrayList<>();
|
||||||
add(list);
|
add(list);
|
||||||
@@ -65,6 +70,11 @@ final class JsonValueWriter extends JsonWriter {
|
|||||||
if (peekScope() != EMPTY_ARRAY) {
|
if (peekScope() != EMPTY_ARRAY) {
|
||||||
throw new IllegalStateException("Nesting problem.");
|
throw new IllegalStateException("Nesting problem.");
|
||||||
}
|
}
|
||||||
|
if (stackSize == ~flattenStackSize) {
|
||||||
|
// Cancel this close. Restore the flattenStackSize so we're ready to flatten again!
|
||||||
|
flattenStackSize = ~flattenStackSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
stackSize--;
|
stackSize--;
|
||||||
stack[stackSize] = null;
|
stack[stackSize] = null;
|
||||||
pathIndices[stackSize - 1]++;
|
pathIndices[stackSize - 1]++;
|
||||||
@@ -76,6 +86,11 @@ final class JsonValueWriter extends JsonWriter {
|
|||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Object cannot be used as a map key in JSON at path " + getPath());
|
"Object cannot be used as a map key in JSON at path " + getPath());
|
||||||
}
|
}
|
||||||
|
if (stackSize == flattenStackSize && scopes[stackSize - 1] == EMPTY_OBJECT) {
|
||||||
|
// Cancel this open. Invert the flatten stack size until this is closed.
|
||||||
|
flattenStackSize = ~flattenStackSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
checkStack();
|
checkStack();
|
||||||
Map<String, Object> map = new LinkedHashTreeMap<>();
|
Map<String, Object> map = new LinkedHashTreeMap<>();
|
||||||
add(map);
|
add(map);
|
||||||
@@ -91,6 +106,11 @@ final class JsonValueWriter extends JsonWriter {
|
|||||||
if (deferredName != null) {
|
if (deferredName != null) {
|
||||||
throw new IllegalStateException("Dangling name: " + deferredName);
|
throw new IllegalStateException("Dangling name: " + deferredName);
|
||||||
}
|
}
|
||||||
|
if (stackSize == ~flattenStackSize) {
|
||||||
|
// Cancel this close. Restore the flattenStackSize so we're ready to flatten again!
|
||||||
|
flattenStackSize = ~flattenStackSize;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
promoteValueToName = false;
|
promoteValueToName = false;
|
||||||
stackSize--;
|
stackSize--;
|
||||||
stack[stackSize] = null;
|
stack[stackSize] = null;
|
||||||
|
@@ -24,7 +24,9 @@ import javax.annotation.Nullable;
|
|||||||
import okio.BufferedSink;
|
import okio.BufferedSink;
|
||||||
import okio.BufferedSource;
|
import okio.BufferedSource;
|
||||||
|
|
||||||
|
import static com.squareup.moshi.JsonScope.EMPTY_ARRAY;
|
||||||
import static com.squareup.moshi.JsonScope.EMPTY_OBJECT;
|
import static com.squareup.moshi.JsonScope.EMPTY_OBJECT;
|
||||||
|
import static com.squareup.moshi.JsonScope.NONEMPTY_ARRAY;
|
||||||
import static com.squareup.moshi.JsonScope.NONEMPTY_OBJECT;
|
import static com.squareup.moshi.JsonScope.NONEMPTY_OBJECT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,6 +142,26 @@ public abstract class JsonWriter implements Closeable, Flushable {
|
|||||||
boolean serializeNulls;
|
boolean serializeNulls;
|
||||||
boolean promoteValueToName;
|
boolean promoteValueToName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controls the deepest stack size that has begin/end pairs flattened:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>If -1, no begin/end pairs are being suppressed.
|
||||||
|
* <li>If positive, this is the deepest stack size whose begin/end pairs are eligible to be
|
||||||
|
* flattened.
|
||||||
|
* <li>If negative, it is the bitwise inverse (~) of the deepest stack size whose begin/end
|
||||||
|
* pairs have been flattened.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>We differentiate between what layer would be flattened (positive) from what layer is being
|
||||||
|
* flattened (negative) so that we don't double-flatten.
|
||||||
|
*
|
||||||
|
* <p>To accommodate nested flattening we require callers to track the previous state when they
|
||||||
|
* provide a new state. The previous state is returned from {@link #beginFlatten} and restored
|
||||||
|
* with {@link #endFlatten}.
|
||||||
|
*/
|
||||||
|
int flattenStackSize = -1;
|
||||||
|
|
||||||
/** Returns a new instance that writes UTF-8 encoded JSON to {@code sink}. */
|
/** Returns a new instance that writes UTF-8 encoded JSON to {@code sink}. */
|
||||||
@CheckReturnValue public static JsonWriter of(BufferedSink sink) {
|
@CheckReturnValue public static JsonWriter of(BufferedSink sink) {
|
||||||
return new JsonUtf8Writer(sink);
|
return new JsonUtf8Writer(sink);
|
||||||
@@ -357,6 +379,88 @@ public abstract class JsonWriter implements Closeable, Flushable {
|
|||||||
promoteValueToName = true;
|
promoteValueToName = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels immediately-nested calls to {@link #beginArray()} or {@link #beginObject()} and their
|
||||||
|
* matching calls to {@link #endArray} or {@link #endObject()}. Use this to compose JSON adapters
|
||||||
|
* without nesting.
|
||||||
|
*
|
||||||
|
* <p>For example, the following creates JSON with nested arrays: {@code [1,[2,3,4],5]}.
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
*
|
||||||
|
* JsonAdapter<List<Integer>> integersAdapter = ...
|
||||||
|
*
|
||||||
|
* public void writeNumbers(JsonWriter writer) {
|
||||||
|
* writer.beginArray();
|
||||||
|
* writer.value(1);
|
||||||
|
* integersAdapter.toJson(writer, Arrays.asList(2, 3, 4));
|
||||||
|
* writer.value(5);
|
||||||
|
* writer.endArray();
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* <p>With flattening we can create JSON with a single array {@code [1,2,3,4,5]}:
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
*
|
||||||
|
* JsonAdapter<List<Integer>> integersAdapter = ...
|
||||||
|
*
|
||||||
|
* public void writeNumbers(JsonWriter writer) {
|
||||||
|
* writer.beginArray();
|
||||||
|
* int token = writer.beginFlatten();
|
||||||
|
* writer.value(1);
|
||||||
|
* integersAdapter.toJson(writer, Arrays.asList(2, 3, 4));
|
||||||
|
* writer.value(5);
|
||||||
|
* writer.endFlatten(token);
|
||||||
|
* writer.endArray();
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* <p>This method flattens arrays within arrays:
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
*
|
||||||
|
* Emit: [1, [2, 3, 4], 5]
|
||||||
|
* To produce: [1, 2, 3, 4, 5]
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* It also flattens objects within objects. Do not call {@link #name} before writing a flattened
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
*
|
||||||
|
* Emit: {"a": 1, {"b": 2}, "c": 3}
|
||||||
|
* To Produce: {"a": 1, "b": 2, "c": 3}
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* Other combinations are permitted but do not perform flattening. For example, objects inside of
|
||||||
|
* arrays are not flattened:
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
*
|
||||||
|
* Emit: [1, {"b": 2}, 3, [4, 5], 6]
|
||||||
|
* To Produce: [1, {"b": 2}, 3, 4, 5, 6]
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* <p>This method returns an opaque token. Callers must match all calls to this method with a call
|
||||||
|
* to {@link #endFlatten} with the matching token.
|
||||||
|
*/
|
||||||
|
public final int beginFlatten() {
|
||||||
|
int context = peekScope();
|
||||||
|
if (context != NONEMPTY_OBJECT && context != EMPTY_OBJECT
|
||||||
|
&& context != NONEMPTY_ARRAY && context != EMPTY_ARRAY) {
|
||||||
|
throw new IllegalStateException("Nesting problem.");
|
||||||
|
}
|
||||||
|
int token = flattenStackSize;
|
||||||
|
flattenStackSize = stackSize;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ends nested call flattening created by {@link #beginFlatten}. */
|
||||||
|
public final void endFlatten(int token) {
|
||||||
|
flattenStackSize = token;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a <a href="http://goessner.net/articles/JsonPath/">JsonPath</a> to
|
* Returns a <a href="http://goessner.net/articles/JsonPath/">JsonPath</a> to
|
||||||
* the current location in the JSON value.
|
* the current location in the JSON value.
|
||||||
|
338
moshi/src/test/java/com/squareup/moshi/FlattenTest.java
Normal file
338
moshi/src/test/java/com/squareup/moshi/FlattenTest.java
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 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.util.Arrays;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/** Note that this test makes heavy use of nested blocks, but these are for readability only. */
|
||||||
|
@RunWith(Parameterized.class)
|
||||||
|
public final class FlattenTest {
|
||||||
|
@Parameter public JsonCodecFactory factory;
|
||||||
|
|
||||||
|
@Parameters(name = "{0}")
|
||||||
|
public static List<Object[]> parameters() {
|
||||||
|
return JsonCodecFactory.factories();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void flattenExample() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder().build();
|
||||||
|
JsonAdapter<List<Integer>> integersAdapter =
|
||||||
|
moshi.adapter(Types.newParameterizedType(List.class, Integer.class));
|
||||||
|
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginArray();
|
||||||
|
int token = writer.beginFlatten();
|
||||||
|
writer.value(1);
|
||||||
|
integersAdapter.toJson(writer, Arrays.asList(2, 3, 4));
|
||||||
|
writer.value(5);
|
||||||
|
writer.endFlatten(token);
|
||||||
|
writer.endArray();
|
||||||
|
|
||||||
|
assertThat(factory.json()).isEqualTo("[1,2,3,4,5]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void flattenObject() throws Exception {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginObject();
|
||||||
|
{
|
||||||
|
writer.name("a");
|
||||||
|
writer.value("aaa");
|
||||||
|
int token = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginObject();
|
||||||
|
{
|
||||||
|
writer.name("b");
|
||||||
|
writer.value("bbb");
|
||||||
|
}
|
||||||
|
writer.endObject();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token);
|
||||||
|
writer.name("c");
|
||||||
|
writer.value("ccc");
|
||||||
|
}
|
||||||
|
writer.endObject();
|
||||||
|
assertThat(factory.json()).isEqualTo("{\"a\":\"aaa\",\"b\":\"bbb\",\"c\":\"ccc\"}");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void flattenArray() throws Exception {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("a");
|
||||||
|
int token = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("b");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token);
|
||||||
|
writer.value("c");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
assertThat(factory.json()).isEqualTo("[\"a\",\"b\",\"c\"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void recursiveFlatten() throws Exception {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("a");
|
||||||
|
int token1 = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("b");
|
||||||
|
int token2 = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("c");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token2);
|
||||||
|
writer.value("d");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token1);
|
||||||
|
writer.value("e");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
assertThat(factory.json()).isEqualTo("[\"a\",\"b\",\"c\",\"d\",\"e\"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void flattenMultipleNested() throws Exception {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("a");
|
||||||
|
int token = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("b");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("c");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token);
|
||||||
|
writer.value("d");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
assertThat(factory.json()).isEqualTo("[\"a\",\"b\",\"c\",\"d\"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void flattenIsOnlyOneLevelDeep() throws Exception {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("a");
|
||||||
|
int token = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("b");
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("c");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
writer.value("d");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token);
|
||||||
|
writer.value("e");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
assertThat(factory.json()).isEqualTo("[\"a\",\"b\",[\"c\"],\"d\",\"e\"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void flattenOnlySomeChildren() throws Exception {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("a");
|
||||||
|
int token = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("b");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token);
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("c");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
writer.value("d");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
assertThat(factory.json()).isEqualTo("[\"a\",\"b\",[\"c\"],\"d\"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void multipleCallsToFlattenSameNesting() throws Exception {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("a");
|
||||||
|
int token1 = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("b");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
int token2 = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("c");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token2);
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("d");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token1);
|
||||||
|
writer.value("e");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
assertThat(factory.json()).isEqualTo("[\"a\",\"b\",\"c\",\"d\",\"e\"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void deepFlatten() throws Exception {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
int token1 = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
int token2 = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
int token3 = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("a");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token3);
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token2);
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token1);
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
assertThat(factory.json()).isEqualTo("[\"a\"]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void flattenTopLevel() {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
try {
|
||||||
|
writer.beginFlatten();
|
||||||
|
fail();
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
assertThat(e).hasMessage("Nesting problem.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void flattenDoesNotImpactOtherTypesInObjects() throws Exception {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginObject();
|
||||||
|
{
|
||||||
|
int token = writer.beginFlatten();
|
||||||
|
writer.name("a");
|
||||||
|
writer.beginArray();
|
||||||
|
writer.value("aaa");
|
||||||
|
writer.endArray();
|
||||||
|
writer.beginObject();
|
||||||
|
{
|
||||||
|
writer.name("b");
|
||||||
|
writer.value("bbb");
|
||||||
|
}
|
||||||
|
writer.endObject();
|
||||||
|
writer.name("c");
|
||||||
|
writer.beginArray();
|
||||||
|
writer.value("ccc");
|
||||||
|
writer.endArray();
|
||||||
|
writer.endFlatten(token);
|
||||||
|
}
|
||||||
|
writer.endObject();
|
||||||
|
assertThat(factory.json()).isEqualTo("{\"a\":[\"aaa\"],\"b\":\"bbb\",\"c\":[\"ccc\"]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void flattenDoesNotImpactOtherTypesInArrays() throws Exception {
|
||||||
|
JsonWriter writer = factory.newWriter();
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
int token = writer.beginFlatten();
|
||||||
|
{
|
||||||
|
writer.beginObject();
|
||||||
|
{
|
||||||
|
writer.name("a");
|
||||||
|
writer.value("aaa");
|
||||||
|
}
|
||||||
|
writer.endObject();
|
||||||
|
writer.beginArray();
|
||||||
|
{
|
||||||
|
writer.value("bbb");
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
writer.value("ccc");
|
||||||
|
writer.beginObject();
|
||||||
|
{
|
||||||
|
writer.name("d");
|
||||||
|
writer.value("ddd");
|
||||||
|
}
|
||||||
|
writer.endObject();
|
||||||
|
}
|
||||||
|
writer.endFlatten(token);
|
||||||
|
}
|
||||||
|
writer.endArray();
|
||||||
|
assertThat(factory.json()).isEqualTo("[{\"a\":\"aaa\"},\"bbb\",\"ccc\",{\"d\":\"ddd\"}]");
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user