Java 无阻塞地读取json流
我希望能够使用Jackson(2)读取json消息流(从套接字) 有几种方法可以将读卡器作为源传递,例如:Java 无阻塞地读取json流,java,jackson,nonblocking,Java,Jackson,Nonblocking,我希望能够使用Jackson(2)读取json消息流(从套接字) 有几种方法可以将读卡器作为源传递,例如: ObjectMapper mapper = new ObjectMapper(); MyObject obj = mapper.readValue(aReader, MyObject.class); 但这将阻止整个json消息到达,我希望避免这种情况 有没有一种方法可以让我不断向缓冲区添加字节,并能够询问缓冲区是否包含特定类的完整json表示? 比如: JsonBuffer buffer
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();
}
谢谢。您可以使用
JsonParser
获取单个事件/令牌(这是ObjectMapper
内部使用的),这允许更细粒度的访问。但所有当前的功能都使用阻塞IO,因此无法进行所谓的非阻塞(也称为“异步”)解析
编辑:2019-09-18——更正:Jackson 2.9()增加了对非阻塞/异步JSON解析的支持(问题)这不是我问题的答案,而是我想出的更多解决方法 我没有处理Jackson方面的非阻塞IO,而是在协议中实现了它。
发送时,所有json消息都用4字节整数填充,该整数保存消息其余部分的长度。
现在读取json消息变得很容易,我只需找出长度,异步读取它,然后就可以使用Jackson和结果字符串 如果有人知道如何直接从Jackson那里做到这一点,我仍然有兴趣知道。(我知道这条线索很旧,但由于没有公认的答案,我想添加我的,以防万一还有人读到这篇文章) 我刚刚发布了一个名为Actson()的新库。它几乎像OP建议的那样工作。您可以向它提供字节,直到它返回一个或多个JSON事件。当它消耗了所有的输入数据后,您将向它提供更多的字节,并获取下一个JSON事件。这个过程一直持续到JSON文本被完全使用为止 如果您知道aaltoxml(),那么您应该能够快速熟悉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);
我找到了解决这个问题的有效方法。您可以使用方法
inputStream.available
检查流中是否有一些字节,该方法也是非阻塞的。所以,您可以使用这个方法来检查当是时是否有一些东西-解析值,如果没有-等待一段时间再次检查。下面是两个例子
安全样式-检查开始对象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.
}
}
Jackson支持非阻塞JSON流解析。您可以找到一个关于如何在SpringFramework5中使用它的示例。如何使用
private fun handleActions(webSocketMessage:webSocketMessage,webSocketSession:webSocketSession):Mono{
val action=Gson().fromJson(webSocketMessage.payloadAsText,ActionWs::class.java)
返回时间(action.action){
“注册”->companyService.createCompany(action.company)
.map{webSocketSession.textMessage(jacksonObjectMapper().writeValueAsString(it))}
else->Mono.just(webSocketSession.textMessage(Gson().toJson)(CompanyInfo(0,0,0,“ACAO INVALIDA!”))
}
}
谢谢,但我确实在寻找异步方式。。我设法找到了一个解决办法,并添加了我自己的答案。是的,我正要提到带长度前缀的外部框架可能是一种方式。。。但我想你可能已经知道了这种可能性。我最初是直接通过jackson实现的,但当我看到它只实现阻塞IO时,我开始考虑其他选项。阻塞IO是一种方法——我所知道的Java JSON解析器都不支持推式解析。其他的很少(对于XML,Aalto是这样做的)。非阻塞是一个主要的PITA,我在写了一些东西之后说了这些。使用NIO是痛苦的,但除此之外,当结合诸如压缩、身份验证等东西时,事情变得非常复杂。我发现Netty使NIO变得不那么痛苦,但我同意,这并不总是正确的方法,对于身份验证,我使用阻塞IO,但对于通常的流,我需要实现NIO,只是执行得更好。
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!"))))
}
}