使用Jackson来解析一组Json对象

时间:2014-07-19 00:07:45

标签: json jackson

我有一个包含json对象数组的文件:

[     {         “test1”:“abc”     },     {         “test2”:[1,2,3]     } ]

我希望使用Jackson的JsonParser从这个文件中获取输入流,并且在每次调用.next()时,我希望它从数组中返回一个对象,直到它用完对象或失败。

这可能吗?

用例: 我有一个大型文件,其中json数组填充了大量具有不同模式的对象。我希望一次获得一个对象,以避免将所有内容加载到内存中。

编辑:

我完全忘了提及。我的输入是随着时间的推移而添加的字符串。它随着时间的推移逐渐积累json。我希望能够通过对象从字符串中删除已解析的对象来解析它。

但我想这没关系!只要jsonParser将索引返回到字符串中,我就可以手动执行此操作。

4 个答案:

答案 0 :(得分:32)

是的,你可以使用ObjectMapper实现这种部分流 - 部分 - 树模型处理风格:

ObjectMapper mapper = new ObjectMapper();
JsonParser parser = mapper.getFactory().createParser(new File(...));
if(parser.nextToken() != JsonToken.START_ARRAY) {
  throw new IllegalStateException("Expected an array");
}
while(parser.nextToken() == JsonToken.START_OBJECT) {
  // read everything from this START_OBJECT to the matching END_OBJECT
  // and return it as a tree model ObjectNode
  ObjectNode node = mapper.readTree(parser);

  // do whatever you need to do with this object
}

parser.close();

答案 1 :(得分:12)

您要找的是Jackson Streaming API。这是一个使用Jackson Streaming API的代码片段,可以帮助您实现所需。

JsonFactory factory = new JsonFactory();
JsonParser parser = factory.createJsonParser(new File(yourPathToFile));

JsonToken token = parser.nextToken();
if (token == null) {
    // return or throw exception
}

// the first token is supposed to be the start of array '['
if (!JsonToken.START_ARRAY.equals(token)) {
    // return or throw exception
}

// iterate through the content of the array
while (true) {

    token = parser.nextToken();
    if (!JsonToken.START_OBJECT.equals(token)) {
        break;
    }
    if (token == null) {
        break;
    }

    // parse your objects by means of parser.getXxxValue() and/or other parser's methods

}

答案 2 :(得分:3)

这是一个基于Ian Roberts'回答。如果它嵌套到文档中,您还可以使用JsonPointer查找起始位置。这避免了自定义编码略微麻烦的流式令牌方法以到达起点。在这种情况下,basePath是" /",但它可以是JsonPointer理解的任何路径。

Path sourceFile = Paths.get("/path/to/my/file.json");
// Point the basePath to a starting point in the file
JsonPointer basePath = JsonPointer.compile("/");
ObjectMapper mapper = new ObjectMapper();
try (InputStream inputSource = Files.newInputStream(sourceFile);
     JsonParser baseParser = mapper.getFactory().createParser(inputSource);
     JsonParser filteredParser = new FilteringParserDelegate(baseParser,
                    new JsonPointerBasedFilter(basePath), false, false);) {
    // Call nextToken once to initialize the filteredParser
    JsonToken basePathToken = filteredParser.nextToken();
    if (basePathToken != JsonToken.START_ARRAY) {
        throw new IllegalStateException("Base path did not point to an array: found " 
                                       + basePathToken);
    }
    while (filteredParser.nextToken() == JsonToken.START_OBJECT) {
        // Parse each object inside of the array into a separate tree model 
        // to keep a fixed memory footprint when parsing files 
        // larger than the available memory
        JsonNode nextNode = mapper.readTree(filteredParser);
        // Consume/process the node for example:
        JsonPointer fieldRelativePath = JsonPointer.compile("/test1");
        JsonNode valueNode = nextNode.at(fieldRelativePath);
        if (!valueNode.isValueNode()) {
            throw new IllegalStateException("Did not find value at "
                    + fieldRelativePath.toString() 
                    + " after setting base to " + basePath.toString());
        }
        System.out.println(valueNode.asText());
    }
}

答案 3 :(得分:0)

此示例直接从流中读取自定义对象:

源是一个java.io.File

ObjectMapper mapper = new ObjectMapper();
JsonParser parser = mapper.getFactory().createParser( source );
if ( parser.nextToken() != JsonToken.START_ARRAY ) {
    throw new Exception( "no array" );
}
while ( parser.nextToken() == JsonToken.START_OBJECT ) {
    CustomObj custom = mapper.readValue( parser, CustomObj.class );
    System.out.println( "" + custom );
}