Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-12915

ConfigurationClassEnhancer.enhanceFactoryBean is not transparent for method calls other than getObject()

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Complete
    • Affects Version/s: 4.1.2
    • Fix Version/s: 4.2 RC1
    • Component/s: Core:DI
    • Labels:
      None
    • Last commented by a User:
      false

      Description

      When a @Bean method returns an instance of a FactoryBean, Spring proxies the factory bean, redirecting calls to getObject() to applicationContext.getBean().

      The relevant code reads:

      	/**
      	 * Create a subclass proxy that intercepts calls to getObject(), delegating to the current BeanFactory
      	 * instead of creating a new instance. These proxies are created only when calling a FactoryBean from
      	 * within a Bean method, allowing for proper scoping semantics even when working against the FactoryBean
      	 * instance directly. If a FactoryBean instance is fetched through the container via &-dereferencing,
      	 * it will not be proxied. This too is aligned with the way XML configuration works.
      	 */
      	private Object enhanceFactoryBean(Class<?> fbClass, final ConfigurableBeanFactory beanFactory,
      			final String beanName) throws InstantiationException, IllegalAccessException {
      
      		Enhancer enhancer = new Enhancer();
      		enhancer.setSuperclass(fbClass);
      		enhancer.setUseFactory(false);
      		enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      		enhancer.setCallback(new MethodInterceptor() {
      			@Override
      			public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
      				if (method.getName().equals("getObject") && args.length == 0) {
      					return beanFactory.getBean(beanName);
      				}
      				return proxy.invokeSuper(obj, args); // bug here?
      			}
      		});
      		return enhancer.create();
      	}
      

      In the marked line, obj refers to the proxy object.

      Therefore, calls to methods other than getObject() are forwarded to the super implementation on the proxy object, which has a different state than the FactoryBean it proxies.

      This breaks the following usecase:

              @Bean
              protected DBTool dbTool() {
                  return new DBTool(hibernateSessionFactory());
              }
      
              @Bean
              protected AnnotationSessionFactoryBean hibernateSessionFactory() {
                   // hibernate setup goes here
              }
      

      where DBTool has a method:

          public void createSchema() {
              annotationSessionFactory.createDatabaseSchema();
          }
      

      which now throws

      java.lang.IllegalStateException: SessionFactory not initialized yet
      	at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.getSessionFactory(AbstractSessionFactoryBean.java:215)
      	at org.springframework.orm.hibernate3.LocalSessionFactoryBean.createDatabaseSchema(LocalSessionFactoryBean.java:989)
      	at org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean$$EnhancerBySpringCGLIB$$2fba14bc.CGLIB$createDatabaseSchema$12(<generated>)
      	at org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean$$EnhancerBySpringCGLIB$$2fba14bc$$FastClassBySpringCGLIB$$52787a0.invoke(<generated>)
      	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
      	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor$1.intercept(ConfigurationClassEnhancer.java:383)
      	at org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean$$EnhancerBySpringCGLIB$$2fba14bc.createDatabaseSchema(<generated>)
      	at ch.bedag.ste.app.cf.hibernate.framework.DBTool.createSchema(DBTool.java:23)
      

      because the proxy object is a factory that has not been configured.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                juergen.hoeller Juergen Hoeller
                Reporter:
                bedag-moo Adrian Moos
                Last updater:
                Juergen Hoeller
              • Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Days since last comment:
                  2 years, 50 weeks, 6 days ago