I'm using javax and Hibernate implementation for validation of my request payload.
version - org.hibernate:hibernate-validator:5.4.1.final
Sample Pojo:
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
public class Customer implements Serializable{
@NotNull(message="name is null")
@Size(min = 1)
public String name;
@NotNull(message="country is null")
@Size(min = 1)
public String country;
}
Sample controller:
@RequestMapping(value = {"/customer"}, method = RequestMethod.POST)
@ResponseBody
public Customer doAdd(@RequestBody @Valid Customer inData){
//some logic
return outData
}
Sample input json:
{
"country":"canada"
}
Console Exception:
org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument at index 0 in method: ........ model.request.Customer,java.lang.String,java.lang.String,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse), with 1 error(s): [Field error in object 'Customer' on field 'name': rejected value [null]; codes [NotNull.Customer.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [Customer.name,name]; arguments []; default message [name]]; default message [name is null]]
Here when customer.name is null, i'm getting response code as 422(Unprocessable entity). But i want to return 400(BAD Request). How can i override the response code here? Any document reference would be appreciated.
note - i don't want to do these validation at controller's side, where can i can check and send the response code accordingly. Like this one - How to return 400 http status code with @NotNull?
Update - issue was resolved -------
The issue is resolved for me. Thanks all for your response.
Let me explain what was causing this,
HttpRequest ----> @Valid on RequestBody ----> Javax validation on Request object-----> If any of the validation fails, **MethodArgumentNotValidException** exception is thrown.
It is the responsibility of the developer to catch this exception and throw corresponding http response code. In my case, the exception handler was already there and it was catching this MethodArgumentNotValidException and returning HttpStatus.UNPROCESSABLE_ENTITY. Thats the reason i was seeing 422 error code.
Now i have changed the exception handler as below,
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResource>
handleMethodArgumentNotValidException(MethodArgumentNotValidException exception, HttpServletRequest request) {
List<FieldErrorResource> fieldErrorResources = new ArrayList<>();
BindingResult bindingResult = exception.getBindingResult();
for (FieldError constraintViolation : bindingResult.getFieldErrors()) {
fieldErrorResources.add(FieldErrorResource.builder()
.field(constraintViolation.getField())
.resource(request.getContextPath())
.message(constraintViolation.getDefaultMessage()).build());
}
return responseEntityFor(HttpStatus.BAD_REQUEST,
"The content you've sent contains " + bindingResult.getErrorCount() + " validation errors.", fieldErrorResources);
}
You can use RestControllerAdvice for the same
@RestControllerAdvice
public class ExceptionRestControllerAdvice {
@ExceptionHandler({ConstraintViolationException.class})
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public ExceptionResponseMessage handleInvalidParameterException(RuntimeException ex) {
return sendResponse(HttpStatus.BAD_REQUEST, ex);
}
private ExceptionResponseMessage sendResponse(HttpStatus status, RuntimeException ex) {
return new ExceptionResponseMessage(Instant.now(), status.value(), status.getReasonPhrase(),
ex.getClass().toString(), ex.getMessage());
}
}
public class ExceptionResponseMessage {
private Instant time;
private int status;
private String error;
private String exception;
private String message;
// setter and getter and constructor