Closed
Description
Bruno Navert opened SPR-3150 and commented
This problem was encountered with Snapshot build 98 of version 2.0.3.
The following bean definition of a custom-scoped bean (the class is a backport of JDK 1.5's java.util.concurrent.ArrayBlockingQueue to work on JDK 1.4):
<bean class="edu.emory.mathcs.backport.java.util.concurrent.ArrayBlockingQueue" scope="report">
<constructor-arg value="3" />
<aop:scoped-proxy />
</bean>
Failed with the error below. The class in question has no empty constructor, it needs an integer value, which is specified by <constructor-arg>.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'edu.emory.mathcs.backport.java.util.concurrent.ArrayBlockingQueue#55a338': Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Couldn't generate CGLIB subclass of class [class edu.emory.mathcs.backport.java.util.concurrent.ArrayBlockingQueue]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
Caused by: org.springframework.aop.framework.AopConfigException: Couldn't generate CGLIB subclass of class [class edu.emory.mathcs.backport.java.util.concurrent.ArrayBlockingQueue]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
Caused by: java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
at net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:718)
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:499)
at net.sf.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
at org.springframework.aop.framework.Cglib2AopProxy.getProxy(Cglib2AopProxy.java:193)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:107)
at org.springframework.aop.scope.ScopedProxyFactoryBean.setBeanFactory(ScopedProxyFactoryBean.java:109)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1074)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:430)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBeanDefinition(BeanDefinitionValueResolver.java:197)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:107)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1017)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:810)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:426)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:252)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:144)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:249)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:163)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:358)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:869)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:782)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:426)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:252)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:144)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:249)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:163)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:280)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:357)
I am using CGLib 2.1.3 (the one that ships with Hibernate 3.2.1)
This problem does not occur in version 2.0.0
Affects: 2.0.3
Issue Links:
- Add ability to create proxy around classes that has no default constructor [SPR-10594] #15223 Add ability to create proxy around classes that has no default constructor ("is superseded by")
15 votes, 19 watchers
Metadata
Metadata
Assignees
Labels
Type
Projects
Relationships
Development
No branches or pull requests
Activity
spring-projects-issues commentedon Feb 22, 2007
Juergen Hoeller commented
We do generally not support CGLIB proxies for classes that do not have default constructors, neither for standard AOP proxies nor for scoped proxies. (Well, to be exact, we do internally, but we're not exposing this functionality to applications.) Creating proxy instances with constructor arguments will usually lead to the proxy class internally initializing state, which is very undesirable. In general, only use CGLIB proxy classes that allow for 'stateless' construction.
In your case, I would strongly recommend to use
<aop:scoped-proxy proxy-target-class="false"/>
for such a bean, in particular since ArrayBlockingQueue implements a BlockingQueue interface anyway!
Juergen
spring-projects-issues commentedon Feb 22, 2007
Bruno Navert commented
Point taken. I was forced to use CGLIB proxies due to another bug in 2.0.0, but that bug has since been fixed in 2.0.3 so it's not an issue anymore.
Thanks for the info.
spring-projects-issues commentedon Aug 30, 2009
Kent Tong commented
Having a constructor that takes arguments does NOT imply that the object is stateful. For example, one singleton bean could refer to another singleton bean using constructor injection.
On the other hand, even if a default constructor is used, it is possible to be stateful (eg, establishing a DB connection in that constructor).
With the current behavior, it is impossible to create a CGLIB proxy for it if constructor injection is used. Therefore, I'd suggest change this behavior and give a warning in the documentation that the constructor will be executed twice.
spring-projects-issues commentedon Oct 14, 2011
Tomasz Nurkiewicz commented
This limitation is even more annoying when working with Scala:
Here I can inject dependencies via constructor and not only Scala compiler will automatically create private fields for each injected dependency, but also these fields will be final. However when CGLIB proxy is used I am forced to add dummy c-tor and keep it in sync with the primary one:
spring-projects-issues commentedon Apr 9, 2012
Oleg Alexeyev commented
It basically means that constructor injection doesn't work if AOP is enabled and an object doesn't implement interfaces. Or do I miss something? This is now exactly the problem I faced with. And now have to get back to setter injection or create an interface, which don't really need.
spring-projects-issues commentedon Nov 15, 2012
Ilya Kazakevich commented
Regular project has a lot of services. Most of them have final fields with pointers to other services. All of them are created using [constructor-arg] in xml.
Now I need to wrap them to implement logging and I do not want to use AspectJ weaving.
Why can't you support constructor parameters injection in Spring-AOP?
That works perfectly in CGLIB, so nothing prevents you from doing it. You only need to pass arguments to CGLIB.
BTW, you do have "Cglib2AopProxy#setConstructorArguments", why not to use it?
spring-projects-issues commentedon Jun 12, 2013
Przemysław Pokrywka commented
Kent, Tomasz, Oleg and Ilya had a valid point. Even parameterless constructors can have side-effects, so clear warning in the docs would be useful. And with the warning in place there's no longer need to annoy users of constructor-based injection.
Spring was meant to be agnostic about setter/constructor injection, wasn't it?
spring-projects-issues commentedon Jul 24, 2013
Andrzej Winnicki commented
Przemysław is right.
Constructor injection is becoming more and more popular. We need either clear warning in the docs: you can't use constructor-injection with CGLIB and AOP, or have this issue fixed.
spring-projects-issues commentedon Dec 13, 2013
Juergen Hoeller commented
Let's consider this fixed as of 4.0 RC1, since #15223 introduced an ObjenesisCglibAopProxy that bypasses constructor invocation for a CGLIB proxy instance altogether, avoiding any kind of side effect from constructor invocation (even in case of a default constructor). This is used by default with an embedded version of Objenesis in Spring Framework 4.0 now.
Juergen