Reputation: 5446
I had the need to convert java objects to Map<String, String>
for a REST api wrapper I am writing. Any fields that were complex objects needed to be serialized to json. I figured out how to do that like this:
public static Map<String, String> toContentMap(Object object) throws JsonProcessingException {
Map<String, Object> objectParamMap = MAPPER.convertValue(object, new TypeReference<Map<String, Object>>() {});
Map<String, String> contentMap = new HashMap<>();
for (Entry<String, Object> entry : objectParamMap.entrySet()) {
String key = entry.getKey();
String value = MAPPER.writeValueAsString(entry.getValue());
contentMap.put(key, StringUtils.strip(value, "\""));
}
return contentMap;
}
Now I need a way to get from this Map<String, String>
representation back to the pojo object. Is this possible to do using mostly jackson apis?
Edit:
I guess I wasn't clear. I know the POJO I am going to/from. But it should be generic and work for any basic POJO.
An example:
class MyObject {
String fieldA;
Long fieldB;
MyOtherObject fieldC;
List<String> fieldD;
}
class MyOtherObject {
String fieldA;
String fieldB;
}
MyObject object = new MyObject("valueA", 20L,
new MyOtherObject("valueA", "valueB"),
Lists.newArrayList("array1", "array2"));
Map<String, String> contentMap = toContentMap(object);
/*
"fieldA" -> "valueA"
"fieldB" -> "20"
"fieldC" -> "{\"fieldA\":\"valueA\",\"fieldB\":\"valueB\"}"
"fieldD" -> "[\"array1\",\"array2\"]"
*/
MyObject newObject = fromContentMap(contentMap);
assertEquals(object, newObject)
Upvotes: 2
Views: 5766
Reputation: 191963
Based on your comment
it should work for any POJO I ask it to
I think you are looking for the @JsonAnyGetter
and @JsonAnySetter
annotations, which will assign the values that it can to the POJO (which you need to specify at deserialization... it can't be generic), but will stick anything not parsed into a Map<String, Object>
.
Note, it can't be Map<String, String>
because JSON contains more than just Strings as its values.
For example, take the JSON
{
"uid": 1,
"username": "steve",
"email": "[email protected]"
}
You can generate a Jackson POJO that looks like so.
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"uid",
"username",
"email"
})
public class User {
@JsonProperty("uid")
private Integer uid;
@JsonProperty("username")
private String username;
@JsonProperty("email")
private String email;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
@JsonProperty("uid")
public Integer getUid() {
return uid;
}
@JsonProperty("uid")
public void setUid(Integer uid) {
this.uid = uid;
}
@JsonProperty("username")
public String getUsername() {
return username;
}
@JsonProperty("username")
public void setUsername(String username) {
this.username = username;
}
@JsonProperty("email")
public String getEmail() {
return email;
}
@JsonProperty("email")
public void setEmail(String email) {
this.email = email;
}
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
Upvotes: 2
Reputation: 724
You can use
ObjectMapper mapper = new ObjectMapper();
String jsonInString = "{'name' : 'rahul'}";
//JSON from String to Object
User user = mapper.readValue(jsonInString, User.class);
or
User user = mapper.convertValue(map, User.class);
if you are converting from json/map to custom object. You can also pass type information to the serialization/deserialization process so that jackson is aware of the internals. Please read more about that here.
Upvotes: 1
Reputation: 30839
We can't do it I am afraid. When an object
gets serialized into JSON String
, it loses it's class type. So, while deserializing a string into object, parser doesn't know which class to deserialize the object into. However, there are a couple of ways to do it:
Store type info in another map:
Create a new map
like this:
Map<String, Class> metaData = new HashMap<>();
It will store the type name along with Class. So, while derializing, we can lookup class type from this map and pass it to readValue
method.
Use @Type
annotation of ObjectMapper
: (only useful if all the objects extend same base class)
Jakson has a feature called Polymorphic Deserialization
which will help deserializing into object if all the classes inherit common base class. Have a look at the documentation here.
Upvotes: 0