The same concept, applies when you are designing a Rest API. In other words, the same endpoint can admit different Json structures. With this technique, you avoid to create a different endpoints for the different Json formats. Then your Rest API is more confortable and more friendly for your clients.
Imagine you have to design and endpoint to create task. But you have to be able to create user task and group task. The first step is to design our request model for this endpoint.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface CreateTaskRequest { | |
String getTitle(); | |
String getDescription(); | |
TaskType getType(); | |
} |
As you can see down, with the annotation @JsonTypeInfo we are telling to Jackson (Jackson is the library used in this example to convert Json files to java objects) what property has to use to find the class to deserialize. When the property informed in the Json input file is "group", jackson tries to deserialize to GroupCreateTaskRequest object or to GroupCreateTaskRequest when is "user". On the other hand, with the annotation @JsonSubType we are mapping the type property value with the child class.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "taskType") | |
@JsonSubTypes({ @Type(value = UserCreateTaskRequest.class, name = "user"), @Type(value = GroupCreateTaskRequest.class, name = "group") }) | |
public abstract class AbstractCreateTaskRequest implements CreateTaskRequest { | |
private String title; | |
private String description; | |
private TaskType taskType; | |
public AbstractCreateTaskRequest(TaskType taskType) { | |
this.taskType = taskType; | |
} | |
@Override | |
public String getTitle() { | |
return this.title; | |
} | |
@Override | |
public String getDescription() { | |
return this.description; | |
} | |
@Override | |
public TaskType getType() { | |
return this.taskType; | |
} | |
public void setTitle(String title) { | |
this.title = title; | |
} | |
public void setDescription(String description) { | |
this.description = description; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class UserCreateTaskRequest extends AbstractCreateTaskRequest { | |
private String userName; | |
public UserCreateTaskRequest() { | |
super(TaskType.USER); | |
} | |
public String getUserName() { | |
return userName; | |
} | |
public void setUserName(String userName) { | |
this.userName = userName; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class GroupCreateTaskRequest extends AbstractCreateTaskRequest { | |
private String groupName; | |
public GroupCreateTaskRequest() { | |
super(TaskType.GROUP); | |
} | |
public String getGroupName() { | |
return groupName; | |
} | |
public void setGroupName(String groupName) { | |
this.groupName = groupName; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@RestController | |
@RequestMapping("/task") | |
public class TaskController { | |
@RequestMapping(method = RequestMethod.POST) | |
public void createTask(@RequestBody CreateTaskRequest createTaskRequest) { | |
if (TaskType.GROUP.equals(createTaskRequest.getType())) { | |
System.out.println("Creating group task"); | |
} | |
if (TaskType.USER.equals(createTaskRequest.getType())) { | |
System.out.print("Creating user task"); | |
} | |
} | |
} |
You can find the code of this example here.