当用 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