mapping nested json and POJOs using Spring

28,113

Just use a nested Object like so:

public class Action implements Serializable {

    @Id
    private String id;
    private String name;
    private String applicationId;
    private String timeStamp;
    private String username;
    private Map<String, String> options;
    //Getters and Setters
}

This will give you this format:

{
    "id": "11954cd5-eec3-4f68-b0e8-a4d9b6a976a9",
    "name": "kill button",
    "applicationId": "34fa7bbf-e49f-4f2a-933a-de26b9fdb0f1",
    "timeStamp": "2014-03-05T11:51+0000",
    "username": "user1783",
    "options":{
          "data": "Click Here",
          "size": "36",
          "application":"facebook app"
     }
}

UPDATE: - Adding test to prove that the solution does indeed work.

public class ActionTest {

        @Test
        public void testObjectToJson() throws JsonProcessingException {

            Action action = new Action();
            action.setId("id");
            action.setUsername("username");
            action.setApplicationId("applicationId");
            action.setName("name");
            action.setTimeStamp("timestamp");
            Map<String, String> map = Maps.newHashMap();
            map.put("key", "value");
            map.put("key2", "value2");
            action.setOptions(map);

            ObjectMapper mapper = new ObjectMapper();

            String value = mapper.writeValueAsString(action);
            System.out.println(value);
        }

        @Test
        public void testJsonToObject() throws IOException {

            String json = "{\"id\":\"id\",\"name\":\"name\",\"applicationId\":\"applicationId\",\"timeStamp\":\"timestamp\",\"username\":\"username\",\"options\":{\"key\":\"value\", \"key2\":\"value2\"}}";

            ObjectMapper mapper = new ObjectMapper();

            Action value = mapper.readValue(json, Action.class);
            System.out.println(value);
        }
    }

    class Action {

        private String id;
        private String name;
        private String applicationId;
        private String timeStamp;
        private String username;
        private Map<String, String> options;

        public Action() {}

        @Override
        public String toString() {
            final StringBuffer sb = new StringBuffer("Action{");
            sb.append("id='").append(id).append('\'');
            sb.append(", name='").append(name).append('\'');
            sb.append(", applicationId='").append(applicationId).append('\'');
            sb.append(", timeStamp='").append(timeStamp).append('\'');
            sb.append(", username='").append(username).append('\'');
            sb.append(", options=").append(options);
            sb.append('}');
            return sb.toString();
        }

        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 getApplicationId() {
            return applicationId;
        }

        public void setApplicationId(String applicationId) {
            this.applicationId = applicationId;
        }

        public String getTimeStamp() {
            return timeStamp;
        }

        public void setTimeStamp(String timeStamp) {
            this.timeStamp = timeStamp;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public Map<String, String> getOptions() {
            return options;
        }

        public void setOptions(Map<String, String> options) {
            this.options = options;
        }
    }
Share:
28,113
mohi
Author by

mohi

Updated on May 23, 2020

Comments

  • mohi
    mohi almost 4 years

    I am implementing a REST API which send and receive data with json(I am totally new to this API design). I am using Spring framework and requestbody/responsebody for mapping. Initially, I had a pojo like this:

    public class Action implements Serializable {
    
        @Id
        private String id;
        private String name;
        private String applicationId;
        private String timeStamp;
        private String username;
        private String options;
        //Getters and Setters
    }
    

    and the json format for this pojo is like this:

    {
     "id": "11954cd5-eec3-4f68-b0e8-a4d9b6a976a9",
     "name": "kill button",
     "applicationId": "34fa7bbf-e49f-4f2a-933a-de26b9fdb0f1",
     "timeStamp": "2014-03-05T11:51+0000",
     "username": "user1783",
     "options": "facebook app" 
    }
    

    This is how the controller look like:I do not get any json, Spring is converting already to java object, should it do it manually myself?

    @RequestMapping(value = "applications/{appId}/actions", method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
    @ResponseBody
    public Action addAction(@PathVariable String appId, @RequestBody Action action) {
        return actionService.add(appId, action);
    }
    

    you can find a pretty json format of it here: https://gist.github.com/bakharzy/8948950

    I want to change the last pair in the json to be a json itself as it is shown in the second json format in gist. So user can send more information. Now that I have a new format for json which is kind of json in json, how should I change the pojo (private String options;) to store the data coming from second json format. Note that the inner json can have arbitrary number of pairs.

    My first idea is to change the options in pojo to something like Hash object. Is it doable? If so, how?

    Thanks

  • ninnemannk
    ninnemannk about 10 years
    This is fine when you don't care about your pojo mapping.. But when you're using direct pojo mapping for REST calls and using these objects in your application logic - this is not the way to go.
  • mohi
    mohi about 10 years
    Thanks.I want to give the user the flexibility to add arbitrary number of pairs to options. In my example, there are just 3 pairs, data, size and application. But I want it in a way which user can send 1 or more number of pairs in this options. Can you modify your solution for that?
  • Hot Licks
    Hot Licks about 10 years
    @ninnemannk - I don't know about that. Seems to me that lots of folks here are stumbling over the "automatic" POJO mapping of JSON when simply writing the code is simpler and clearer. (And what does this have to do with REST?)
  • Hot Licks
    Hot Licks about 10 years
    @user3207391 - For that options must be a Map (or something that simulates one).
  • ninnemannk
    ninnemannk about 10 years
    Let me make sure I understand what you're asking. You want to be able to pass in any number of fields in Options with varying keys (field name)?
  • ninnemannk
    ninnemannk about 10 years
    OP clearly stated that he was writing a REST api. Passing around maps is not good for doing logic or persisting data.
  • mohi
    mohi about 10 years
    yes ninnemannk, that is right. I think as Hot Licks said and I guessed, it can be done with Map structure.
  • Hot Licks
    Hot Licks about 10 years
    @ninnemannk - REST has nothing to do with how you construct the JSON.
  • ninnemannk
    ninnemannk about 10 years
    @user3207391 - A map would give you the functionality you're looking for as Hot Licks has said.
  • ninnemannk
    ninnemannk about 10 years
    I said nothing about the structure of the json. I simply stated that when doing application logic inside of his api it will be much easier with a structured object (OOP) than passing around a HashMap.
  • Hot Licks
    Hot Licks about 10 years
    @ninnemannk - Except that, as it turns out, he must have a HashMap anyway.
  • ninnemannk
    ninnemannk about 10 years
    He could easily achieve the same results by using a well structured ArrayList.
  • Hot Licks
    Hot Licks about 10 years
    @ninnemannk - ArrayList won't give you key->value mappings for free. And it would require introducing another tuple object to hold the pairs.
  • mohi
    mohi about 10 years
    Im trying it now and see if it works. Feel free to have a loo at the source code, its in github. The project name is thesis!
  • mohi
    mohi about 10 years
    @ninnemannk I tried to send a post request with this json but the options is not saved and is null.
  • mohi
    mohi about 10 years
    @HotLicks How do you handle an http post coming from user containing that json format? how can I save that? I have not used any decoder/encoder for mapping before. Is it necessary to use?
  • Hot Licks
    Hot Licks about 10 years
    If you use something to produce POJOs from JSON, you're using a decoder. When you send POJOs as JSON you're using a encoder.
  • mohi
    mohi about 10 years
    I am using Spring annotation responsebody and requestbody @HotLicks
  • Hot Licks
    Hot Licks about 10 years
    I'm not up on Spring.
  • ninnemannk
    ninnemannk about 10 years
    @user3207391 - I've updated my answer with a test that proves the solution does work. Please see the update.
  • mohi
    mohi about 10 years
    @ninnemannk Can you have a look at my controller, I've updated the question. Should I do the mapping myself as you did in your test?because RequestBody is doing the mapping I think now
  • ninnemannk
    ninnemannk about 10 years
    What you have there should work. ObjectMapper is what spring uses internally to parse the response. If you'd like, you could definitely try it manually. You can do so by changing your @RequestBody to a String and parsing it as I did in my test.
  • ninnemannk
    ninnemannk about 10 years
    Also, feel free to copy my test into your project. Give it a run & see if the version of ObjectMapper you're using gives the same results.
  • mohi
    mohi about 10 years
    Thank you so much, it is solved. This is working fine without mapping manually. I am not sure what was my problem from last night that I could not get it work! @ninnemannk
  • ninnemannk
    ninnemannk about 10 years
    @user3207391 No problem! Glad to be able to help. :)
  • Omega
    Omega about 3 years
    My Problem sounds very similar to this. I have tried this but i think i have to add few more things. Could you please help me with this question Nested JSON response from SQL View ? I'm running out of time :( @HotLicks