Reputation: 1179
I want to validate the request param.I have gone through number of blogs and answer and did the same. Added @Validated on the controller class.
Method in controller:
public ResponseEntity<Employee> getHistory(
@Valid @Pattern(regexp = "^[A-Z]{2}[0-9]{6}[A-Z]{0,1}$", message = "Invalid
emp") @NotNull(message = "input cannot be null") @RequestParam(name = "emp")
String emp) { method body..........}
Controller Advice
@ExceptionHandler(value = {ConstraintViolationException.class})
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleValidationFailure(ConstraintViolationException ex) {
StringBuilder messages = new StringBuilder();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
messages.append(violation.getMessage() + "\n");
}
return messages.toString();
}
Config:
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
After doing all this now I am getting a 404 error. "status":404,"error":"Not Found","message":"No message available"
Upvotes: 2
Views: 7177
Reputation: 42184
You are missing @ResponseBody annotation over a method in controller advice. It causes an error, because Spring is trying to locate template with name returned as a String
from this method, so during REST call you get something like this:
{
"error": "Not Found",
"exception": "javax.validation.ConstraintViolationException",
"message": "No message available",
"path": "/history",
"status": 404,
"timestamp": 1502293311543
}
Adding @ResponseBody
annotation to handleValidationFailure(ConstraintViolationException ex)
method means that when you return a String it's not a template name but the response object itself.
Alternatively you can use ResponseEntity<String>
as a return type in your advice method, e.g.
@ExceptionHandler(value = {ConstraintViolationException.class})
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public ResponseEntity<String> handleValidationFailure(ConstraintViolationException ex) {
StringBuilder messages = new StringBuilder();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
messages.append(violation.getMessage());
}
return ResponseEntity.badRequest().body(messages.toString());
}
so you don't have to annotate method with @ResponseBody
and Spring will now that your response is not a view name but response body itself. I hope it helps.
I assume you are calling incorrect endpoint. I have created a small Spring Boot application that replicates your problem using provided information:
Feel free to clone it and run it. After running you can try calling /history
endpoint with:
curl "localhost:8080/history?emp=AZ000001A"
and it will display in return:
{"id":"AZ000001A","name":"Joe Doe"}%
If you call this endpoint with emp
that violates validation rules:
curl "localhost:8080/history?emp=sd"
you will get following response:
{"message":"Your request contains errors","errors":[{"getHistory.arg0":"Invalid emp"}]}
My assumption is that in your case you are calling your endpoint incorrectly. There is popular misunderstanding in using @RestController
annotation. I saw people using it like @RestController("/someRootPath")
and then they expected to have endpoints like
localhost:8080/someRootPath/...
which is not correct. Value passed to @RestController
annotation is nothing else than:
The value may indicate a suggestion for a logical component name, to be turned into a Spring bean in case of an autodetected component.
You can always check console log to see what are the final mappings for your controllers, e.g.
2017-08-09 20:40:45.663 INFO 1340 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6385cb26: startup date [Wed Aug 09 20:40:44 CEST 2017]; root of context hierarchy
2017-08-09 20:40:45.696 INFO 1340 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/history],methods=[GET]}" onto public org.springframework.http.ResponseEntity<com.github.wololock.restvalidationdemo.Employee> com.github.wololock.restvalidationdemo.EmployeeController.getHistory(java.lang.String)
2017-08-09 20:40:45.698 INFO 1340 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-08-09 20:40:45.698 INFO 1340 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-08-09 20:40:45.708 INFO 1340 --- [ main] o.s.w.s.h.BeanNameUrlHandlerMapping : Mapped URL path [/employee] onto handler '/employee'
2017-08-09 20:40:45.714 INFO 1340 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-08-09 20:40:45.714 INFO 1340 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
I hope it helps.
Upvotes: 3