Search code examples
javaspringspring-bootvalidationhibernate-validator

How to apply Hibernate validator when data submitted via POST and omit when PUT?


Have the same DTO object for POST and PUT methods:

class AcmeRequest {
    private String id;
    @NotEmpty
    private String productCode;
    private String description;
}

For POST request I always expect to see productCode field, that's why I specified @NotEmpty annotation but when PUT request received productCode should be optional.

Is it possible some how just to skip @NotEmpty when request is PUT?


Solution

  • Every Hibernate Validator annotation has a groups parameter. Through interfaces, you can control which validations are activated. See more at docs.

    In controller level, specify which groups must be activated with the @Validated annotation.

    Below, there is a small example from one of my demo projects. I once had the same question as you.

    Entity:

    @Entity
    @Table(name = "tasks")
    @Getter @Setter
    public class Task
    {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Null(message = "You can't provide a task ID manually. ID's are automatically assigned by our internal systems.", groups = {TaskInsertValidatorGroup.class})
        @NotNull(message = "You must provide an id" , groups = TaskUpdateValidatorGroup.class)
        private Integer id;
    
        @NotBlank(message = "Task description cannot be empty")
        @Length(max = 255 , message = "Task description length must not exceed 255 characters")
        private String description;
    
        @JsonProperty("is_completed")
        @Column(name = "is_completed")
        private Boolean isCompleted = false;
    
        @CreationTimestamp
        @JsonProperty("created_on")
        @JsonFormat(pattern="dd-MM-yyyy HH:mm:ss")
        @Column(name = "created_on", updatable = false)
        private Timestamp creationDate;
    
        @UpdateTimestamp
        @JsonProperty("last_modified")
        @JsonFormat(pattern="dd-MM-yyyy HH:mm:ss")
        @Column(name = "last_modidied")
        private Timestamp lastModificationDate;
    
        @Override
        public boolean equals(Object o)
        {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Task task = (Task) o;
            return id.equals(task.id);
        }
    
        @Override
        public int hashCode()
        {
            return Objects.hash(id);
        }
    }
    

    Interfaces:

    public interface TaskInsertValidatorGroup {}
    
    public interface TaskUpdateValidatorGroup{}
    

    Controller:

    RestController
    @RequestMapping("/api")
    public class TaskRestController
    {
    
        @Autowired
        private TaskService taskService;
    
        @GetMapping("/tasks/{id}")
        public ResponseEntity<?> getTask(@PathVariable Integer id)
        {
            return new ResponseEntity<>(taskService.findTask(id),HttpStatus.OK);
        }
    
        @GetMapping("/tasks")
        public ResponseEntity<?> getTasks()
        {
            return new ResponseEntity<>(taskService.findAllTasks(),HttpStatus.OK);
        }
    
        @PostMapping("/tasks")
        public ResponseEntity<?> addTask(@Validated(TaskInsertValidatorGroup.class) @RequestBody Task task)
        {
            taskService.saveTask(task);
            APISuccessResponse response = APISuccessResponse.builder()
                    .info("Task added")
                    .build();
    
            return new ResponseEntity<>(response,HttpStatus.OK);
        }
    
        @RequestMapping(value = "/tasks" , method = RequestMethod.PATCH)
        public ResponseEntity<?> updateTask(@Validated(TaskUpdateValidatorGroup.class) @RequestBody Task task)
        {
            taskService.updateTask(task);
            APISuccessResponse response = APISuccessResponse.builder()
                    .info("Task Updated")
                    .build();
    
            return new ResponseEntity<>(response,HttpStatus.OK);
        }
    
        @RequestMapping(value = "/tasks/{id}", method = RequestMethod.DELETE)
        public ResponseEntity<?> removeTask(@PathVariable Integer id)
        {
            taskService.removeTask(id);
            APISuccessResponse response = APISuccessResponse.builder()
                    .info("Task Deleted")
                    .build();
    
            return new ResponseEntity<>(response,HttpStatus.OK);
        }
    
    }