Flying Wolf created WICKET-6911:
-----------------------------------
Summary: 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: Bug
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
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)