【问题标题】:Parsing JSON into Jackson using a stream/object approach使用流/对象方法将 JSON 解析为 Jackson
【发布时间】:2012-11-08 02:30:54
【问题描述】:

我有一个可以有多种类型的 JSON 文件。

例如:

{
    "dog": {
        "owner" : "John Smith",
        "name" : "Rex",
        "toys" : {
            "chewtoy" : "5",
            "bone" : "1"
        }
    },
    "person": {
        "name" : "John Doe",
        "address" : "23 Somewhere Lane"
    }
    // Further examples of dogs and people, and a few other types.
}

我想将这些解析为对象。 IE。我想创建一个具有所有者/名称/玩具属性的 Dog 对象和具有名称/地址属性的人,并使用 Jackson 读取并从中创建对象。

排序很重要——例如,我需要知道 Rex 比 John Doe 来得早。我更喜欢使用类似流的方法(即读取 Rex 并将其解析为 Dog 对象,对其进行处理,然后丢弃它,然后转到 John Doe)。所以我需要一种基于流的方法。

我不知道如何同时使用流读取 API(按顺序执行)和 ObjectMapper 接口(以便从 JSON 创建 Java 对象)来完成此操作。

【问题讨论】:

  • (1) 您关于流或类似 SAX 的解析的问题是完全有效的。 +1。但是(2)如果在字典中排序很重要,那么您的数据设计得不好。 JSON 字典本质上是无序的。如果您需要订单,请使用数组并将类型(狗/人)信息也编码为属性。
  • 嗯。数据源可能是不可更改的(不在我的控制之下)。当您说使用数组并对信息进行编码时,您的意思是手动执行此操作吗? (通读所有标记并创建调用适当设置器的适当对象)或者有没有办法使用杰克逊做到这一点?
  • 我的意思是如果顺序很重要,JSON 数据应该以数组的形式出现,并且每个对象都有编码的类型。但是,如果您不控制 JSON 数据,那么没关系 - 您将不得不按照您的建议处理流解析。 :) 我没有你实际问题的答案,尽管这里的其他人肯定会。但是要知道,想出这种 JSON 格式的人是在玩火。依赖字典中的键顺序是非常脆弱的,更不用说它给试图处理它的人(你)带来的痛苦——这与大多数工具的本质背道而驰。
  • 感谢您的回复。如果我确实更改了数据,以便将对象存储为数组,那么是否可以执行组合流/对象映射器解析方法?

标签: java json parsing jackson


【解决方案1】:

为此,您需要在工厂中使用对象映射器

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.ObjectMapper;
...
private static ObjectMapper mapper = new ObjectMapper();
private static JsonFactory factory = mapper.getJsonFactory();

然后为输入创建一个解析器。

JsonParser parser = factory.createJsonParser(in);

现在您可以混合调用 parser.nextToken() 和调用 parser.readValueAs(Class c)。这是一个从地图中获取类的示例:

Map<String, Class<?>> classMap = new HashMap<String, Class<?>>();
classMap.put("dog", Dog.class);
classMap.put("person", Person.class);

InputStream in = null;
JsonParser parser = null;
List<Object> results = new ArrayList<Object>();
try {
  in = this.getClass().getResourceAsStream("input.json");
  parser = factory.createJsonParser(in);
  parser.nextToken();// JsonToken.START_OBJECT
  JsonToken token = null;
  while( (token = parser.nextToken()) == JsonToken.FIELD_NAME ) {
    String name = parser.getText();
    parser.nextToken(); // JsonToken.START_OBJECT
    results.add(parser.readValueAs(classMap.get(name)));
  }
  // ASSERT: token = JsonToken.END_OBJECT
}
finally {
  IOUtils.closeQuietly(in);
  try {
    parser.close();
  }
  catch( Exception e ) {}
}

【讨论】:

  • 我想我现在明白了。当我最初尝试这样做时,我很挣扎,因为我不知道我在哪个对象(“狗”或“人”),但是如果数据被格式化为一个数组,其中狗/人的值作为值在“类型”属性中,我可以做到这一点。谢谢大家。
  • 一个很好的答案。但是,如果您可以使用最新的 Jackson 库重写您的代码 sn-p,那就太好了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-22
  • 2016-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多