33

Im using Spring Social in my application:

<spring.framework.version>3.2.0.RELEASE</spring.framework.version>
<hibernate.version>4.1.9.Final</hibernate.version>
<commons-dbcp.version>1.4</commons-dbcp.version>
<org.springframework.social-version>1.1.0.BUILD-SNAPSHOT</org.springframework.social-version>
<org.springframework.social.facebook-version>1.1.0.BUILD-SNAPSHOT</org.springframework.social.facebook-version>
<org.springframework-version>3.2.1.RELEASE</org.springframework-version>
<org.springframework.security.crypto-version>3.1.3.RELEASE</org.springframework.security.crypto-version>

When I apply

private final Facebook facebook;

@Inject
public SearchController(Facebook facebook) {
    this.facebook = facebook;
}

To my HomeController:

@Controller
public class HomeController {


    private final Facebook facebook;

    @Inject
    public HomeController(Facebook facebook) {
        this.facebook = facebook;
    }

    private static final Logger logger = LoggerFactory.getLogger(HomeController.class);

    /**
     * Simply selects the home view to render by returning its name.
     */
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String home(Model model) {
        return "home";
    }

}

The injection works like intented and I can get information from facebook. However, when I apply it to one of my other Cotrollers like this one

@Controller
@Transactional
@RequestMapping(value = "/search")
public class SearchController {

    private static final Logger logger = LoggerFactory.getLogger(SearchController.class);

    private final Facebook facebook;

    @Inject
    public SearchController(Facebook facebook) {
        this.facebook = facebook;
    }

    @PersistenceContext
    private EntityManager entityManager;

    ...

I getting this error:

mar 05, 2013 12:46:36 EM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/project] threw exception [Request processing failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'searchController' defined in file [C:\Users\Nilsi\Downloads\springsource\vfabric-tc-server-developer-2.7.2.RELEASE\base-instance\wtpwebapps\course_info\WEB-INF\classes\com\courseinfo\project\controller\SearchController.class]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.courseinfo.project.controller.SearchController]: 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] with root cause
java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given
    at org.springframework.cglib.proxy.Enhancer.emitConstructors(Enhancer.java:721)
    at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:499)
    at org.springframework.cglib.transform.TransformingClassGenerator.generateClass(TransformingClassGenerator.java:33)
    at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
    at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
    at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:285)
    at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205)
    at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:111)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:477)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:362)
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:412)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1492)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:524)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1117)
    at org.springframework.web.method.HandlerMethod.createWithResolvedBean(HandlerMethod.java:202)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:233)
    at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.getHandlerInternal(AbstractHandlerMethodMapping.java:55)
    at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:297)
    at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1091)
    at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1076)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:896)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:920)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:801)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

My guess is that I can't inject facebook to a Controller with annotation @Transactional?

nilsi
  • 10,351
  • 10
  • 67
  • 79
  • Is it working if you use property based injection? – Maksym Demidas Mar 05 '13 at 17:13
  • Wow, it worked! if you put it as an answer I will mark it as correct. I simply deleted the constructor and changed to this: @Inject private Facebook facebook; Tested that before but couldn't get it to work cause the variable originally was final. (Was final in Springs example code i got it from). – nilsi Mar 05 '13 at 17:38

3 Answers3

68

CGlib has one important restriction: the target class must provide a default constructor.

If you use property-based injection instead of constructor-based injection, the problem will go away.

Makoto
  • 104,088
  • 27
  • 192
  • 230
Maksym Demidas
  • 7,707
  • 1
  • 29
  • 36
  • 49
    Expanding on this answer: This would have worked fine via constructor-injection (which is preferred) had you not added `@Transactional` to the controller. Once you added `@Transactional`, AOP kicks in and a proxy must be created. CGLib needs a default constructor. Another solution is to configure Spring transactions to use AspectJ instead of proxies. This requires a bit more setup, but would allow transactions on a class with no default constructor. – Craig Walls Mar 06 '13 at 15:11
  • 3
    This is a very good comment! I think it should be added to the answer. – Ido.Co Jan 16 '14 at 09:28
  • 9
    Prior to Spring 4, CGLIB-based proxy classes require a default constructor. And this is not the limitation of CGLIB library, but Spring itself. Fortunately, as of Spring 4 this is no longer an issue. CGLIB-based proxy classes no longer require a default constructor. See this article: http://blog.codeleak.pl/2014/07/spring-4-cglib-based-proxy-classes-with-no-default-ctor.html – Rafal Borowiec Jul 02 '14 at 15:32
  • 3
    I found a way to make it work with constructor-injection and `@Transactional`. Create an interface that `SearchController` implements, and change the contructor of `HomeController` to take an instance of this interface instead. – marstran Jan 12 '16 at 13:13
  • 2
    Basically make `HomeController` depend on an interface, not an implementation. – marstran Jan 12 '16 at 14:17
  • 1
    This interface hint really is worth a mint, should be an answer! – Sebastian Apr 04 '16 at 10:53
  • The comment from @marstran is useful in that allows you to use both constructor injection and `@Transactional` at the same time. Just make the class with `@Transactional` to implement an interface. – Igor Rodriguez Jul 05 '17 at 13:40
  • I don't really remember making this comment, and I find it a bit confusing. Why did I say that `HomeController` should take a `SearchController` as an argument? Is anyone able to decode what I meant? :) – marstran Jul 05 '17 at 15:06
  • @CraigWalls - How do you suggest injecting a constructor using cglib? – AlikElzin-kilaka Mar 14 '18 at 16:01
1

I just created an empty default constructor to deal with this.

Smart Coder
  • 1,435
  • 19
  • 19
-2

If you are using Lombok in your code, then you can just add the following annotation to get rid of this error:

@NoArgsConstructor
public class SearchController {
Navigatron
  • 2,065
  • 6
  • 32
  • 61
  • Seriously dude? Do you really believe that writing an empty constructor is a big deal that requires an additional library and IDE plugin? – sergpank Dec 04 '18 at 10:52
  • 4
    @sergpank If its already included in your project, why wouldn't you use it? I clearly stated "if you are using Lombok". It can do a lot more than just add an empty constructor by the way. – Navigatron Dec 04 '18 at 12:20
  • 1
    Thank you for your opinion. I'm sorry you feel that way. – Navigatron Dec 06 '18 at 14:45
  • The @NoArgsConstructor is one of the reasons why I hate Lombok today. It provides a negligible code length reduction while preventing me from using my IDE's "find usages" option. Just write the constructor and document why it exists (see that you failed to document why the annotation is needed). – Torben Oct 05 '21 at 10:23
  • @Torben That issue is with your IDE, using "open call hierarchy" in Eclipse reports all usages correctly. There might be a setting you can change to get it to work in whatever IDE you are using. – Navigatron Oct 08 '21 at 09:39