在json中保存记录,附加它们并解析

时间:2018-05-18 19:35:50

标签: java json gson

我正在尝试使用类似数据库的GSON构建。我想存储相同对象的记录,并且能够随时附加新记录。此外,我正在尝试构建解析器,它将从json到ArrayList的所有对象。我怎么能这样做?目前我写了这样的东西:

public void addRecord(Record record) throws IOException {

    JsonWriter writer = new JsonWriter(new FileWriter("/file.json", true));

    writer.setIndent(" ");
    gson.toJson(record, Record.class, writer);
    writer.close();
}

但是,intelliJ告诉我,JSON标准只允许一个顶级值。怎么避免呢?据我所知,文件应该只包含一个列表,我应该添加新的对象,但我不知道如何。另外,如何将它们解析为ArrayList?

1 个答案:

答案 0 :(得分:1)

  

但是,intelliJ告诉我,JSON标准只允许一个顶级值。

是。 您实现的是串联JSON(请参阅more)。 您仍然可以使用它,但您的记录文件不会被符合JSON标准的工具解析。 如果你不想使用" raw" 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

&lt; no content;零长度文件&gt;

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}]