215

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

Alexandre
  • 4,382
  • 2
  • 23
  • 33

6 Answers6

390

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);
icedtrees
  • 6,134
  • 5
  • 25
  • 35
  • 25
    Unfortunatelly there is no treeToValue(TreeNode n,TypeReference type) variant like there is for readValue(). Bad news for anyone dealing with more complex types with generics :( – Espinosa Oct 05 '16 at 17:28
  • 18
    @Espinosa Per [jackson-databind#1294](https://github.com/FasterXML/jackson-databind/issues/1294), you'll want something like (unfortunately more verbose) `jsonObjectMapper.readValue(jsonObjectMapper.treeAsTokens(someJsonNode), someTypeReference)` – M. Justin Jun 27 '17 at 05:02
  • 1
    For older version use: `objectMapper.treeToValue(jsonNode, MyClass.class)` – amod Jan 24 '18 at 17:42
  • 3
    You can also use this method in StdDeserializer: `p.codec.treeToValue`. – galcyurio May 28 '18 at 17:10
  • @icedtrees jsonObjectMapper is an instance of JsonObjectMapper or just the ObjectMapper – KNDheeraj May 22 '19 at 11:47
  • Instead of jsonObjectMapper.treeAsTokens(someJsonNode) one can also use objectMapper.readerFor(MyClass::class).readValue(someJsonNode) with seemingly same amount of overhead, but with option to extract a reader for later use. – Maksim Gumerov Sep 22 '19 at 11:14
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.

Bugs
  • 4,491
  • 9
  • 32
  • 41
Eric Barr
  • 443
  • 4
  • 8
  • 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! – Alexandre Oct 31 '13 at 17:03
  • 7
    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); – gx0r Sep 25 '14 at 22:18
  • 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. – Eric Barr Oct 02 '14 at 17:08
  • @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 versions – Ivaylo Slavov Oct 23 '14 at 07:23
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);
mumrah
  • 361
  • 4
  • 3
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);
gx0r
  • 4,682
  • 2
  • 23
  • 24
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);
xbmono
  • 2,084
  • 2
  • 30
  • 50
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

Druckles
  • 3,161
  • 2
  • 41
  • 65