无阻塞地读取json流

时间:2012-06-02 11:52:01

标签: java jackson nonblocking

我希望能够使用Jackson(2)读取json消息的流(来自套接字)。

有一些方法可以将Reader作为源传递,例如:

ObjectMapper mapper = new ObjectMapper();
MyObject obj = mapper.readValue(aReader, MyObject.class);

但是这将阻止整个json消息到达,我想避免这种情况。

有没有办法有一个缓冲区,我可以继续添加字节,并能够询问缓冲区是否包含特定类的完整json表示?
类似的东西:

JsonBuffer buffer = new JsonBuffer(MyObject.class);
...
buffer.add(readBytes);
if (buffer.hasObject()) {
    MyObject obj = buffer.readObject();
}

感谢。

6 个答案:

答案 0 :(得分:3)

您可以使用JsonParser获取单个事件/令牌(这是ObjectMapper内部使用的内容),这样可以实现更细粒度的访问。但是所有当前功能都使用阻塞IO,因此无法进行所谓的非阻塞(即“异步”)解析。

答案 1 :(得分:2)

这不是我的问题的答案,而是我提出的更多解决方法。

我没有处理杰克逊方面的非阻塞IO,而是在我的协议中实现了它 发送时所有json消息都填充4字节int,其中包含消息其余部分的长度 现在阅读json消息变得简单了,我只是找出长度是什么,异步读取它然后可以使用Jackson来生成字符串。

如果有人知道如何直接从杰克逊那里做到这一点,我仍然有兴趣知道。

答案 2 :(得分:2)

(我知道这个帖子已经老了,但由于没有接受的答案,我想加我的,以防有人还在读这个。)

我刚刚发布了一个名为Actson(https://github.com/michel-kraemer/actson)的新库。它的工作方式几乎与OP建议的一样。您可以使用字节来提供它,直到它返回一个或多个JSON事件。当它消耗了所有输入数据时,您需要输入更多字节并获取下一个JSON事件。此过程将继续,直到完全使用JSON文本。

如果您了解Aalto XML(https://github.com/FasterXML/aalto-xml),那么您应该能够快速熟悉Actson,因为界面几乎相同。

这是一个简单的例子:

// JSON text to parse
byte[] json = "{\"name\":\"Elvis\"}".getBytes(StandardCharsets.UTF_8);

JsonParser parser = new JsonParser(StandardCharsets.UTF_8);

int pos = 0; // position in the input JSON text
int event; // event returned by the parser
do {
    // feed the parser until it returns a new event
    while ((event = parser.nextEvent()) == JsonEvent.NEED_MORE_INPUT) {
        // provide the parser with more input
        pos += parser.getFeeder().feed(json, pos, json.length - pos);

        // indicate end of input to the parser
        if (pos == json.length) {
            parser.getFeeder().done();
        }
    }

    // handle event
    System.out.println("JSON event: " + event);
    if (event == JsonEvent.ERROR) {
        throw new IllegalStateException("Syntax error in JSON text");
    }
} while (event != JsonEvent.EOF);

答案 3 :(得分:1)

Jackson支持非阻塞JSON流解析as of 2.9。您可以在Spring Framework 5 Jackson2Tokenizer中找到有关如何使用它的示例。

答案 4 :(得分:0)

我找到了解决这个问题的方法。您可以使用方法inputStream.available来检查流中是否有一些字节,并且此方法也是非阻塞的。因此,您可以使用此方法检查是否有什么是 - 解析值,如果不是 - 等待一段时间再次检查。两个例子如下所示。

安全风格 - 检查START_OBJECT json令牌:

while (run.get()) { 
    if (inputStream.available() > 0) {
        for (JsonToken jsonToken; (null != (jsonToken = jsonParser.nextToken())); ) {
            if (JsonToken.START_OBJECT.equals(jsonToken)) {
                outputStream.onNext(jsonParser.readValueAs(tClass));
                break;
            }
        }
    } else {
        Thread.sleep(200); // Or can be another checking time.
    }
}

或最简单的风格:

while (run.get()) {
    if (inputStream.available() > 0) {
        outputStream.onNext(jsonParser.readValueAs(tClass));
    } else {
        Thread.sleep(200); // Or can be another checking time.
    }
}

答案 5 :(得分:0)

使用 Gson 怎么样?

private fun handleActions(webSocketMessage: WebSocketMessage, webSocketSession: WebSocketSession): Mono<WebSocketMessage> {
    val action = Gson().fromJson(webSocketMessage.payloadAsText, ActionWs::class.java)
    return when (action.action) {
        "REGISTER" -> companyService.createCompany(action.company)
            .map { webSocketSession.textMessage(jacksonObjectMapper().writeValueAsString(it)) }
        else -> Mono.just(webSocketSession.textMessage(Gson().toJson(CompanyInfo(0, 0, 0, "ACAO INVALIDA!"))))
    }
}