This project demonstrates how to handle subtypes of request bodies in Spring Boot with validation.
It shows how to create a base request (CreateTaskRequest
) and extend it with specific subtypes (e.g., ConsultationSchedulingTaskRequest
), while applying different validation rules depending on the subtype.
- Polymorphic DTOs with inheritance (
CreateTaskRequest
→ConsultationSchedulingTaskRequest
) - Spring Validation (
@Valid
,@NotNull
, custom constraints) - Factory Pattern for mapping request DTOs to Task entities
- Example REST Controller with clean API endpoints
@Data
@Schema(description = "Request to create a new task")
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY,
property = "type",
visible = true
)
@JsonSubTypes({
@JsonSubTypes.Type(value = ConsultationSchedulingTaskRequest.class, name = "CONSULTATION_SCHEDULING"),
@JsonSubTypes.Type(value = OfflineVisitSchedulingTaskRequest.class, name = "OFFLINE_VISIT_SCHEDULING"),
@JsonSubTypes.Type(value = DocumentUploadTaskRequest.class, name = "DOCUMENT_UPLOAD"),
@JsonSubTypes.Type(value = CreateTaskRequest.class, name = "SIMPLE")
})
public class CreateTaskRequest {
@NotBlank(message = "Task name is required")
@Size(min = 1, max = 200, message = "Task name must be between 1 and 200 characters")
private String name;
@Size(max = 500, message = "Description must not exceed 500 characters")
private String description;
@NotNull(message = "Task type is required")
private TaskType type;
}
@Data
@EqualsAndHashCode(callSuper = true)
public class ConsultationSchedulingTaskRequest extends CreateTaskRequest{
@NotNull(message = "Consultation name cannot be null")
private String consultationName;
}
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(name = "document_upload", description = "Document Upload Task Request")
public class DocumentUploadTaskRequest extends CreateTaskRequest {
@NotBlank(message = "Report name cannot be blank")
private String reportName;
}
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(name = "consultation", description = "C")
public class EventSchedulingDetailsRequest extends CreateTaskRequest{
}
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(name = "offline_visit", description = "Offline Visit Scheduling Task Request")
public class OfflineVisitSchedulingTaskRequest extends CreateTaskRequest{
@NotBlank(message = "Visit task cannot be null")
private String vistTask;
private String visitSubTask;
private String visitCustomTask;
}
POST /tasks
{
"name": "Simple Task",
"description": "A basic task",
"type": "SIMPLE"
}
{
"name": "Offline Visit Task",
"description": "A basic task",
"type": "OFFLINE_VISIT_SCHEDULING",
"visitTask": "Visit Task",
"visitSubTask": "Visit Sub Task",
"visitCustomTask": "Visit Custom Task"
}
{
"name": "Event Scheduling Task",
"description": "Schedule an event",
"type": "CONSULTATION"
}
{
"name": "Document Upload Task",
"description": "Upload a document",
"type": "DOCUMENT_UPLOAD",
"reportName": "Report Name"
}
- Uses Spring Boot 4.0.0 and Java 25
- MongoDB is optional, but included in the example
- Demonstrates best practices for DTO design, validation, and clean controllers