简体   繁体   中英

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:

  • Some basic JSON properties should be mapped to the getters and setters fields in POJO class.
  • And again all JSON properties should be loaded into the Map filed of the same POJO class.

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

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM