[
https://issues.apache.org/jira/browse/WICKET-6911?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Sven Meier reassigned WICKET-6911:
----------------------------------
Assignee: Sven Meier
> wicket-spring throws an error when a spring bean uses ctor injection
> --------------------------------------------------------------------
>
> Key: WICKET-6911
> URL: https://issues.apache.org/jira/browse/WICKET-6911
> Project: Wicket
> Issue Type: Improvement
> Components: wicket-spring
> Affects Versions: 9.4.0
> Environment: wicket-core: 9.4.0
> wicket-spring: 9.4.0
> spring-context: 5.3.9
> Reporter: Flying Wolf
> Assignee: Sven Meier
> Priority: Minor
> Attachments: HomePage.html, HomePage.java, MyComponent.java,
> MyService.java, WicketApplication.java, pom.xml
>
>
> Since Spring 4, the use of constructor injection for dependencies is possible
> and recommended, instead of setter injection. So most Spring users probably
> use constructor dependency injection in their Spring components.
> But this causes an exception when used with wicket-spring. When tried, cglib
> used by wicket-spring, will throw an error with message: "Superclass has no
> null constructors but no arguments were given". So basically every Spring
> user will by default get this error, without a clear solution.
> However, there exists a simple but undocumented solution or feature, which is
> mentioned in [https://stackoverflow.com/a/36324808/1039774]
> {quote}_Objenesis_ is a little and less known byte code manipulation library
> which (in opposite to _CGLIB_ provided together with _Wicket_) is able to
> create a proxy object for a class which has no default (no args) constructor.
> If you add it as a compile dependency to your project then _Wicket_ will
> switch it's internal lazily initializable proxy creation logic to take
> advantage of _Objenesis_ (instead _CGLIB_ which requires no args constructor)
> while instantiating a proxy. Unfortunately this feature is not documented but
> I can confirm it works in my case.
> {quote}
> Wicket-spring internally checks for the availability of Objenesis. If present
> in the class path, it will use Objenesis instead of cglib, when a no
> no-argument-constructor is present. See
> [https://github.com/apache/wicket/blob/509bd2fec696ff44d231874477ebcd2549437fef/wicket-ioc/src/main/java/org/apache/wicket/proxy/LazyInitProxyFactory.java#L170]
> This feature or solution is not mentioned in the documentation
> ([https://ci.apache.org/projects/wicket/guide/9.x/single.html#_integrating_wicket_with_spring]),
> neither in the exception, causing the error to appear like a bug.
> To solve this problem, one or many of the following points should be taken
> for the Wicket repository code base:
> * Objenesis provided as a dependency in wicket-spring pom.xml
> * Objenesis should be mentioned in the documentation of
> [https://ci.apache.org/projects/wicket/guide/9.x/single.html#_integrating_wicket_with_spring]
> * LazyInitProxyFactory should mention about Objenesis in the exception, when
> Objenesis is not present and only argument-constructors are present.
> h1. Example code causing the exception:
> {code:java}
> @Component
> public class MyComponent {}
> // This Spring bean isn't accepted by wicket-spring, because of ctor injection
> @Service
> public class MyService {
> private MyComponent myComponent;
> public MyService(MyComponent myComponent) {
> this.myComponent = myComponent;
> }
> }
> public class HomePage extends WebPage {
> @SpringBean
> private MyService myService;
> public HomePage(final PageParameters parameters) {
> super(parameters);
> }
> }
> public class WicketApplication extends WebApplication {
> //...
> @Override
> public void init() {
> super.init();
> AnnotationConfigApplicationContext context = new
> AnnotationConfigApplicationContext();
> context.scan("myapp.spring");
> context.refresh();
> getComponentInstantiationListeners().add(new
> SpringComponentInjector(this, context));
> }
> }
> {code}
> Exception:
> {quote}Exception:
> Last cause: Superclass has no null constructors but no arguments were given
> WicketMessage: Can't instantiate page using constructor 'public
> myapp.wicket.HomePage(org.apache.wicket.request.mapper.parameter.PageParameters)'
> and argument ''. An exception has been thrown during construction!
> Root cause:
> java.lang.IllegalArgumentException: Superclass has no null constructors but
> no arguments were given
> at net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:931)
> at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:631)
> at
> net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
> at
> net.sf.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:332)
> at net.sf.cglib.proxy.Enhancer.generate(Enhancer.java:492)
> at
> net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:96)
> at
> net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:94)
> at net.sf.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
> at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
> at net.sf.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
> at net.sf.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
> at
> net.sf.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:119)
> at
> net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:294)
> at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:480)
> at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:305)
> at
> org.apache.wicket.proxy.LazyInitProxyFactory.createProxy(LazyInitProxyFactory.java:191)
> at
> org.apache.wicket.spring.injection.annot.AnnotProxyFieldValueFactory.getFieldValue(AnnotProxyFieldValueFactory.java:166)
> at org.apache.wicket.injection.Injector.inject(Injector.java:111)
> at
> org.apache.wicket.spring.injection.annot.SpringComponentInjector.inject(SpringComponentInjector.java:124)
> ...
> at java.base/java.lang.Thread.run(Thread.java:834)
> Complete stack:
> org.apache.wicket.WicketRuntimeException: Can't instantiate page using
> constructor 'public
> myapp.wicket.HomePage(org.apache.wicket.request.mapper.parameter.PageParameters)'
> and argument ''. An exception has been thrown during construction!
> at
> org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:194)
> ...
> at
> org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:277)
> java.lang.reflect.InvocationTargetException
> at
> java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native
> Method)
> at
> java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
> at
> java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
> at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
> at
> org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:171)
> ...
> at
> org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:277)
> java.lang.RuntimeException: error while injecting object [[Page class =
> myapp.wicket.HomePage, id = 6, render count = 0]] of type
> [myapp.wicket.HomePage]
> at org.apache.wicket.injection.Injector.inject(Injector.java:122)
> at
> org.apache.wicket.spring.injection.annot.SpringComponentInjector.inject(SpringComponentInjector.java:124)
> at
> org.apache.wicket.spring.injection.annot.SpringComponentInjector.onInstantiation(SpringComponentInjector.java:130)
> at
> org.apache.wicket.application.ComponentInstantiationListenerCollection$1.notify(ComponentInstantiationListenerCollection.java:38)
> at
> org.apache.wicket.application.ComponentInstantiationListenerCollection$1.notify(ComponentInstantiationListenerCollection.java:34)
> at
> org.apache.wicket.util.listener.ListenerCollection.notify(ListenerCollection.java:80)
> at
> org.apache.wicket.application.ComponentInstantiationListenerCollection.onInstantiation(ComponentInstantiationListenerCollection.java:33)
> at org.apache.wicket.Component.<init>(Component.java:690)
> at org.apache.wicket.MarkupContainer.<init>(MarkupContainer.java:179)
> at org.apache.wicket.Page.<init>(Page.java:171)
> ...
> at
> org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:277)
> {quote}
> h1. Example code without the problem:
> Add Objenesis dependency to pom.xml:
> {code:java}
> <dependency>
> <groupId>org.objenesis</groupId>
> <artifactId>objenesis</artifactId>
> <version>3.2</version>
> </dependency>
> {code}
> The rest of the code can stay the same. (Only the presence of Objenesis
> solves the problem.)
--
This message was sent by Atlassian Jira
(v8.3.4#803005)