If you have a few years of experience in the Java ecosystem, and you're interested in sharing that experience with the community (and getting paid for your work of course), have a look at the "Write for Us" page. Cheers. Eugen

I just released Module 10 in the Master Class of “REST with Spring”:

>> THE "REST WITH SPRING" CLASSES

1. Overview

This quick tutorial will illustrate how to use Jackson 2 to deserialize JSON using a custom Deserializer.

If you want to dig deeper and learn other cool things you can do with the Jackson 2 – head on over to the main Jackson tutorial.

2. Standard Deserialization

Let’s start by defining 2 entities and see how Jackson will deserialize a JSON representation to these entities without any customization:

public class User {
    public int id;
    public String name;
}
public class Item {
    public int id;
    public String itemName;
    public User owner;
}

Now, let’s define the JSON representation we want to deserialize:

{
    "id": 1,
    "itemName": "theItem",
    "owner": {
        "id": 2,
        "name": "theUser"
    }
}

And finally, let’s unmarshall this JSON to Java Entities:

Item itemWithOwner = new ObjectMapper().readValue(json, Item.class);

3. Custom Deserializer on ObjectMapper

In the previous example, the JSON representation matched the java entities perfectly – next, we will simplify the JSON:

{
    "id": 1,
    "itemName": "theItem",
    "createdBy": 2
}

When unmarshalling this to the exact same entities – by default, this will of course fail:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: 
Unrecognized field "createdBy" (class org.baeldung.jackson.dtos.Item), 
not marked as ignorable (3 known properties: "id", "owner", "itemName"])
 at [Source: [email protected]; line: 1, column: 43] 
 (through reference chain: org.baeldung.jackson.dtos.Item["createdBy"])

We’ll solve this by doing our own deserialization with a custom Deserializer:

public class ItemDeserializer extends StdDeserializer<Item> { 

    public ItemDeserializer() { 
        this(null); 
    } 

    public ItemDeserializer(Class<?> vc) { 
        super(vc); 
    }

    @Override
    public Item deserialize(JsonParser jp, DeserializationContext ctxt) 
      throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        int id = (Integer) ((IntNode) node.get("id")).numberValue();
        String itemName = node.get("itemName").asText();
        int userId = (Integer) ((IntNode) node.get("createdBy")).numberValue();

        return new Item(id, itemName, new User(userId, null));
    }
}

As you can see, the deserializer is working with the standard Jackson representation of JSON – the JsonNode. Once the input JSON is represented as a JsonNode, we can now extract the relevant information from it and construct our own Item entity.

Simply put, we need to register this custom deserializer and simply deserialize the JSON normally:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Item.class, new ItemDeserializer());
mapper.registerModule(module);

Item readValue = mapper.readValue(json, Item.class);

4. Custom Deserializer on the Class

Alternatively we can also register the deserializer directly on the class:

@JsonDeserialize(using = ItemDeserializer.class)
public class Item {
    ...
}

With the deserializer defined at the class level, there is no need to register it on the ObjectMapper – a default mapper will work fine:

Item itemWithOwner = new ObjectMapper().readValue(json, Item.class);

This type of per-class configuration is very useful in situations in which we may not have direct access to the raw ObjectMapper to configure.

5. Conclusion

This articles shows how to leverage Jackson 2 to read non-standard JSON input – and how to map that input to any java entity graph with full control over the mapping.

The implementation of all these examples and code snippets can be found in my github project – this is an Eclipse based project, so it should be easy to import and run as it is.

Go deeper into building a REST API with Spring:

>> CHECK OUT THE COURSE

Sort by:   newest | oldest | most voted
Gábor Garami
Guest

Bug: The second JSON should contain `createdBy` instead of `owner`…

Eugen Paraschiv
Guest

Nice catch – I updated the article with the fix.
Thanks,
Eugen.

Anamika
Guest

My custom deserializer is not getting invoked. Do you know why this can happen. I am using Fasterxml jackson.

Eugen Paraschiv
Guest

Hi Anamika – can you please provide some code to look at (preferably on github) – without that, it’s hard to say why your deserializer isn’t invoked. Cheers,
Eugen.

Matt Krevs
Guest

When working with legacy systems, the attribute names of the JSON sometimes dont match the field names of a POJO. Additionally, sometimes we’ll want to ignore particular JSON fields altogether. Are there annotations/techniques for allowing for this without having to hand code your own deserialiser?

Denis
Guest

I get null on jp.getCodec(). Any idea?

Eugen Paraschiv
Guest

Hey Denis – well, there may be any number of reasons, so I’ll need a code sample – preferably a test I can run. Alternatively you can work backwards from my working example over on github and figure out what’s not working when you replace my entity with your own. Regardless – working code sample would make things easier. Cheers,

Eugen.

Denis
Guest

HI Eugen – Thank you for your quick reply. I use MongoJack to map the Json (Bson) from MongoDB to my objects. I still don’t know why I get the null from getCodec() but when I use jp.readValueAsTree() it works. See this example/issue https://github.com/jroper/mongojack/issues/1 – Cheers, Denis

Eugen Paraschiv
Guest
Hey Denis – so I took a quick look at that project – unfortunately it looks like getting even that test to work inside mongojack is a lenghty task (it doesn’t currently compile) – and it also look like even the original reporter gave up :). My suggestion is this – try to replicate the null (jp.getCodec()) in a working test without other frameworks involved. If it’s simply a Jackson problem – that should not be problematic – however if it’s a mongojack problem – then that may be worth following up there. If you do have a working test… Read more »
bsengar
Guest

Hi,
I would like to deserialize a JSON array with different
node names to Java object array. Any idea how can I do that with
Jackson.
For example, JSON looks like this

“65796”: {
“name”: “Harrow West”,
“country”: “E”,
“type”: “WMC”},

“11820”: {
“name”: “Brent and Harrow”,
“country”: “E”,
“type”: “LAC”},

“66065”: {
“name”: “Brent Central”,
“country”: “E”,
“type”: “WMC”},

Thanks

Eugen Paraschiv
Guest

First, the json is missing the start and end to be valid – I’m assuming you’re adding these portions when you run it through Jackson. Second, you should be able to register a custom deserializer (covered here) and then just deserialize the collection. Hope it helps. Cheers,
Eugen.

wpDiscuz