当用 java 解析 JSON 时,如何将 getText() 限制在最大数量范围内?
When parsing JSON with java, how to getText() bounded by a maximum amount?
我正在尝试解析 Apache Tika Server 的 rmeta
网络服务端点的输出:https://cwiki.apache.org/confluence/display/TIKA/TikaServer#TikaServer-RecursiveMetadataandContent
它的有效载荷如下所示:
[
{"Application-Name":"Microsoft Office Word",
"Application-Version":"15.0000",
"X-Parsed-By":["org.apache.tika.parser.DefaultParser","org.apache.tika.parser.microsoft.ooxml.OOXMLParser"],
"X-TIKA:content":"this content string can be many MB large"
...
},
{"Content-Encoding":"ISO-8859-1",
"Content-Length":"8",
"Content-Type":"text/plain; charset=ISO-8859-1"
"X-TIKA:content":"again, this content string can be many MB large",
...
}
...
]
如前所述,X-TIKA:content
字符串可能非常大。如果我将整个字符串加载到内存中,足以 OOM 我的 JVM。
所以如果我像这样使用 JsonParser.getText()
:
private void parseRmetaResponse(CloseableHttpResponse response) {
ObjectMapper objectMapper = new ObjectMapper();
JsonFactory jsonFactory = objectMapper.getFactory();
JsonParser jsonParser = jsonFactory.createParser(response.getEntity().getContent());
JsonToken arrayStartToken = jsonParser.nextToken();
if (arrayStartToken != JsonToken.START_ARRAY) {
throw new IllegalStateException("The first element of the Json structure was expected to be a start array token, but it was: " + arrayStartToken);
}
JsonToken nextToken = jsonParser.nextToken();
while (nextToken != JsonToken.END_ARRAY) {
parseNextField(jsonParser);
}
}
private String getTextContents(JsonParser jsonParser, OutputStream os, Metadata metadata) throws IOException {
String nextAttr = jsonParser.nextFieldName();
if ("X-TIKA:content".equals(nextAttr)) {
return jsonParser.getText();
}
// ...
}
它很容易出现 OOM 崩溃,因为我无法在不耗尽所有 JVM 堆的情况下将所有该字符串加载到内存中。
相反,我有一个最大字符数参数 maxChars
,我想在达到该数字后停止从 X-TIKA:content
读取字符。
如何说“获取文本,但最多只能读取 maxChars
个字符,并丢弃任何其他字符”?
我可以使用 GSON、Fasterxml Jackson 或任何其他库来帮助我完成我需要做的事情。
而不是调用 String getText()
, you can call int getText(Writer writer)
。
给它一个自定义 Writer
that works similar to StringWriter
,但丢弃超过给定阈值的任何字符。
你会像这样使用它:
if ("X-TIKA:content".equals(nextAttr)) {
try (LimitedStringWriter writer = new LimitedStringWriter(maxParseChars)) {
jsonParser.getText(writer);
return writer.toString();
}
}
编写 LimitedStringWriter
class 是您的工作。
提问者 (Nicholas DiPiazza) 添加:
以下是您可以用作示例的实现示例:https://github.com/ow2-proactive/scheduling/blob/master/common/common-api/src/main/java/org/ow2/proactive/utils/BoundedStringWriter.java
我正在尝试解析 Apache Tika Server 的 rmeta
网络服务端点的输出:https://cwiki.apache.org/confluence/display/TIKA/TikaServer#TikaServer-RecursiveMetadataandContent
它的有效载荷如下所示:
[
{"Application-Name":"Microsoft Office Word",
"Application-Version":"15.0000",
"X-Parsed-By":["org.apache.tika.parser.DefaultParser","org.apache.tika.parser.microsoft.ooxml.OOXMLParser"],
"X-TIKA:content":"this content string can be many MB large"
...
},
{"Content-Encoding":"ISO-8859-1",
"Content-Length":"8",
"Content-Type":"text/plain; charset=ISO-8859-1"
"X-TIKA:content":"again, this content string can be many MB large",
...
}
...
]
如前所述,X-TIKA:content
字符串可能非常大。如果我将整个字符串加载到内存中,足以 OOM 我的 JVM。
所以如果我像这样使用 JsonParser.getText()
:
private void parseRmetaResponse(CloseableHttpResponse response) {
ObjectMapper objectMapper = new ObjectMapper();
JsonFactory jsonFactory = objectMapper.getFactory();
JsonParser jsonParser = jsonFactory.createParser(response.getEntity().getContent());
JsonToken arrayStartToken = jsonParser.nextToken();
if (arrayStartToken != JsonToken.START_ARRAY) {
throw new IllegalStateException("The first element of the Json structure was expected to be a start array token, but it was: " + arrayStartToken);
}
JsonToken nextToken = jsonParser.nextToken();
while (nextToken != JsonToken.END_ARRAY) {
parseNextField(jsonParser);
}
}
private String getTextContents(JsonParser jsonParser, OutputStream os, Metadata metadata) throws IOException {
String nextAttr = jsonParser.nextFieldName();
if ("X-TIKA:content".equals(nextAttr)) {
return jsonParser.getText();
}
// ...
}
它很容易出现 OOM 崩溃,因为我无法在不耗尽所有 JVM 堆的情况下将所有该字符串加载到内存中。
相反,我有一个最大字符数参数 maxChars
,我想在达到该数字后停止从 X-TIKA:content
读取字符。
如何说“获取文本,但最多只能读取 maxChars
个字符,并丢弃任何其他字符”?
我可以使用 GSON、Fasterxml Jackson 或任何其他库来帮助我完成我需要做的事情。
而不是调用 String getText()
, you can call int getText(Writer writer)
。
给它一个自定义 Writer
that works similar to StringWriter
,但丢弃超过给定阈值的任何字符。
你会像这样使用它:
if ("X-TIKA:content".equals(nextAttr)) {
try (LimitedStringWriter writer = new LimitedStringWriter(maxParseChars)) {
jsonParser.getText(writer);
return writer.toString();
}
}
编写 LimitedStringWriter
class 是您的工作。
提问者 (Nicholas DiPiazza) 添加:
以下是您可以用作示例的实现示例:https://github.com/ow2-proactive/scheduling/blob/master/common/common-api/src/main/java/org/ow2/proactive/utils/BoundedStringWriter.java