如何在java中解析流中的json

时间:2015-03-14 02:29:02

标签: java json stream

我需要编写一个使用socket与服务器通信的客户端。消息协议采用json格式。服务器将按需将多个json块推送到客户端。 消息是这样的:

{"a": 1, "b": { "c": 1}}{"a": 1, "b": { "c": 1}}... 

您可以看到json块之间没有分隔符或标识符。

我能找到的json解析器(如fastjson,jackson)都只能将流作为整个json块处理,甚至是它们提供的流api。当我使用这些api来解析流时,它们会在第一个json块的末尾抛出异常,表示下一个令牌" {"无效。

java中是否有json解析器可以处理我的问题?还是有其他方法可以解决这个问题?

2 个答案:

答案 0 :(得分:0)

您可以使用Genson执行此操作。 首先将其配置为允许" permissive"解析然后反序列化迭代器中的值。当你在迭代器上调用next时,Genson将逐个解析对象。因此,您可以通过这种方式解析非常大的输入。

Genson genson = new GensonBuilder().usePermissiveParsing(true).create();
ObjectReader reader = genson.createReader(inputStream);
Iterator<SomeObject> iterator = genson.deserializeValues(reader, GenericType.of(SomeObject.class));

这部分API有点冗长,因为用例并不常见。

UPDATE 在Genson 1.4中,usePermissiveParsing已被删除,有利于默认接受未包含在数组中的根值。见https://github.com/owlike/genson/issues/78

答案 1 :(得分:0)

最后,根据我的情况,它不会在java中找到JSON解析器。 我正在使用netty来构建网络应用程序。对于nio,当有来自网络的数据时,调用ByteToMessageDecoder中的解码方法。 在这个方法中,我需要从ByteBuf中找出JSON块。

由于没有可用的JSON解析器,我编写了一个从ByteBuf中拆分JSON块的方法。

    public static void extractJsonBlocks(ByteBuf buf, List<Object> out) throws UnsupportedEncodingException {
    // the total bytes that can read from ByteBuf
    int readable = buf.readableBytes();
    int bracketDepth = 0;
    // when found a json block, this value will be set
    int offset = 0;
    // whether current character is in a string value
    boolean inStr = false;
    // a temporary bytes buf for store json block
    byte[] data = new byte[readable];
    // loop all the coming data
    for (int i = 0; i < readable; i++) {
        // read from ByteBuf
        byte b = buf.readByte();
        // put it in the buffer, be care of the offset
        data[i - offset] = b;
        if (b == SYM_L_BRACKET && !inStr) {
            // if it a left bracket and not in a string value
            bracketDepth++;
        } else if (b == SYM_R_BRACKET && !inStr) {
            // if it a right bracket and not in a string value
            if (bracketDepth == 1) {
                // if current bracket depth is 1, means found a whole json block
                out.add(new String(data, "utf-8").trim());
                // create a new buffer
                data = new byte[readable - offset];
                // update the offset
                offset = i;
                // reset the bracket depth
                bracketDepth = 0;
            } else {
                bracketDepth--;
            }
        } else if (b == SYM_QUOTE) {
            // when find a quote, we need see whether preview character is escape.
            byte prev = i == 0 ? 0 : data[i - 1 - offset];
            if (prev != SYM_ESCAPE) {
                inStr = !inStr;
            }
        }

    }
    // finally there may still be some data left in the ByteBuf, that can not form a json block, they should be used to combine with the following datas
    // so we need to reset the reader index to the first byte of the left data
    // and discard the data used for json blocks
    buf.readerIndex(offset == 0 ? offset : offset + 1);
    buf.discardReadBytes();
}

也许这是一个不完美的解析器,但它现在适用于我的应用程序。