I'm trying to use @Transactional
annotation in a method on my service to lazily load a field. However using @Transactional
on my Implementation class makes all autowired fields null
.
Here is my implementation :
@Service
public class UserServiceImpl implements UserService {
/**
* DefaultMapper.
*/
@Autowired
private DefaultMapper defaultMapper;
/**
* Resource service injection.
*/
@Autowired
private ResourceService resourceService;
/**
* UserRepository.
*/
@Autowired
private UserRepository userRepository;
/**
* Jwt Factory.
*/
@Autowired
private JwtService jwtService;
@Override
@Transactional
public final UserDto findByLogin(final String login) throws ResourceNotFoundException {
// user repository is null here when using @Transactional
User user = this.userRepository.findByLogin(login)
.orElseThrow(() -> new ResourceNotFoundException(
resourceService.getMessage(MessageBundle.EXCEPTION, "resource.notfound.user.login")
));
UserDto userDto = defaultMapper.asUserDtoWithRoles(user);
return userDto;
}
Thank you in advance.
Transaction, amongst others, are applied using AOP, the default AOP mechanism in Spring is to use proxies. When using Spring Boot the proxy mode is set the class based proxies.
You can fix this in 1 of 2 ways.
final
from your methodspring.aop.proxy-target-class=false
to your application.properties
Now when you aded @Transactional
this will lead to a proxy of your UserServiceImpl
to be created, a class-based proxy to be exact. What happens is that a subclass is created for your UserServiceImpl
and all methods are overriden to apply the TransactionInterceptor
. However as your method is marked final
the dynamically created class cannot override this method. As a result the method looks at field instances in the dynamically created proxy class which always will be null
.
When removing final
the method can be overridden, the behavior applied and it will look at the proper field instances (of the actual UserServiceImpl
instead of the proxy).
When disabling class based proxies, you will get a JDK Dynamic Proxy which is basically a thin wrapper which implements all the interfaces your service implements. It applies the added behavior (transactions) and calls the actual service. There is no extension of the actual class needed and as such you can proxy final methods (as long as it is part of your interface).