Deserialize JSON Into Polymorphic Types With Jackson
Problem
Assume you have two types of JSON documents, and the following actions depend on the value of specific attribute.
{
"action": "login",
"userId": "xxx"
}
{
"action": "sendMessage",
"message": "user Message"
}
The simplest way is to deserialized them into Map, but that would be very not object-oriented. We need to find a way to automatically deserialize them into right type of objects.
Solution
Deserialize JSON with Jackson into Polymorphic Types - A Complete Example demonstrate many useful examples. What we need is Example 5, but Mixin is not necessary in our case, not sure if it’s because we use Jackson 2.6.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonSubTypes.Type;
public class JacksonTypeTest {
public static void main(String[] args) throws Exception {
String sendMessageJson = "{ \"action\": \"sendMessage\", \"message\": \"testMessage\"}";
String loginJson = "{ \"action\": \"login\", \"userId\": \"123456\"}";
ObjectMapper mapper = new ObjectMapper();
Action sendMessageAction = mapper.readValue(sendMessageJson, Action.class);
Action loginAction = mapper.readValue(loginJson, Action.class);
System.out.println(sendMessageAction.getClass().getName());
System.out.println(loginAction.getClass().getName());
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "action")
@JsonSubTypes({
@Type(value = SendMessageAction.class, name = "sendMessage"),
@Type(value = LoginAction.class, name = "login")
})
abstract class Action {
protected String action;
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
class SendMessageAction extends Action {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
class LoginAction extends Action {
private String userId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
}
From the output of the example, we see that the JSON documents are deserialized into right type of objects. Now we can operate on objects.
Another Problem
Trying to serialize the deserialized objects, action
attribute got duplicated in the generated JSON. Solving it in the next post.