How can I validate entities with spring data r2dbc?

1.2k views Asked by At

In Spring data JPA there are annotations that can be used to set up validations for entities in a declarative manner. They can be found in javax.validation.constraints.* or additionally in org.hibernate.validator.constraints.* (in the case when Hibernate is plugged in).

Example:

    @NotNull
    private String lastName;

However, if the case of Spring data r2dbc they do not work out of the box.

Is there any simple and smooth way to set up validations for entities in Spring data r2dbc? That should not be too difficult in my opinion because probably it does not require full ORM support, just a matter of callbacks for checking object fields before persisting it.

2

There are 2 answers

1
Hantsy On
  1. In the RestController, validate the incoming request body using the annotations from Bean validation and Hibernate validators.
  2. For RouterFunction or manal validation in your service, inject a Validator or ValidatorFactory to validate the request body before the data is (converted and) persisted into databases.
  3. JPA is tightly integrated with Bean Validation/Hibernate Validator, besides validation, it will affect the generated schemes by default.
  4. In a real world application, do not use the data layered entity classes in the web layer as request body class.
0
Cibele Watt On

It works very fine with Bean Validation and Hibernate Validation.

You can use all the same annotations you did in JPA, since you do it in your DTOs.

See the example:

@Data
public class UserDto {

    private String name;

    @NotNull(message = "Last name can not be empty")
    private String lastName;

    @Min(value = 10, message = "Required min age is 10")
    @Max(value = 50, message = "Required max age is 50")
    private int age;
}

Then your controller would be annotated:

@RestController
@RequestMapping("user")
public class RegistrationController {

    @Autowired
    private UserService userService;

    @PostMapping("register")
    public Mono<UserDto> register(@Valid @RequestBody Mono<UserDto> userDtoMono{
        return this.userService.registerUser(userDtoMono);
    }
}

The only thing now is that you have to personalize your message, so that it returns the one you have set in your DTO. To override it you should create an ExceptionHandler.

@ControllerAdvice
public class ValidationHandler {

    @ExceptionHandler(WebExchangeBindException.class)
    public ResponseEntity<List<String>> handleException(WebExchangeBindException e) {
        var errors = e.getBindingResult()
                .getAllErrors()
                .stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.toList());
        return ResponseEntity.badRequest().body(errors);
    }

}

I've been using it in my projects and got this example from: https://www.vinsguru.com/spring-webflux-validation/