Но intelliJ говорит мне, что стандарт JSON допускает только одно значение верхнего уровня.
Да.То, что вы реализовали, является сцепленным JSON (см. more ).Вы все еще можете использовать его, но ваши файлы записей не будут анализироваться с помощью JSON-совместимых инструментов.Если вы не хотите использовать «сырые» потоки JSON, вы можете реализовать потоки на основе массива JSON.Это требует некоторой работы, но позволит вам создавать и использовать действительные документы JSON.
final class JsonStreams {
private JsonStreams() {
}
@SuppressWarnings("resource")
static void copy(final JsonReader reader, final JsonWriter writer)
throws IOException {
int level = 0;
loop:
for ( JsonToken token = reader.peek(); token != null; token = reader.peek() ) {
switch ( token ) {
case BEGIN_ARRAY:
reader.beginArray();
writer.beginArray();
++level;
break;
case END_ARRAY:
reader.endArray();
writer.endArray();
if ( --level == 0 ) {
return;
}
break;
case BEGIN_OBJECT:
reader.beginObject();
writer.beginObject();
++level;
break;
case END_OBJECT:
reader.endObject();
writer.endObject();
if ( --level == 0 ) {
return;
}
break;
case NAME:
final String name = reader.nextName();
writer.name(name);
break;
case STRING:
final String s = reader.nextString();
writer.value(s);
break;
case NUMBER:
final Number n = new BigDecimal(reader.nextString());
writer.value(n);
break;
case BOOLEAN:
final boolean b = reader.nextBoolean();
writer.value(b);
break;
case NULL:
reader.nextNull();
writer.nullValue();
break;
case END_DOCUMENT:
break loop;
default:
throw new AssertionError(token);
}
}
}
static void appendToArray(final JsonReader jsonReader, final JsonWriter jsonWriter, final Consumer<? super JsonWriter> consumer)
throws IOException {
// Making JsonReader set to END_DOCUMENT if there is a blank/whitespace document
try {
jsonReader.hasNext();
} catch ( final EOFException ignored ) {
}
// Checking the outer-most JSON token
final JsonToken beginJsonToken = jsonReader.peek();
switch ( beginJsonToken ) {
// If it's a blank/whitespace document, then just write a single row
case END_DOCUMENT:
jsonWriter.beginArray();
consumer.accept(jsonWriter);
jsonWriter.endArray();
break;
// If the document starts with [, then unroll all its values
case BEGIN_ARRAY:
jsonReader.beginArray();
jsonWriter.beginArray();
final JsonToken endJsonToken = jsonReader.peek();
if ( endJsonToken != JsonToken.END_ARRAY ) {
// Copy all existing values
while ( jsonReader.hasNext() ) {
final JsonToken rowJsonToken = jsonReader.peek();
switch ( rowJsonToken ) {
case BEGIN_ARRAY:
case BEGIN_OBJECT:
case STRING:
case NUMBER:
case BOOLEAN:
case NULL:
copy(jsonReader, jsonWriter);
break;
// The rest of tokens must never happen because we copy values
case END_ARRAY:
case END_OBJECT:
case NAME:
case END_DOCUMENT:
default:
throw new AssertionError(rowJsonToken);
}
}
}
consumer.accept(jsonWriter);
// End the document with ]
jsonReader.endArray();
jsonWriter.endArray();
break;
default:
throw new JsonParseException("Unexpected outer token: " + beginJsonToken);
}
}
}
public static void main(final String... args)
throws IOException {
final Iterable<String> resourceNames = ImmutableList.of("1-blank.json", "2-empty.json", "3-some.json");
for ( final String resourceName : resourceNames ) {
try ( final JsonReader jsonReader = Resources.getPackageResourceJsonReader(Q50418170.class, resourceName) ) {
final Writer writer = new StringWriter();
final JsonWriter jsonWriter = new JsonWriter(writer);
JsonStreams.appendToArray(jsonReader, jsonWriter, jw -> {
gson.toJson(fooBar(1, 2), jw);
gson.toJson(fooBar(3, 4), jw);
gson.toJson(fooBar(5, 6), jw);
});
System.out.println(writer);
}
}
}
private static JsonElement fooBar(final int foo, final int bar) {
final JsonObject jsonObject = new JsonObject();
jsonObject.add("foo", new JsonPrimitive(foo));
jsonObject.add("bar", new JsonPrimitive(bar));
return jsonObject;
}
Тестовые документы, приведенные выше:
1-blank.json
2-empty.json
[
]
3-some.json
Этот документ отформатирован намеренно, но я буду хранить документы JSON минимизированными (поэтому, Я бы не использовал setIndent
).
[
{
"foo": 0,
"bar": 0,
"baz": [
1,
2,
3
]
}
]
Тест для вышеуказанных документов даст следующий вывод
[{"foo":1,"bar":2},{"foo":3,"bar":4},{"foo":5,"bar":6}]
[{"foo":1,"bar":2},{"foo":3,"bar":4},{"foo":5,"bar":6}]
[{"foo":0,"bar":0,"baz":[1,2,3]},{"foo":1,"bar":2},{"foo":3,"bar":4},{"foo":5,"bar":6}]