I want to validate the JSON content of a POST request in my controller.
I use @NullValue annotations and a custom Validator for a conditional validation. The input is invalid if the attribute type is A and the attribute name is empty.
But I can't get the validator to work.
I have this controller:
@RestController
@RequestMapping("/orders")
@Validated
public class OrderController {
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void createOrder(@Valid @RequestBody Order order) {
// do something
}
}
and this Validator for the Order class:
@Component
public class OrderValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Order.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
final var order = (Order) target;
if (order.getType() == Type.A && Strings.isEmpty(order.getName())) {
errors.rejectValue("name", "name.required", "Name required for type A");
}
}
}
and Order class
@Getter
@Setter
public class OrderDto {
private String name;
@NotNull
private Type type;
}
If I send a POST request where type is null, I get HTTP status 400 (Bad request) as expected.
But when I send a POST request with type=A and name=null the method returns HTTP 201 (Created). The OrderValidator is not executed.
Breakpoints prove, that the supports and validate methods are not called. But I can inject a OrderValidator bean, which means the component was found by Spring Boot.
The only work-around I found was to use this as controller, but this does not look feel right to me:
@RestController
@RequestMapping("/orders")
@Validated
public class OrderController {
@Autowired
private final OrderValidator orderValidator;
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.addValidators(orderValidator);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void createOrder(@Valid @RequestBody Order order, BindingResult result) {
// evaluate bindingResult manually
// do something
}
}
What am I doing wrong?