mapping nested json and POJOs using Spring
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;
}
}
mohi
Updated on May 23, 2020Comments
-
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 about 10 yearsThis 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 about 10 yearsThanks.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 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 about 10 years@user3207391 - For that
options
must be a Map (or something that simulates one). -
ninnemannk about 10 yearsLet 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 about 10 yearsOP clearly stated that he was writing a REST api. Passing around maps is not good for doing logic or persisting data.
-
mohi about 10 yearsyes ninnemannk, that is right. I think as Hot Licks said and I guessed, it can be done with Map structure.
-
Hot Licks about 10 years@ninnemannk - REST has nothing to do with how you construct the JSON.
-
ninnemannk about 10 years@user3207391 - A map would give you the functionality you're looking for as Hot Licks has said.
-
ninnemannk about 10 yearsI 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 about 10 years@ninnemannk - Except that, as it turns out, he must have a HashMap anyway.
-
ninnemannk about 10 yearsHe could easily achieve the same results by using a well structured ArrayList.
-
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 about 10 yearsIm 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 about 10 years@ninnemannk I tried to send a post request with this json but the options is not saved and is null.
-
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 about 10 yearsIf 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 about 10 yearsI am using Spring annotation responsebody and requestbody @HotLicks
-
Hot Licks about 10 yearsI'm not up on Spring.
-
ninnemannk about 10 years@user3207391 - I've updated my answer with a test that proves the solution does work. Please see the update.
-
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 about 10 yearsWhat 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 about 10 yearsAlso, 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 about 10 yearsThank 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 about 10 years@user3207391 No problem! Glad to be able to help. :)
-
Omega about 3 yearsMy 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