The controller:
@RestController
@RequestMapping(value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
@Validated
public class ApiController {
@PostMapping(value = "/in",
consumes = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<InitResponse> inPost(
@ApiParam(required = true) @Valid @RequestBody InRequest inRequest) {
LOG.info("inPost request was received = {}", inRequest);
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
The exception handler:
@ControllerAdvice(assignableTypes = ApiController .class, annotations = RestController.class)
public class InExceptionHandler {
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<INErrors> handleConstraintViolation(ConstraintViolationException ex) {
LOG.info("handleConstraintViolation was trigerred");
INError INError = new INError(HttpStatus.BAD_REQUEST.toString(), ex.getLocalizedMessage());
return new ResponseEntity<>(new INErrors(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<INErrors> handleMethodArgumentConstraintViolation(MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
return new ResponseEntity<>(processFieldErrors(fieldErrors), HttpStatus.BAD_REQUEST);
}
}
If the InRequest has all fields within the javax validation constraint then I get the right code, but when a field doesn't match validation I just get 400 response code. There are other exception handlers defined but I've put breakpoints everywhere and nothing is triggered.
I also added the log4j property:
log4j.logger.org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod=DEBUG,stdout
but this didn't produce any additional output when debugging. I'm expecting to also to have the INErrors object sent back, but it doesn't even enter either one of the 2 handling methods.
This is happening because Spring's default exception handler handles all WebMvc's standard exceptions by itself and then delegates unhandled exceptions to user-defined @ExceptionHandler
methods.
In your case @Valid
constraint violation throws Spring's MethodArgumentNotValidException
which is handled by ResponseEntityExceptionHandler#handleMethodArgumentNotValid
. So, to change the default behaviour for this exception, you need to override this method in your @ControllerAdivce
.
@ControllerAdvice(assignableTypes = ApiController .class, annotations = RestController.class)
public class InExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
BindingResult result = ex.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
return ResponseEntity.badRequest().body(processFieldErrors(fieldErrors));
}
}
EDIT : I saw that you're using both assignableTypes
and annotations
for @ControllerAdvice
exception handler. This makes Spring register one exception handler for all @RestController
s. Try using either assignableTypes
or annotations
.
As an option, you can create your custom annotation for different exception handlers.
Following code prints "one" when invalid data supplied to /one
and "two" when data was sent to "/two".
@RestController
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface One {}
@RestController
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Two {}
@One
class ControllerOne {
@PostMapping("one")
String a(@RequestBody @Valid Data data) {
return data.value;
}
}
@Two
class ControllerTwo {
@PostMapping("two")
String a(@RequestBody @Valid Data data) {
return data.value;
}
}
@ControllerAdvice(annotations = One.class)
class HandlerOne extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
return ResponseEntity.badRequest().body("one");
}
}
@ControllerAdvice(annotations = Two.class)
class HandlerTwo extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
return ResponseEntity.badRequest().body("two");
}
}
The javax annotation style validation for the model worked for me only when I added the method inside the controller:
public class ApiController {
...
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<INErrors> handleConstraintViolation(MethodArgumentNotValidException exception) {
BindingResult result = exception.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
return new ResponseEntity<>(processFieldErrors(fieldErrors), HttpStatus.BAD_REQUEST);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.