I am trying to implement the registration controller for a Rest API. I have read about where to place @Transactional quite a bit. (Not at DAO level but at the services maybe orchestrated). In my use case I want not only services but also a hibernate validation to use the same transaction.
This is the code of the controller:
@Autowired
private UserService userService;
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
@Transactional
public DefaultResponse register(@Valid RegisterIO registerIO, BindingResult errors) {
DefaultResponse result = new DefaultResponse();
if (errors.hasErrors()) {
result.addErrors(errors);
} else {
userService.register(registerIO);
}
return result;
}
I have written an custom contraint annotation, which validates an attribute of the parameter registerIO. Both, this validator and userService.register(registerIO); access the database (check if the email address is already in use).
Therefore I want both methods use the same Hibernate session and transaction.
This approach results in the following exception:
org.hibernate.HibernateException: No Session found for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:97)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:941)
The problem is the @Transactional annotation. When I place this annotation at the methods witch call the database everything works find but two transactions are startet. I suspect that when i place it at the register Method the hibernate validation is performed before @Transactional starts the transaction for this method.
I developed the following functional workaround but I am not happy with it. This codes does not use the @Valid annotation but calls the validator by itself:
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
@Transactional
public DefaultResponse register( RegisterIO registerIO, BindingResult errors) {
DefaultResponse result = new DefaultResponse();
ValidatorFactory vf = Validation.buildDefaultValidatorFactory();
Validator validator = vf.getValidator();
Set<ConstraintViolation<RegisterIO>> valResult = validator.validate(registerIO);
I try to summarise my question: Using Spring MVC and Hibernate-Validation together with @Valid and @Transactional, how is it possible to encapsulate the whole request into one transaction?
Thank you :)