Firstly,if you have any ideas or solution, thank you to present here. I use @RequestBody on one of my controllers for a required parameter, I need some useful way of saying which parameter was missing if it's not there. When there are some parameters missing, it will throw the NullPointerException, SO I create a new exception to instance of this null exception (please see the httpemun and the httphandler) These are the primary codes which referring to this question.
my controller:
public ResponseEntity<?> createOrder(@RequestBody Cart cart) throws Exception {
// ......
}
my entity cart:
public class Cart{
private String channel
private String cartId;
private String status;
private String currency;
getters...
setters...
}
my Http emun class:
public enum HttpStatusEnum {
CRE_CART_INCOMPLETE_BODY(400,"E001","Incomplete request body","");
private HttpStatusEnum(int statusCode, String code,
String message, String detail) {
this.statusCode = statusCode;
this.code = code;
this.message = message;
this.detail = detail;
}
private final int statusCode;
private final String code;
private final String message;
private String detail;
public int getStatusCode() {
return statusCode;
}
public String getCode() {
return code;
}
public String getMessage() {
return message;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getDetail() {
if(detail.isEmpty()) {
return message;
}else {
return detail;
}
}
}
I also have one exception handle
@ControllerAdvice
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResponseEntity<Object> defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
if(e instanceof NullPointerException)
{if(req.getRequestURL().toString().contains(HttpSourceEnum.CART.toString()) && req.getMethod().equals(RequestMethod.POST.toString())){
errorBodyVo.setMessage(HttpStatusEnum.CRE_CART_INCOMPLETE_BODY.getMessage());
errorBodyVo.setDetails(HttpStatusEnum.CRE_CART_INCOMPLETE_BODY.getDetail());
errorBodyVo.setCode(HttpStatusEnum.CRE_CART_INCOMPLETE_BODY.getCode());
}else {
errorBodyVo.setMessage(HttpStatusEnum.COMMON_MISSING_FIELD.getMessage());
errorBodyVo.setDetails(HttpStatusEnum.COMMON_MISSING_FIELD.getDetail());
errorBodyVo.setCode(HttpStatusEnum.COMMON_MISSING_FIELD.getCode());
}
httpStatus = HttpStatus.BAD_REQUEST;
}
}
right now, my API request is:
{
"channel": "XX",
"cartId": "109",
"status": "1",
}
I receive the API response just like below:
{
"error": {
"code": "E001",
"message": "Incomplete request body",
"details": ""
}
}
but it doesn't match my expect. if the channel is missing in my request like below:
{
"cartId": "109",
"status": "1",
}
I expect to show "Required request body content is missing: Channel" in the details:
{
"error": {
"code": "E001",
"message": "Incomplete request body",
"details": "Required request body content is missing: Channel"
}
}
How could I do that? Thanks guys!
A better approach, if you can do it, would probably be to use JSR 303 Validation, which is probably included with your existing Spring dependencies, assuming you're using recent versions.
There's a good, if quite simple, tutorial here: https://www.mkyong.com/spring-mvc/spring-rest-api-validation/ and many more online with more details.
The official Spring docs on the subject are here: https://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#validation-beanvalidation
You should only need to make changes to a few classes, and can potentially remove a lot of your exception handling, depending on how much control you want, or how much you're willing to go with Spring's defaults. The basic changes you'll need to make though are:
To tell Spring what validation is required, you add one or more annotations to the
Cart
class, for example, if you want to ensure that the channel is specified, you could do something like:Then, to instruct Spring to validate the
Cart
object before passing it to your controller, you need to add an@Valid
annotation to your controller method signature:Lastly, modify the
createOrder
signature again to accept anErrors
object:In the
createOrder
method you can then query theErrors
object and respond accordingly. This could mean sending a specific response from the controller or throwing an exception to be handled by your existing exception handling mechanism.