Convert JsonNode into POJO
Asked Answered
G

6

220

This may seem a little unusual, but I am looking for an efficient way to transform/map a JsonNode into a POJO.

I store some of my Model's information in json files and I have to support a couple of version of my model.

What I do is load the json file in memory in a JsonNode, apply a couple of versioning strategies to make it match the latest version of my Model.

    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);

Unless there's a faster way to do it, I will probably end up simply manually applying the JsonNodes to my Model

Geriatric answered 31/10, 2013 at 16:18 Comment(0)
L
399

In Jackson 2.4, you can convert as follows:

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

where jsonObjectMapper is a Jackson ObjectMapper.


In older versions of Jackson, it would be

MyClass newJsonNode = jsonObjectMapper.readValue(someJsonNode, MyClass.class);
Labroid answered 25/2, 2015 at 8:39 Comment(6)
Unfortunatelly there is no treeToValue(TreeNode n,TypeReference<T> type) variant like there is for readValue(). Bad news for anyone dealing with more complex types with generics :(Bareilly
@Bareilly Per jackson-databind#1294, you'll want something like (unfortunately more verbose) jsonObjectMapper.readValue(jsonObjectMapper.treeAsTokens(someJsonNode), someTypeReference)Orthopter
For older version use: objectMapper.treeToValue(jsonNode, MyClass.class)Sikko
You can also use this method in StdDeserializer: p.codec.treeToValue.Gourmand
@Labroid jsonObjectMapper is an instance of JsonObjectMapper or just the ObjectMapperSweeney
Instead of jsonObjectMapper.treeAsTokens(someJsonNode) one can also use objectMapper.readerFor(MyClass::class).<MyClass>readValue(someJsonNode) with seemingly same amount of overhead, but with option to extract a reader for later use.Eudo
T
10

This should do the trick:

mapper.readValue(fileReader, MyClass.class);

I say should because I'm using that with a String, not a BufferedReader but it should still work.

Here's my code:

String inputString = // I grab my string here
MySessionClass sessionObject;
try {
    ObjectMapper objectMapper = new ObjectMapper();
    sessionObject = objectMapper.readValue(inputString, MySessionClass.class);

Here's the official documentation for that call: http://jackson.codehaus.org/1.7.9/javadoc/org/codehaus/jackson/map/ObjectMapper.html#readValue(java.lang.String, java.lang.Class)

You can also define a custom deserializer when you instantiate the ObjectMapper: http://wiki.fasterxml.com/JacksonHowToCustomDeserializers

Edit: I just remembered something else. If your object coming in has more properties than the POJO has and you just want to ignore the extras you'll want to set this:

objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Or you'll get an error that it can't find the property to set into.

Tearful answered 31/10, 2013 at 16:24 Comment(4)
I'll use a CustomDeserializers, it's gonna save me a lot of headaches! I'll also be able to apply my versioning strategies in there with very little modifications. Thanks!Geriatric
The syntax is now: com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper(); mapper.disable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);Andro
Good point @llambda! I haven't touched the ObjectMapper since version 1.7.9, it looks like my answer is out of date by a few versions. Definitely check what version of Jackson you're using.Tearful
@EricBarr, I am using Jackson v1.9.11 and the syntax in your answer is the correct one for that version. Perhaps they tried to change things and reverted them again in the newer versionsMelancholia
H
5

If you're using org.codehaus.jackson, this has been possible since 1.6. You can convert a JsonNode to a POJO with ObjectMapper#readValue: 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);
Hunkers answered 6/1, 2015 at 2:18 Comment(3)
This methods seems to be missing in 2.4.4Eavesdrop
See icedtrees' answer below, for a version 2 solutionCiri
The documentation is now at fasterxml.github.io/jackson-databind/javadoc/2.5/com/fasterxml/…Legate
A
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);

If your JSON input in has more properties than your POJO has and you just want to ignore the extras in Jackson 2.4, you can configure your ObjectMapper as follows. This syntax is different from older Jackson versions. (If you use the wrong syntax, it will silently do nothing.)

mapper.disable(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNK‌​NOWN_PROPERTIES);
Andro answered 14/10, 2014 at 22:17 Comment(0)
A
1

This is also a different way and can be used for an array of objects

ObjectReader reader = mapper.readerFor(new TypeReference<List<SomeClass>>() {
});
assert someJsonNode.isArray()
List<SomeClass> list = reader.readValue(someJsonNode);
Antique answered 27/1, 2022 at 4:24 Comment(0)
C
0

If you don't have an ObjectMapper (if you're in a custom deserializer, for instance), you can use the ObjectCodec from the JsonParser parameter like this:

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

This will give you the something object back according to existing serialization rules for MyClass.

Thanks to @galcyurio for the comment:

You can also use this method in StdDeserializer: p.codec.treeToValue

Choler answered 1/3, 2023 at 15:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.