Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wicket @SpringBean and Spring @Autowired with injection via constructor

I have a Wicket panel in which I want to inject bean using @SpringBean

public class SomePanel extends Panel {

  @SpringBean
  private BlogSummaryMailGenerator blogSummaryMailGenerator;

}

But this BlogSummaryMailGenerator has injection via constructor defined like this:

@Component
public class BlogSummaryMailGenerator {

  private BlogRepository blogRepository;
  private BlogPostRepository blogPostRepository;

  @Autowired
  public BlogSummaryMailGenerator(BlogRepository blogRepository,
                                BlogPostRepository blogPostRepository) {
    this.blogRepository = blogRepository;
    this.blogPostRepository = blogPostRepository;
  }
}

And when SomePanel is instantiated I am getting an exception

Caused by: java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
at net.sf.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:721) ~[cglib-3.1.jar:na]
at net.sf.cglib.proxy.Enhancer.generateClass(Enhancer.java:499) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25) ~[cglib-3.1.jar:na]
at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216) ~[cglib-3.1.jar:na]
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377) ~[cglib-3.1.jar:na]
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285) ~[cglib-3.1.jar:na]
at org.apache.wicket.proxy.LazyInitProxyFactory.createProxy(LazyInitProxyFactory.java:191) ~[wicket-ioc-7.2.0.jar:7.2.0]

Adding empty no-args constructor to the BlogSummaryMailGenerator solves this issue but adding such code only to make injection work is wrong and I would like to avoid it.

Any suggestions how to make @SpringBean work with beans using injection via constructor?

like image 684
Tomasz Dziurko Avatar asked Feb 07 '16 23:02

Tomasz Dziurko


People also ask

Can we use @autowired on constructor?

You can apply @Autowired to constructors as well. A constructor @Autowired annotation indicates that the constructor should be autowired when creating the bean, even if no <constructor-arg> elements are used while configuring the bean in XML file.

What is the difference between Autowired and constructor injection?

You can annotate fields and constructor using @Autowired to tell Spring framework to find dependencies for you. The @Inject annotation also serves the same purpose, but the main difference between them is that @Inject is a standard annotation for dependency injection and @Autowired is spring specific.

Does Spring @autowired inject beans by name or by type?

Spring @Autowired Annotation - Service ClassThe setter method will be used for spring autowiring byName and byType whereas constructor based injection will be used by constructor autowire attribute.

How constructor injection works in Spring?

Constructor Based Dependency Injection. It is a type of Spring Dependency Injection, where object's constructor is used to inject dependencies. This type of injection is safer as the objects won't get created if the dependencies aren't available or dependencies cannot be resolved.


1 Answers

The real problem is in CGLIB. It requires a default constructor to be able to create the proxy instance. The real Spring bean is created separately by Spring and has no such restrictions. The default constructor needed by CGLIB could be even private as far as I remember.

Update: Since Wicket 9.5.0 Wicket could also use ByteBuddy instead of CGLib.

Another solution is to use an interface for this bean. Then Wicket will use JDK Proxy instead of CGLIB and in this case there is no need of default constructor in the implementation.

like image 171
martin-g Avatar answered Nov 15 '22 04:11

martin-g