Jackson Deserialization: How to map specific properties to getters and setters as well as loading all the properties into map of a same POJO?

I need to deserialize JSON string into POJO class with following scenario:

For example I have the following JSON String:

"entry":[
   {
        "id": "1",
        "name": "Type",
        "type": "General",
        "updated": "Tue, 12 Aug 2014 05:24:01.397Z",
        "summary": {
            "lang": "en",
            "value": "Testing for content"
        }
    },
    {
        "id": "1",
        "name": "Type",
        "type": "General",
        "updated": "Tue, 12 Aug 2014 05:24:01.397Z",
        "summary": {
            "lang": "en",
         "value": "Testing for content"
        }
      }
  ]

Now I need to deserialize the above JSON String into following POJO class:

public class EntryType
{
    private String id;

    private String name;

    private String type;

    private String updated;

    private Map<String,Object> allJsonProperties;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getUpdated() {
        return updated;
    }

    public void setUpdated(String updated) {
        this.updated = updated;
    }

    public Map<String, Object> getAllJsonProperties() {
        return allJsonProperties;
    }

    public void setAllJsonProperties(Map<String, Object> allJsonProperties) {
        this.allJsonProperties = allJsonProperties;
    }

}

I am able to map id,name,type,updated to the appropriate POJO class fields. But I don not know how to load id,name,type,updated,summary properties again into Map(allJsonProperties) field. Can any one guide me how to work out this?.

Note: I use Jackson API version 2.2.2

Upvotes: 3

Views: 5607

Answers (2)

Alexey Gavrilov
Alexey Gavrilov

Reputation: 10853

You can consider deserialising your object twice. Firstly, create an instance using a constructor with a map parameter marked with the @JsonCreator annotation. Secondly, populate the newly created instance with the json values using ObjectMapper.readerForUpdating method.

Here is an example:

public class JacksonForUpdate {

    public static class Bean {
        private String name;
        private Map<String, Object> properties;

        public void setName(String name) {
            this.name = name;
        }

        @JsonCreator
        public Bean(Map<String, Object> properties) {
            this.properties = properties;
        }

        @Override
        public String toString() {
            return "Bean{" +
                    "name='" + name + '\'' +
                    ", properties=" + properties +
                    '}';
        }
    }
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        final String json = "{\"name\":\"value\"}";
        Bean object = mapper.readValue(json, Bean.class);
        System.out.println(mapper.readerForUpdating(object).readValue(json));
    }
}

Output:

Bean{name='value', properties={name=value}}

UPDATE: The solution above wont work for deserialisation of an array of objects. One possible workaround is to construct the object out of a JsonNode, set the properties map using the ObjectMapper.convertValue conversion, and populate the field value as before.

Note that the ObjectMapper needs to be accessible inside this bean class which is can be done using the Jackson value injection.

Here is an example:

public class JacksonForUpdate2 {

    public static class Bean {
        private String name;
        private Map<String, Object> properties;

        public void setName(String name) {
            this.name = name;
        }

        @JsonCreator
        public Bean(JsonNode node, @JacksonInject ObjectMapper mapper) throws IOException {
            this.properties = mapper.convertValue(node, Map.class);
            mapper.readerForUpdating(this).readValue(node);
        }

        @Override
        public String toString() {
            return "Bean{" +
                    "name='" + name + '\'' +
                    ", properties=" + properties +
                    '}';
        }
    }
    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        // make the mapper to be available for the bean
        mapper.setInjectableValues(new InjectableValues.Std().addValue(ObjectMapper.class, mapper));
        final String json = "[{\"name\":\"value\"},{\"name\":\"value2\"}]";
        System.out.println( mapper.readValue(json, new TypeReference<List<Bean>>() {}));
    }
}

Output:

[Bean{name='value', properties={name=value}}, Bean{name='value2', properties={name=value2}}]

This doesn't longer look very elegant though.

Upvotes: 2

SANN3
SANN3

Reputation: 10069

We can use Custom Deserializer

 import java.io.IOException;

import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.JsonToken;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;

    public class EntryTypeDeSerializer extends JsonDeserializer<EntryType>
    {

        @Override
        public EntryType deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            EntryType entryType = new EntryType();
                while (jp.nextToken() != JsonToken.END_OBJECT) {
                    String name = jp.getCurrentName();
                    if ("id".equals(name)) {
                        jp.nextToken();
                        entryType.setId(jp.getText());
                    } else if ("name".equals(name)) {
                        jp.nextToken();
                        entryType.setName(jp.getText());
                    }
                    .
                    .
                    .
                    .
                    else{

                    }
            }
            return entryType;
        }
    }

Main class

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule", new Version(1, 0, 0, null));
simpleModule.addDeserializer(EntryType.class, new EntryTypeDeSerializer());
objectMapper.registerModule(simpleModule);

EntryType entryType = objectMapper.readValue(json, EntryType.class);

Upvotes: 2

Related Questions