Reputation: 55
I have a custom validation annotation that verifies a fiscal code.
FiscalCode.java
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Constraint(validatedBy = FiscalCodeValidator.class)
public @interface FiscalCode {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
This annotation performs multiple checks, and the isValid
method returns different error messages depending on how far it has validated the string.
FiscalCodeValidator.java
public class FiscalCodeValidator implements ConstraintValidator<FiscalCode, String> {
@Override
public boolean isValid(String fc, ConstraintValidatorContext context) {
String validationMessage = checkFC(fc);
if (!validationMessage.isEmpty()) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(validationMessage).addConstraintViolation();
return false;
}
return true;
}
private String checkFC(String fc) {
if (...) return "err1";
... some logic ...
if (...) return "err2";
... some logic ...
if (...) return "err3";
... some logic ...
if (...) return "errN";
... some logic ...
return "";
}
}
I would like to use it both as a parameter in GET requests at the Controller level and as a field in a request object (POST, PUT).
TestController.java
@RestController
public class TestController {
@GetMapping("test-get")
public ResponseEntity<String> testGet(@FiscalCode String fc) {
return ResponseEntity.ok(fc);
}
@PostMapping("test-post")
public ResponseEntity<String> testPost(@Valid @RequestBody Example example) {
return ResponseEntity.ok(example.getFiscalCode());
}
@PutMapping("test-put")
public ResponseEntity<String> testPut(@Valid @RequestBody Example example) {
return ResponseEntity.ok(example.getFiscalCode());
}
@DeleteMapping("test-delete")
public ResponseEntity<String> testDelete(@FiscalCode String fc) {
return ResponseEntity.ok(fc);
}
}
Example.java
@Getter
@Setter
public class Example {
@FiscalCode
private String fiscalCode;
}
I would like to expose a dynamic validation error to the client (based on what the validation method returns) always in the ProblemDetail shape, with the detail property containing the error text.
GlobalExceptionHandler.java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(HandlerMethodValidationException.class)
ResponseEntity<ProblemDetail> handleHandlerMethodValidationException(HandlerMethodValidationException ex) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "");
... some logic ...
return new ResponseEntity<>(problemDetail, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
ResponseEntity<ProblemDetail> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, "");
... some logic ...
return new ResponseEntity<>(problemDetail, HttpStatus.BAD_REQUEST);
}
}
Is it absolutely necessary to handle each specific exception, extract the information, and insert it into a ProblemDetail? Are there more decoupled methods to achieve this? Is it possible to integrate with constraint management and provide a custom provider? Is there a best practice or recommended approach?
Thanks in advance
Upvotes: 0
Views: 108