Upgrading to Spring Boot 1.5.1, #Valid no longer triggering validation - spring

Upgraded an application to Spring Boot 1.5.1. I have controllers defined like:
public ResponseEntity<MappingJacksonValue> save(#Valid #RequestBody Brand brand, BindingResult bindingResult) {
...
}
When I execute my integration tests and expect validation to fail on Brand because of a #Size or #NotNull constraint, they never fail.

I upgraded to version 1.5.2.RELEASE and the #valid annotation returned to work.

Related

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.

#Nullable in Spring 5 is annotated with #Nonnull

I just updated my project to use Spring Boot 2.0.3 with Spring Framework 5.0.7.
And now I see that some parameters in methods of MessageSource are annotated with Spring's shiny new #Nullable annotation. But due to this annotation, IDEA 14 says that the appropriate parameters cannot be null (SURPRISE!).
As I understand that's due to the fact that #Nullable is annotated with #Nonnull:
#Nonnull(
when = When.MAYBE
)
What was the reason to mark annotation with a logically opposite one?
As explained by #StephanHerrmann, it's related to the original JSR.
So the idea is that null value is allowed in some cases - just to make code self-documented.
Similar approach is actually used in javax.annotation.Nullable:
#Documented
#TypeQualifierNickname
#Nonnull(when = When.UNKNOWN)
#Retention(RetentionPolicy.RUNTIME)
public #interface Nullable {
}
In latest IDEA versions this annotation is supported (or WILL be supported) out of the box.
To fix IDEA warning in older versions you just need to add the Spring's annotation manually.

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

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.

Spring Boot JPA CrudRepository

I'm working with Spring Boot + Spring Data JPA and facing this problem when trying to inject a class that extends CrudRepository:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'topicRepository': Could not resolve
matching constructor (hint: specify index/type/name arguments for
simple parameters to avoid type ambiguities)
Repository Class:
public interface TopicRepository extends CrudRepository<Topic, Integer> {}
Service Class:
#Service
public class TopicService {
#Autowired
private TopicRepository topicRepository;
}
Any suggestions?
I was having the same issue, and I fixed it by switching Spring Boot versions. Changing the Spring Data JPA versions did nothing (this is where I assumed the bug would be), so I think there is a bug in Spring Boot version 1.5.1. I switched back to version 1.4.3 and the error was gone. I didn't try subsequent/different versions, so you may just have to experiment with your dependencies and their versions.
For the record, you can have your service class annotated with #Repository, it shouldn't make any difference. I've been setting these apps up the same way using the service/dao pattern, and it has never been too picky with the annotations. Hopefully this may help others whose Spring Boot development flow suddenly throws an error!
Which versions of spring-data-commons and spring-data-jpa are you using. I just ran into this using spring-data-commons 1.13.x with spring-data-jpa 1.10.x. Upgrading spring-data-jpa to 1.11.x fixed the issue for me.
I too had the same issue after updating Spring Boot to 1.5.4.
I am also using spring-data-envers, which was at version 1.0.4. Upgrading to 1.4.1 solved the problem.
I hope it helps someone :)
Make sure:
1) TopicRepository is annotated with #Repository.
2) You have the scanning packages configured:
<jpa:repositories base-package="mypkg.repositories"></jpa:repositories>
Had the same issue on 1.5.2. Upgrading to 1.5.5 solved the problem.
You can use Applicationcontext to inject repository to this reference topicRepository..
You just declare applicationcontext in #rest controller class
Same like topicRepository by using annotation. Then you pass this to the service class which should take parms through constructor.
Ex-
public TopicService(Applicationcontext ctx) {this.topicRepository =context.getBean(TopicRepository.class);
}

#Rollback(true) not working in spring boot 1.3.X

I have updated my pom from spring-boot-starter-parent 1.2.5.RELEASE to 1.3.2.RELEASE.
The problem is that everything stay the same but all the test #Rollback(true) not working at all after migration.
#Transactional
#Rollback(true)
#Test
public void testRollBack() {
dao.saveToDb();
throw new RunTimeException();
}
Configaturation:
#Bean
#Primary
public PlatformTransactionManager txManager() {
return new DataSourceTransactionManager(dataSource());
}
It works perfectly in the same configuration and code and the only change is spring boot version. I cannot see that Transaction is being created in logs as suppose too
Anyone has a clue? Maybe a way to debug and understand what is the problem?
Thanks
TransactionTestExecutionListener has changed quite a lot between Spring Framework 4.1 (used by Spring Boot 1.2) and Spring Framework 4.2 (used by Spring Boot 1.3). It sounds like there's been a change in behaviour which I suspect probably wasn't intentional.
To fix your problem without renaming one of your beans, you need to tell the test framework which transaction manager to use. The easiest way to do that is via the #Transactional annotation:
#Transactional("txManager")
#Rollback(true)
#Test
public void testRollBack() {
dao.saveToDb();
throw new RunTimeException();
}
I have put spring on debug..
There is a problem/bug in the test framework or i don't understand the use correctly.
I checked the code of spring and saw this:
bf.getBean(DEFAULT_TRANSACTION_MANAGER_NAME, PlatformTransactionManager.class);
This happens when we have several transaction manager, instead of getting the bean marked by #Primary annotation spring try to get transaction manager that called "transactionManager".
The solution is just mark the bean in that name.. Tried to open issue to spring-test project but don't know where.. If anyone knows how please advise.
Thanks
EDIT: So the solution is eiether what i have wrote above or just name them transaction(#Transactional("myManager")) and use it in the test method signature

Resources