将JsonNode转换为POJO

220

这可能看起来有点不寻常,但我正在寻找一种高效的方法将JsonNode转换/映射为POJO

我将我的一些模型信息存储在json文件中,并且必须支持我的模型的几个版本。

我所做的是将json文件加载到内存中的JsonNode中,应用一些版本控制策略,使其与我的模型的最新版本匹配。

    ObjectMapper mapper = new ObjectMapper();
    BufferedReader fileReader = new BufferedReader(new FileReader(projPath));

    JsonNode rootNode = mapper.readTree(fileReader);

    //Upgrade our file in memory
    applyVersioningStrategy(rootNode);

    ProjectModel project = mapJsonNodeToProject(rootNode);

除非有更快的方法,否则我可能最终只能手动将JsonNodes应用于我的模型。

6个回答

396

在Jackson 2.4中,您可以按如下方式进行转换:

MyClass newJsonNode = jsonObjectMapper.treeToValue(someJsonNode, MyClass.class);

其中jsonObjectMapper是一个Jackson ObjectMapper


在旧版本的Jackson中,它将会是

MyClass newJsonNode = jsonObjectMapper.readValue(someJsonNode, MyClass.class);

25
很遗憾,对于像readValue()一样的treeToValue(TreeNode n,TypeReference<T> type)变体不存在。这对于处理更复杂的泛型类型的人来说是个坏消息 :( - Espinosa
18
@Espinosa Per jackson-databind#1294,您需要类似以下的内容(不幸的是,更加冗长)jsonObjectMapper.readValue(jsonObjectMapper.treeAsTokens(someJsonNode), someTypeReference) - M. Justin
2
对于旧版本,请使用:objectMapper.treeToValue(jsonNode, MyClass.class) - amod
4
您可以在StdDeserializer中使用此方法:p.codec.treeToValue。这个方法可以将树形结构转换为相应的Java对象。 - galcyurio
@icedtrees jsonObjectMapper 是 JsonObjectMapper 的一个实例,或者只是 ObjectMapper。 - KNDheeraj
除了使用 jsonObjectMapper.treeAsTokens(someJsonNode) 之外,我们还可以使用 objectMapper.readerFor(MyClass::class).<MyClass>readValue(someJsonNode)。这两种方法的开销似乎相同,但是后者可以提取一个 reader 以供以后使用。 - Maksim Gumerov

10

这应该能行:

mapper.readValue(fileReader, MyClass.class);

我使用的是 String,而不是 BufferedReader,所以我说“应该”能够工作。

这是我的代码:

String inputString = // I grab my string here
MySessionClass sessionObject;
try {
    ObjectMapper objectMapper = new ObjectMapper();
    sessionObject = objectMapper.readValue(inputString, MySessionClass.class);
这是该调用的官方文档:http://jackson.codehaus.org/1.7.9/javadoc/org/codehaus/jackson/map/ObjectMapper.html#readValue(java.lang.String, java.lang.Class)
您也可以在实例化ObjectMapper时定义自定义反序列化程序:http://wiki.fasterxml.com/JacksonHowToCustomDeserializers
编辑: 我刚想起另一件事。如果传入的对象具有比POJO更多的属性,并且您只想忽略额外的属性,则需要设置以下内容:
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

否则您将收到错误提示,无法找到要设置的属性。


我将使用CustomDeserializers,这将为我节省很多麻烦!我还能够在其中应用我的版本控制策略,只需进行很少的修改。谢谢! - Alexandre
7
现在的语法是:com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();mapper.disable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);该代码用于创建一个Jackson ObjectMapper对象,并禁用了在反序列化时遇到未知属性时抛出异常的特性。 - gx0r
不错的观点@llambda!自从1.7.9版本以来,我就没有碰过ObjectMapper了,看起来我的答案已经过时了几个版本。一定要检查你正在使用的Jackson版本。 - Eric Barr
@EricBarr,我正在使用Jackson v1.9.11,你回答中的语法是该版本的正确语法。也许他们尝试在新版本中更改了一些东西,然后又恢复了原样。 - Ivaylo Slavov

5
如果你正在使用org.codehaus.jackson,自1.6版本以来就可以实现这个功能。你可以使用ObjectMapper#readValue将JsonNode转换为POJO:http://jackson.codehaus.org/1.9.4/javadoc/org/codehaus/jackson/map/ObjectMapper.html#readValue(org.codehaus.jackson.JsonNode, java.lang.Class)。

    ObjectMapper mapper = new ObjectMapper();
    JsonParser jsonParser = mapper.getJsonFactory().createJsonParser("{\"foo\":\"bar\"}");
    JsonNode tree = jsonParser.readValueAsTree();
    // Do stuff to the tree
    mapper.readValue(tree, Foo.class);

5
这种方法似乎在2.4.4版本中缺失。 - Kevin Wittek
1
请查看icedtrees在下面的答案(https://dev59.com/amIj5IYBdhLWcg3w95nA#28714523),以获取版本2的解决方案。 - Tim Büthe
文档现在位于 https://fasterxml.github.io/jackson-databind/javadoc/2.5/com/fasterxml/jackson/databind/ObjectMapper.html。 - David Tonhofer

4
String jsonInput = "{ \"hi\": \"Assume this is the JSON\"} ";
com.fasterxml.jackson.databind.ObjectMapper mapper =
    new com.fasterxml.jackson.databind.ObjectMapper();
MyClass myObject = objectMapper.readValue(jsonInput, MyClass.class);

如果您的JSON输入包含比POJO属性更多的属性,并且您只想在Jackson 2.4中忽略额外的属性,您可以按照以下方式配置ObjectMapper。这种语法与旧版Jackson不同。(如果使用错误的语法,它将静默执行不做任何事情。)
mapper.disable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNK‌​NOWN_PROPERTIES);

1

这也是一种不同的方式,可以用于对象数组

ObjectReader reader = mapper.readerFor(new TypeReference<List<SomeClass>>() {
});
assert someJsonNode.isArray()
List<SomeClass> list = reader.readValue(someJsonNode);

0

如果您没有 ObjectMapper(例如,如果您在自定义反序列化器中),则可以像这样使用来自JsonParser参数的ObjectCodec

jsonParser.getCodec().treeToValue(root.get("something"), MyClass.class)

根据现有的MyClass序列化规则,这将返回something对象。

感谢@galcyurio的评论:

您还可以在StdDeserializer中使用此方法:p.codec.treeToValue


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接