我有一个Java应用程序,它使用Spring的RestTemplate API编写简洁,可读的JSON REST服务使用者:
在本质上:
RestTemplate rest = new RestTemplate(clientHttpRequestFactory);
ResponseEntity<ItemList> response = rest.exchange(url,
HttpMethod.GET,
requestEntity,
ItemList.class);
for(Item item : response.getBody().getItems()) {
handler.onItem(item);
}
Run Code Online (Sandbox Code Playgroud)
JSON响应包含一个项目列表,正如您所看到的,我在自己的代码中有一个事件驱动的设计来依次处理每个项目.然而,整个列表是在存储器中作为其一部分response
,其RestTemplate.exchange()
产生.
我希望应用程序能够处理包含大量项目的响应 - 比如50,000,在这种情况下,实现有两个问题:
是否有一个相当成熟的Java JSON/REST客户端API,以事件驱动的方式消耗响应?
我想它可以让你做类似的事情:
RestStreamer rest = new RestStreamer(clientHttpRequestFactory);
// Tell the RestStreamer "when, while parsing a response, you encounter a JSON
// element matching JSONPath "$.items[*]" pass it to "handler" for processing.
rest.onJsonPath("$.items[*]").handle(handler);
// Tell the RestStreamer to make an HTTP request, parse it as a stream.
// We expect "handler" to get passed an object each time the parser encounters
// an item.
rest.execute(url, HttpMethod.GET, requestEntity);
Run Code Online (Sandbox Code Playgroud)
我很欣赏我可以使用来自Jackson,GSON等的流式JSON API来实现这种行为的实现 - 但是我很想知道那里有一些东西能够可靠地使用简洁,富有表现力的API,与HTTP方面.
几个月后; 回来回答我自己的问题.
我没有找到一个表达性的API来做我想要的,但我能够通过将HTTP主体作为流来实现所需的行为,并使用Jackson来消费它JsonParser
:
ClientHttpRequest request =
clientHttpRequestFactory.createRequest(uri, HttpMethod.GET);
ClientHttpResponse response = request.execute();
return handleJsonStream(response.getBody(), handler);
Run Code Online (Sandbox Code Playgroud)
...使用handleJsonStream设计来处理如下所示的JSON:
{ items: [
{ field: value; ... },
{ field: value, ... },
... thousands more ...
] }
Run Code Online (Sandbox Code Playgroud)
...它验证了导致阵列开始的令牌; 它Item
每次遇到数组元素时都会创建一个对象,并将其提供给处理程序.
// important that the JsonFactory comes from an ObjectMapper, or it won't be
// able to do readValueAs()
static JsonFactory jsonFactory = new ObjectMapper().getFactory();
public static int handleJsonStream(InputStream stream, ItemHandler handler) throws IOException {
JsonParser parser = jsonFactory.createJsonParser(stream);
verify(parser.nextToken(), START_OBJECT, parser);
verify(parser.nextToken(), FIELD_NAME, parser);
verify(parser.getCurrentName(), "items", parser);
verify(parser.nextToken(), START_ARRAY, parser);
int count = 0;
while(parser.nextToken() != END_ARRAY) {
verify(parser.getCurrentToken(), START_OBJECT, parser);
Item item = parser.readValueAs(Item.class);
handler.onItem(item);
count++;
}
parser.close(); // hope it's OK to ignore remaining closing tokens.
return count;
}
Run Code Online (Sandbox Code Playgroud)
verify()
只是一个私有静态方法,如果前两个参数不相等则抛出异常.
关于这个方法的关键是无论流中有多少项,这个方法只有每个都有一个Item的引用.
小智 4
你可以尝试JsonSurfer,它旨在以事件驱动的方式处理 json 流。
JsonSurfer surfer = JsonSurfer.jackson();
Builder builder = config();
builder.bind("$.items[*]", new JsonPathListener() {
@Override
public void onValue(Object value, ParsingContext context) throws Exception {
// handle the value
}
});
surfer.surf(new InputStreamReader(response.getBody()), builder.build());
Run Code Online (Sandbox Code Playgroud)