Iv'e seen this nice mechanism:
http://www.mkyong.com/spring-mvc/spring-3-mvc-and-jsr303-valid-example/
Is it possible to make the #Valid annotation avaialble for all the Controllers with validation? It seems very redundant to do the following:
#RequestMapping(value = "/getPlayerAccounts", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(value = HttpStatus.OK)
#ResponseBody
public QueryResultsDTO<PlayerAccountResultDTO> getPlayerAccounts(#RequestBody **#Valid** FilteredQueryRequestDTO filteredQueryRequestDTO,
**BindingResult result**) {
**this.validateDTO(result);**
return this.playerService.getPlayerAccounts(filteredQueryRequestDTO);
}
Reduandant code:
#Valid
BindingResult result
this.validateDTO(result);
These seems like a recurring pattern, probably someone already solved it? maybe with aspects?
I dont care that all my methods and controllers will have the #Valid login, most of the DTOs they recieve will be valid anyway (since no validation annotations are applied to them)
Thanks
you cannot omit #Valid annotation, since this is the way to tell spring which dto to validate, that is just the way the spring validation works. But having a BindingResult result to each of your methods is not necessary. You may omit it completely. If you want to do something when validation fails, you can catch the MethodArgumentNotValidException that is thrown in that case from an exception handling method (e.g you can use a class with #ControllerAdvice annotations that will contain #ExceptionHandler methods applied to all controllers - exception handling is a whole different topic, you can read more details on related spring mvc exception handling documentation)
Related
I have and endpoint, where I validate received json document which contains collections of objects. I would like to only log these objects which don't pass a validation, when others i would like to store in db. Controller should return 200 OK in that situation. I was trying to use BindingResult object for this purpose. Unfortunately i always get a ConstraintViolationException. It seems that it validates it before it enter the method and throw exception. How can I force it to use BindingResult object ?
#RestController
#Validated
#RequestMapping(path = "/test")
class TestController {
#PostMapping(consumes = APPLICATION_JSON_VALUE)
public ResponseEntity<Void> addObjects(#RequestBody #Valid List<Document> objects, BindingResult bindingResult) {
if(bindingResult.hasErrors()){
}
return new ResponseEntity<Void>(HttpStatus.OK);
}
}
I'm using Spring Boot 1.5.9.RELEASE with Java 8
I've managed to solve it finally. Problem is with #Validated annotation on controller class. With this annotation spring do a validation on request and throw ConstraintViolationException. Without that, validation is triggered later and it results are stored in BindingResult object as expected
Could You please add the model classes with its annotations?
Remember that if You have any fields in Document class which are Your custom defined classes and You want it to be validated also then You have to decorate these fields with #Valid annotation too.
Background:
I am developing an web application with Spring MVC.
I want to make an aspect that is executed on POST requests and not executed on GET requests, because I want to inject the logic that prevent POST requests which are sent before completion of HTML rendering.
#RequestMapping(value = "/aaa", method = RequestMethod.POST)
public String methodForPost(AnDto dto, Model model) {
// the aspect should be executed on this method
}
#RequestMapping(value = "/bbb", method = RequestMethod.GET)
public String methodForGET(AnDto dto, Model model) {
// the aspect shouldn't be executed on this method
}
Question:
How can I specify method with an parameterized annotation and its value with #Pointcut ?
How can I specify method with an parameterized annotation and its value in <aop:pointcut> in Spring applicationContext.xml?
#Around(value="#annotation(RequestMapping)")
public Object display(ProceedingJoinPoint joinPoint, RequestMapping requestMapping ) throws Throwable {
// You have access to requestMapping. From which you can get whether its get or post and decide to proceed or not.
}
More info http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-ataspectj-advice-params-passing
You might have to extend this to intercept only for Requestmapping's in your package. Because this intercepts every RequestMappig you might have in your project including one used by the libraries which you might be using, which is a burden.
What's the difference between #GetMapping and #RequestMapping(method = RequestMethod.GET)?
I've seen in some Spring Reactive examples, that
#GetMapping was used instead of #RequestMapping
#GetMapping is a composed annotation that acts as a shortcut for #RequestMapping(method = RequestMethod.GET).
#GetMapping is the newer annotaion.
It supports consumes
Consume options are :
consumes = "text/plain"
consumes = {"text/plain", "application/*"}
For Further details see:
GetMapping Annotation
or read:
request mapping variants
RequestMapping supports consumes as well
GetMapping we can apply only on method level and RequestMapping annotation we can apply on class level and as well as on method level
As you can see here:
Specifically, #GetMapping is a composed annotation that acts as a
shortcut for #RequestMapping(method = RequestMethod.GET).
Difference between #GetMapping & #RequestMapping
#GetMapping supports the consumes attribute like
#RequestMapping.
#RequestMapping is a class level
#GetMapping is a method-level
With sprint Spring 4.3. and up things have changed. Now you can use #GetMapping on the method that will handle the http request. The class-level #RequestMapping specification is refined with the (method-level)#GetMapping annotation
Here is an example:
#Slf4j
#Controller
#RequestMapping("/orders")/* The #Request-Mapping annotation, when applied
at the class level, specifies the kind of requests
that this controller handles*/
public class OrderController {
#GetMapping("/current")/*#GetMapping paired with the classlevel
#RequestMapping, specifies that when an
HTTP GET request is received for /order,
orderForm() will be called to handle the request..*/
public String orderForm(Model model) {
model.addAttribute("order", new Order());
return "orderForm";
}
}
Prior to Spring 4.3, it was #RequestMapping(method=RequestMethod.GET)
Extra reading from a book authored by Craig Walls
Short answer:
There is no difference in semantic.
Specifically, #GetMapping is a composed annotation that acts as a
shortcut for #RequestMapping(method = RequestMethod.GET).
Further reading:
RequestMapping can be used at class level:
This annotation can be used both at the class and at the method level.
In most cases, at the method level applications will prefer to use one
of the HTTP method specific variants #GetMapping, #PostMapping,
#PutMapping, #DeleteMapping, or #PatchMapping.
while GetMapping only applies to method:
Annotation for mapping HTTP GET requests onto specific handler
methods.
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/GetMapping.html
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html
`#RequestMapping` since 2.5
=> Can handle all HTTP methods
=> Applicable to class and method
=> Can be used as a substitute of #Controller and #RestController, If we use it
along with #Component.
`#GetMapping` since 4.3
=> Can handle only GET method of HTTP
=> Applicable to method only
#GetMapping is a specific type of #RequestMapping(method = RequestMethod.GET). Both supports consumes
#RequestMapping supports consumes even with method=GET, while #GetMapping doesn't supports consumes.
#RequestMapping is Method & Type level annotation, while #GetMapping is a Method level annotation
Other than that #GetMapping is same as #RequestMapping(method=RequestMethod.GET)
#GetMapping is the shortcut for #RequestMapping(method = RequestMethod.GET)
#RequestMapping is a class level
#GetMapping is a method-level
4)The #RequestMapping annotation is used to map web requests to specific handler classes and functions. This annotations key advantage is that it may be used on both the controller class and methods.
5)It is always advised to be specific while declaring #RequestMapping on the controller methods as in most mapping handler classes, #Getmapping is not used.
Let say we have an API endpoint configured using Spring MVC and Spring Security. We would like to be able to handle pairs of #RequestMapping and #Secured annotations where the only #Secured annotation values differ from pair to pair. This way, we would be able to return a different response body depending on security rules for the same request.
This may allow our code to be more maintainable by avoiding to check for security rules directly into the method body.
With a not working example, here is what we would like to do :
#Controller
#RequestMapping("/api")
public class Controller {
#Secured ({"ROLE_A"})
#RequestMapping(value="{uid}", method=RequestMethod.GET)
#ResponseBody
public Response getSomething(#PathVariable("uid") String uid) {
// Returns something for users having ROLE_A
}
#Secured ({"ROLE_B"})
#RequestMapping(value="{uid}", method=RequestMethod.GET)
#ResponseBody
public Response getSomethingDifferent(#PathVariable("uid") String uid) {
// Returns something different for users having ROLE_B
}
}
How can we achieve this ?
And if this can be done: How the priority should be managed for a user who has both ROLE_A and ROLE_B ?
Assuming you are using Spring 3.1 (or up) together with the RequestMappingHandlerMapping (and RequestMappingHandlerAdapter) you can extend the request mapping mechanism. You can do this by creating your own implementation of the RequestCondition interface and extend the RequestMappingHandlerMapping to construct this based on the #Secured annotation on your method.
You would need to override the 'getCustomMethodCondition' method on the RequestMappingHandlerMapping and based on the Method and the existence of the #Secured annotation construct your custom implementation of the RequestCondition. All that information is then taken into account when matching incoming requests to methods.
Related answers (although not specific for #Secured annotations but the mechanism is the same) is also to be found here or here
I don't think you can do this in spring-mvc, since both routes have exactly the same #RequestMapping (#Secured) is not taken into account by the route engine of spring-mvc. The easiest solution would be to do this:
#Secured ({"ROLE_A", "ROLE_B"})
#RequestMapping(value="{uid}", method=RequestMethod.GET)
#ResponseBody
public Response getSomething(#PathVariable("uid") String uid, Principal p) {
// Principal p gets injected by spring
// and you need to cast it to check access roles.
if (/* p.hasRole("ROLE_A") */) {
return "responseForA";
} else if (/* p.hasRole("ROLE_B") */) {
return "responseForB";
} else {
// This is not really needed since #Secured guarantees that you don't get other role.
return 403;
}
}
However, I would change your design, since the response is different per role, why not have 2 separate request mappings with slightly different URLs? If at some point you have users with role A and B at the same time, you can't let the user choose what response to get (think, for example, of the public and private profiles of LinkedIn)
In the following example, the ScriptFile parameter is marked with an #Valid annotation.
What does #Valid annotation do?
#RequestMapping(value = "/scriptfile", method = RequestMethod.POST)
public String create(#Valid ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {
if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");
if (result.hasErrors()) {
modelMap.addAttribute("scriptFile", scriptFile);
modelMap.addAttribute("showcases", ShowCase.findAllShowCases());
return "scriptfile/create";
}
scriptFile.persist();
return "redirect:/scriptfile/" + scriptFile.getId();
}
It's for validation purposes.
Validation It is common to validate a
model after binding user input to it.
Spring 3 provides support for
declarative validation with JSR-303.
This support is enabled automatically
if a JSR-303 provider, such as
Hibernate Validator, is present on
your classpath. When enabled, you can
trigger validation simply by
annotating a Controller method
parameter with the #Valid annotation:
After binding incoming POST
parameters, the AppointmentForm will
be validated; in this case, to verify
the date field value is not null and
occurs in the future.
Look here for more info:
http://blog.springsource.com/2009/11/17/spring-3-type-conversion-and-validation/
Adding to above answers, take a look at following. AppointmentForm's date column is annotated with couple of annotations. By having #Valid annotation that triggers validations on the AppointmentForm (in this case #NotNull and #Future). These annotations could come from different JSR-303 providers (e.g, Hibernate, Spring..etc).
#RequestMapping(value = "/appointments", method = RequestMethod.POST)
public String add(#Valid AppointmentForm form, BindingResult result) {
....
}
static class AppointmentForm {
#NotNull #Future
private Date date;
}
#Valid in itself has nothing to do with Spring. It's part of Bean Validation specification(there are several of them, the latest one being JSR 380 as of second half of 2017), but #Valid is very old and derives all the way from JSR 303.
As we all know, Spring is very good at providing integration with all different JSRs and java libraries in general(think of JPA, JTA, Caching, etc.) and of course those guys took care of validation as well. One of the key components that facilitates this is MethodValidationPostProcessor.
Trying to answer your question - #Valid is very handy for so called validation cascading when you want to validate a complex graph and not just a top-level elements of an object. Every time you want to go deeper, you have to use #Valid. That's what JSR dictates. Spring will comply with that with some minor deviations(for example I tried putting #Validated instead of #Valid on RestController method and validation works, but the same will not apply for a regular "service" beans).
I wanted to add more details about how the #Valid works, especially in spring.
Everything you'd want to know about validation in spring is explained clearly and in detail in https://reflectoring.io/bean-validation-with-spring-boot/, but I'll copy the answer to how #Valid works incase the link goes down.
The #Valid annotation can be added to variables in a rest controller method to validate them. There are 3 types of variables that can be validated:
the request body,
variables within the path (e.g. id in /foos/{id}) and,
query parameters.
So now... how does spring "validate"? You can define constraints to the fields of a class by annotating them with certain annotations. Then, you pass an object of that class into a Validator which checks if the constraints are satisfied.
For example, suppose I had controller method like this:
#RestController
class ValidateRequestBodyController {
#PostMapping("/validateBody")
ResponseEntity<String> validateBody(#Valid #RequestBody Input input) {
return ResponseEntity.ok("valid");
}
}
So this is a POST request which takes in a request body, and we're mapping that request body to a class Input.
Here's the class Input:
class Input {
#Min(1)
#Max(10)
private int numberBetweenOneAndTen;
#Pattern(regexp = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$")
private String ipAddress;
// ...
}
The #Valid annotation will tell spring to go and validate the data passed into the controller by checking to see that the integer numberBetweenOneAndTen is between 1 and 10 inclusive because of those min and max annotations. It'll also check to make sure the ip address passed in matches the regular expression in the annotation.
side note: the regular expression isn't perfect.. you could pass in 3 digit numbers that are greater than 255 and it would still match the regular expression.
Here's an example of validating a query variable and path variable:
#RestController
#Validated
class ValidateParametersController {
#GetMapping("/validatePathVariable/{id}")
ResponseEntity<String> validatePathVariable(
#PathVariable("id") #Min(5) int id) {
return ResponseEntity.ok("valid");
}
#GetMapping("/validateRequestParameter")
ResponseEntity<String> validateRequestParameter(
#RequestParam("param") #Min(5) int param) {
return ResponseEntity.ok("valid");
}
}
In this case, since the query variable and path variable are just integers instead of just complex classes, we put the constraint annotation #Min(5) right on the parameter instead of using #Valid.
IIRC #Valid isn't a Spring annotation but a JSR-303 annotation (which is the Bean Validation standard). What it does is it basically checks if the data that you send to the method is valid or not (it will validate the scriptFile for you).
public String create(#Valid #NotNull ScriptFile scriptFile, BindingResult result, ModelMap modelMap) {
if (scriptFile == null) throw new IllegalArgumentException("A scriptFile is required");
I guess this #NotNull annotation is valid therefore if condition is not needed.
I think I know where your question is headed. And since this question is the one that pop ups in google's search main results, I can give a plain answer on what the #Valid annotation does.
I'll present 3 scenarios on how I've used #Valid
Model:
public class Employee{
private String name;
#NotNull(message="cannot be null")
#Size(min=1, message="cannot be blank")
private String lastName;
//Getters and Setters for both fields.
//...
}
JSP:
...
<form:form action="processForm" modelAttribute="employee">
<form:input type="text" path="name"/>
<br>
<form:input type="text" path="lastName"/>
<form:errors path="lastName"/>
<input type="submit" value="Submit"/>
</form:form>
...
Controller for scenario 1:
#RequestMapping("processForm")
public String processFormData(#Valid #ModelAttribute("employee") Employee employee){
return "employee-confirmation-page";
}
In this scenario, after submitting your form with an empty lastName field, you'll get an error page since you're applying validation rules but you're not handling it whatsoever.
Example of said error:
Exception page
Controller for scenario 2:
#RequestMapping("processForm")
public String processFormData(#Valid #ModelAttribute("employee") Employee employee,
BindingResult bindingResult){
return bindingResult.hasErrors() ? "employee-form" : "employee-confirmation-page";
}
In this scenario, you're passing all the results from that validation to the bindingResult, so it's up to you to decide what to do with the validation results of that form.
Controller for scenario 3:
#RequestMapping("processForm")
public String processFormData(#Valid #ModelAttribute("employee") Employee employee){
return "employee-confirmation-page";
}
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> invalidFormProcessor(MethodArgumentNotValidException ex){
//Your mapping of the errors...etc
}
In this scenario you're still not handling the errors like in the first scenario, but you pass that to another method that will take care of the exception that #Valid triggers when processing the form model. Check this see what to do with the mapping and all that.
To sum up: #Valid on its own with do nothing more that trigger the validation of validation JSR 303 annotated fields (#NotNull, #Email, #Size, etc...), you still need to specify a strategy of what to do with the results of said validation.
Hope I was able to clear something for people that might stumble with this.
Just adding to the above answer, In a web application
#valid is used where the bean to be validated is also annotated with validation annotations e.g. #NotNull, #Email(hibernate annotation) so when while getting input from user the values can be validated and binding result will have the validation results.
bindingResult.hasErrors() will tell if any validation failed.
Another handy aspect of #Valid not mentioned above is that (ie: using Postman to test an endpoint) #Valid will format the output of an incorrect REST call into formatted JSON instead of a blob of barely readable text. This is very useful if you are creating a commercially consumable API for your users.