#Valid vs #Validated in Spring Boot Rest API #RequestBody [duplicate] - spring

This question already has answers here:
Difference between #Valid and #Validated in Spring
(6 answers)
Closed 5 years ago.
I am coming from a .NET background in developing REST APIs. Now working on java REST project using spring boot.
First my validation at the controller #RequestBody just stop working. While trying to fix it, I saw different ways to implement. So what would be the correct way to annotate the #RequestBody?
#Validated #RequestBody
or
#Valid #RequestBody

There are generally no huge difference between them two, #Valid is from JSR-303 standand, #Validated is spring standard. according to spring document:
Spring provides a Validator interface that can be used for validation in all layers of an application. In Spring MVC you can configure it for use as a global Validator instance, to be used whenever an #Valid or #Validated controller method argument is encountered, and/or as a local Validator within a controller through an #InitBinder method. Global and local validator instances can be combined to provide composite validation.
Reference: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-config-validation
However there are differences, one of them is for example, if you need use group in your validation annotation, you need to use #Validated, it is not supported with #Valid.

#Valid is in the JSR-Specification and #Validated is from spring framework.
When your program should be compatible to EJB/JSR Standard use #Valid otherwise you can use both.

Related

Spring Boot Best approach for validation in facade

I use Spring Boot with Kotlin and my project is splitted on modules where I have application layer with REST controllers and facades, domain layer with services and business logic and infrastructures layer for communication with external services or DBs. I think (but I can be wrong) that the best place for basic validation like notNull, notEmpty, max and min, size etc. is facade because both REST controllers and another modules communicate with it, but the problem is that javax validation annotation like #Valid are working only on REST Controller layer (in classes with annotation #RestController) and when I try to create some tests for this facade then fields with wrong values return NullPointerException instead of MethodArgumentNotValidException. I tried to create WebMvcTest but also returns wrong exception. Is it some solution for it? I saw that I could call some validator inside the method but it looks like much more complex approach than annotation on method's argument.
You can inject the javax.validation.Validator into any Spring component. For example, into a facade component, and perform validation in the facade layer:
#Autowired
Validator validator;
Set<ConstraintViolation<UserRequestDTO>> violations = validator.validate(userRequest);
This way you can remove the #Valid annotation from controllers at all. And this approach puts validation results under the your control.

Why Spring Boot throws different exceptions for Controller method argument validations?

While validating a primitive type or their equivalent (Integer, Boolean) using constraints validation annotations (#Min, #NotNull, ...) Spring Boot throws ConstraintViolationException. But when validating a parameter using the #Valid annotation then MethodArgumentNotValidException is thrown.
I have a class annotated with #ControllerAdvice to handle the exceptions from the Controllers.
The problem is that depending on the spring-boot-starter-parent version, the results are pretty much different.
While using the version 2.0.5.RELEASE I just needed to include a handler for the ConstraintViolationException class.
But there are some others versions that MethodArgumentNotValidException is thrown too.
It already was mentioned on a GitHub issue, but no useful answer...
I'll use the lukasniemeier-zalando's example here. For more detail click on the link above.
#Validated // needed to actually trigger validation
#RestController
class MyController {
#RequestMapping
Response serve(
#RequestParam #Min(2) Integer parameter, // throws ConstraintViolationException
#RequestBody #Valid BodyModel body // throws MethodArgumentNotValidException
) {
return new Response();
}
}
I would expect that both validations throws the same exception, no matter which of them, just to be consistent.
Apearently there's no reason to this to be like it is, at least it was what I understood from this other GitHub issue.
Then I just want a answer why Spring Boot throws 2 types of exception to represent the same problem (argument validation).
Note: as mentioned before, using the version 2.0.5.RELEASE of the spring-boot-starter-parent it doesn't happens.
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
But as reported by the last GitHub issue that I linked, the version 2.0.0.M4 has this behavior, and I also experienced it with the 2.2.0.M3 version.
They are handled by different validation mechanisms. The #Validated on the class is handled by the MethodValidationInterceptor which is a generic purpose validation mechanism for classes. Due to this it throws a ConstraintViolationException. The #Validated is used here simply because the #Valid annotation isn't allowed on types. Hence the only way to enable/trigger the MethodValidationInterceptor is by using the #Validation annotation.
The #Valid on the method argument in a controller is handled by the ModelAttributeMethodProcessor internally and leads to a web specific binding exception, the MethodArgumentNotValidException. The ModelAttributeMethodProcessor is called (indirectly) from the RequestMappingHandlerAdapter when preparing the method invocation. Instead of #Valid you could also use the #Validated annotation on the method argument. Spring MVC supports both (it actually supported #Validated before #Valid even existed!).
The solution/workaround is to create your own exception-handler which handles the ConstraintViolationException the same as a MethodArgumentNotValidException. Which is also suggested in the GitHub issue you link to.

When to use #RestController vs #RepositoryRestResource

I have been looking at various examples of how to use Spring with REST. Our end target is a Spring HATEOAS/HAL setup
I have seen two distinct methods for rendering REST within Spring
Via #RestController within a Controller
Via #RepositoryRestResource within a Repository
The thing I am struggling to find is why would you use one over the other. When trying to implement HAL which is best?
Our database backend is Neo4j.
Ok, so the short story is that you want to use the #RepositoryRestResource since this creates a HATEOAS service with Spring JPA.
As you can see here adding this annotation and linking it to your Pojo you have a fully functional HATEOAS service without having to implement the repository method or the REST service methods
If you add the #RestController then you have to implement each method that you want to expose on your own and also it does not export this to a HATEOAS format.
There is a third (and fourth) option that you have not outlined, which is to use either #BasePathAwareController or #RepositoryRestController, depending on whether you are performing entity-specific actions or not.
#RepositoryRestResource is used to set options on the public Repository interface - it will automatically create endpoints as appropriate based on the type of Repository that is being extended (i.e. CrudRepository/PagingAndSortingRepository/etc).
#BasePathAwareController and #RepositoryRestController are used when you want to manually create endpoints, but want to use the Spring Data REST configurations that you have set up.
If you use #RestController, you will create a parallel set of endpoints with different configuration options - i.e. a different message converter, different error handlers, etc - but they will happily coexist (and probably cause confusion).
Specific documentation can be found here.
Well, above answers are correct in their context still I am giving you practical example.
In many scenarios as a part of API we need to provide endpoints for searching an entity based on certain criteria. Now using JPA you don't have to even write queries, just make an interface and methods with specific nomenclature of Spring-JPA. To expose such APIs you will make Service layer which would simply call these repository methods and finally Controllers which will expose endpoints by calling Service layer.
What Spring did here, allow you to expose these endpoints from such interfaces (repositories) which are generally GET calls to search entity and in background generates necessary files to create final endpoints. So if you are using #RepositoryRestResource then there is no need to make Service/Controller layer.
On the other hand #RestController is a controller that specifically deals with json data and rest work as a controller. In short #Controller + #ResponseBody = #RestController.
Hope this helps.
See my working example and blog for the same:
http://sv-technical.blogspot.com/2015/11/spring-boot-and-repositoryrestresource.html
https://github.com/svermaji/Spring-boot-with-hibernate-no-controller
#RepositoryRestController override default generated Spring Data REST controllers from exposed repository.
To take advantage of Spring Data REST’s settings, message converters, exception handling, and more, use the #RepositoryRestController annotation instead of a standard Spring MVC #Controller or #RestController
E.g this controllers use spring.data.rest.basePath Spring Boot setting as base path for routing.
See Overriding Spring Data REST Response Handlers.
Be aware of adding #ResponseBody as it is missed in #RepositoryRestController
If you not exposed repository (marked as #RepositoryRestResource(exported = false)), use #BasePathAwareController annotation instead
Also be aware of bags
ControllerLinkBuilder does not take Spring Data REST's base path into account and #RequestMapping shouldn't be used on class/type level
and
Base path doesn't show up in HAL
Workaround to fix link: https://stackoverflow.com/a/51736503/548473
UPDATE: at last I prefer not to use #RepositoryRestController due to lot of workarounds.

#Valid working without spring-mvc?

I'd like to use #Valid annotation to validate my beans in controller method. Unfortunatelly it does not work. I know that in order to make it work I'd have to include spring-mvc into my project and put there mvc:annotation-driven or #EnableMvc... .
But I do not use spring-mvc! I use Wicket framework. How to make #Valid working without incorporating spring-mvc?
Thanks!
#Valid is not specific to spring it is an implementation of JSR 303 bean validation. You can use any other reference implementation or write your own. e.g Apache and Hibernate Validator has reference implementation available. Take a look at this answer Is there an implementation of JSR-303 (bean validation) available?

spring mvc annotation #RequestAttribute similar to #RequestParam

I would like add an annotation similar to #RequestParam, though have it pull the values from the request attribute rather than the request param...
Is there an example or explanation how to create my own annotation for this and the handler / binder needed as well?
Thanks
The blog entry with the title "Extending Spring MVC's annotation controller" answers your question. Google it to find it since Stackoverflow won't let me create the direct link.
Basically you create an #RequestAttribute annotation and then a custom WebArgumentResolver.
The blog entry has examples for #RequestAttribute and #SessionAttribute.
The svn directory with the examples is here.
http://impala-extensions.googlecode.com/svn/trunk/impala-extension-mvc/src/org/impalaframework/extension/mvc/
Since Spring 4.3 #RequestAttribute annotation is a part of Spring MVC, so there is no need to create your own #RequestAttribute annotation

Resources