我希望能够使用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();
}
感谢。
答案 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!"))))
}
}