Michel Jung opened SPR-15911 and commented
Posted in https://stackoverflow.com/questions/45955727/autowired-field-is-null-in-cglib-enhanced-bean
I have this repository:
@Repository
public class MyRepository {
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public MyRepository(NamedParameterJdbcTemplate namedParameterJdbcTemplate) {
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
}
void doSomething() {
namedParameterJdbcTemplate.update(...);
}
}
With Spring 4.3.7 everything worked as expected. But it no longer does since Spring 4.3.8:
When the bean is being instantiated, constructor-injection works as expected.
However, when doSomething()
is called, the debugger shows that my repository is an instance of MyRepository$$EnhancerBySpringCGLIB
(wasn't with Spring 4.3.7) and namedParameterJdbcTemplate
is null
.
If I use @Service
instead of @Repository
the bean does not get CGLIB enhanced and everything works as expected.
I guess there's a reason why repositories are now GCLIB enhanced, but why doesn't auto wiring work anymore? I tried removing final
but it didn't change anything.
Affects: 4.3.8
Attachments: - spr-15911-v4.3.7.log (4.52 MB) - spr-15911-v4.3.8.log (4.50 MB)
Comment From: spring-projects-issues
Juergen Hoeller commented
It looks like your call ends up in the CGLIB proxy instance (where all fields are null by design) rather than the actual target object (which has dependency injection applied). This usually only happens for methods which can't be intercepted such as final methods, since for a regular CGLIB proxy method, any such method will be overridden in order to forward the call through the interceptor chain, eventually ending up in the target instance.
I'm not aware of a regression in that area in 4.3.8 yet. Further insight would be much appreciated!
Comment From: spring-projects-issues
Michel Jung commented
Comparing debug logs of 4.3.7 and 4.3.8 with the exact same code revealed something.
This line is printed in 4.3.8 but not in 4.3.7:
o.s.aop.framework.CglibAopProxy : Method [void com.faforever.server.chat.NickCoreRepository.updatePassword(java.lang.String,java.lang.String)] is package-visible across different ClassLoaders and cannot get proxied via CGLIB: Declare this method as public or protected if you need to support invocations through the proxy.
(I updated the issue to reflect the fact that my method wasn't public :-))
So I made the method public (against IntelliJ's recommendation to make it package-private ;-)) and the problem went away.
However, I've not been able to reproduce this in a minimalistic example, so there must be more to this story. The real-world project also uses caching, security, integration, actuator, jolokia If desired I can provide the source code (it's open source) and steps how to run it.
I also attached the log files, the actual class name to look for is NickCoreRepository
and its bean NickCoreRepository
.
I leave it up to you if you want to close this issue as invalid, or if you see a problem with this behavior. Keep in mind that this limitation didn't (seem to) exist pre-4.3.8 and it still does not with @Service
:-)
Comment From: spring-projects-issues
Juergen Hoeller commented
Package-visible methods can only be intercepted and propagated if the original class and the generated proxy class live in the same class loader. We only really revised the log entry in 4.3.8, so I wonder why the actual behavior ends up being different... For a start, you could set a breakpoint in CglibAopProxy.doValidateClass
and compare the class loader references that trigger the log entry there; I wonder why you have different class loaders there to begin with.
As for @Repository
vs @Service
, if you have a PersistenceExceptionTranslationPostProcessor
registered, @Repository
beans get proxied for exception translation purposes while @Service
and other beans remain unproxied. From that perspective, it's no surprise that you're only seeing the effect for @Repository
beans here.
Comment From: desiderati
The problem also happens if you use final methods!
Comment From: snicoll
Duplicate of #30938