Uploaded image for project: '[Read Only] - Hippo Site Toolkit 2'
  1. [Read Only] - Hippo Site Toolkit 2
  2. HSTTWO-3953

Avoid FactoryBeanNotInitializedException warning when Auto-wiring is used in end projects.

    XMLWordPrintable

Details

    • Improvement
    • Status: Closed
    • Normal
    • Resolution: Fixed
    • 4.2.0
    • 5.0.0
    • None
    • None
    • Turing Sprint 156, Turing Sprint 157

    Description

      From community forum by Dennis Nijssen,

      I've just created a new archetype project, and added a Component, PageErrorHandler and a FooService aswell.
      When I run mvn clean package and mvn -P cargo.run I still get the following warning on startup:

      29.03.2017 08:55:53 WARN localhost-startStop-1 [AbstractBeanFactory.getTypeForFactoryBean:1485] Bean creation exception on non-lazy FactoryBean type check: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.hippoecm.hst.pagecomposer.jaxrs.security.SecurityModel#SecurityModelEventListener' defined in class path resource [org/hippoecm/hst/pagecomposer/SpringComponentManager-pagecomposer.xml]: Cannot resolve reference to bean 'jcrObservationEventListenerItems' while setting bean property 'targetObject'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'jcrObservationEventListenerItems': org.springframework.beans.factory.FactoryBeanNotInitializedException: FactoryBean is not fully initialized yet

      As reference I pushed my code to a public github repository: https://github.com/dnijssen/myhippoproject

      Is there anything in the Hippo testsuite that fixed this warning? Or is it cause the testsuite is running on Hippo 12.0 ?
      It is indeed still working correctly, I've also checked with a debugged and the FooService is injected correctly in the Component and PageErrorHandler.

      Woonsan gave a reasoning:

      Thank you very much for sharing the github project! It was really helpful!
      I was able to see the same warning locally, too. It is indeed a very interesting problem case.
      But the good news is, the warning message seems almost harmless to me! So, you can ignore the warning in this context.

      Here's my explanation.

      • When an applicationContext is initialized, if auto-wiring is used, then for each @Autowired field/property, the AutowiredAnnotationBeanPostProcessor tries to find a type-matched bean from the beanFactory.
      • In your project, actually the warning occurred while it tries to find a bean of type FooService (a type-matched bean by FooService type in this case) for MyPageErrorHandler bean. I found this by attaching debugger at AbstractBeanFactory.getTypeForFactoryBean:1485 literally and looking at the stack trace.
      • The way how it determines the best type-matched bean is, (1) iterate each bean definition from all the beans registered in the beanFactory, (2) if a bean definition is not a factoryBean, it checks the type directly and put in into a bag or ignore, or if it is a factoryBean, it needs to determine the return type of the method to use, or return null with that kind of warning if the factory cannot determine the target object or class yet for some reason, c) from the all the candidate beans collected by the type, it finally determines which to take for the @Autowired field/property.
      • In your project, during the scanning/determination process, it left some warnings on some of factory beans due to not being ready to determine the return type of the target method at the moment, but it found out the proper FooService bean in the end and assign in to the MyPageErrorHandler bean. I confirmed this by expressions in debug session:
        • org.hippoecm.hst.site.HstServices.getComponentManager().getComponent("org.hippoecm.hst.core.container.PageErrorHandler")
        • org.hippoecm.hst.site.HstServices.getComponentManager().getComponent("jcrObservationEventListenerItems ")
      • Luckily in this case, the ignored (with warning) bean definitions were simply the factory beans to create a java.util.List objects such as 'jcrObservationEventListenerItems'.

      Therefore, you can ignore this kind of warning logs if the warning logs are concerning about only factory bean definitions which are out of interest in terms of auto-wiring in your project.

      However, even if it is ignorable warnings, as Dennis mentioned:

      Thank you for researching this Woonsan, although the conclusion is we can ignore the warnings, isn't it better to prevent them from happening?
      I've seen the same warning happening when adding the urlrewriter plugin. With that particular case I had the urlrewriting-context.xml in my project and was able to add depends-on="jcrObservationEventListenerItems" to the MethodInvokingFactoryBean, This made the warnings disappear.

      Therefore, one of desirable solutions would be as follows:

      "depends-on" seems to make it more difficult to maintain the software, IMHO.
      So I have another solution:

      • AbstractBeanFactory has a special routine for factory bean: #getTypeForFactoryBean(String, RootBeanDefinition).
      • That routine invokes FactoryBean#getObjectType(). So in most cases, it doesn't require the factory bean to determine the return type of the target object or class just for type checking.
      • However, unfortunately, MethodInvokingFactoryBean#getObjectType() was implemented to try to determine the return type of the target object or class because it is unaware of the type unlike how ListFactoryBean and MapFactoryBean does statically (they can safely infer the type is either java.util.List or java.util.Map, for instance).
      • So, my solution is, maybe HST can extend MethodInvokingFactoryBean to have predetermined type. For example,

      [Before]

      <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
      <property name="targetObject" ref="jcrObservationEventListenerItems"/>
      <property name="targetMethod" value="add"/>
      <!-- SNIP -->
      </bean>

      [After]

      <bean class="org.hippoecm.hst.site.container.TypeDeterminedMethodInvokingFactoryBean">
      <property name="targetObject" ref="jcrObservationEventListenerItems"/>
      <property name="targetMethod" value="add"/>
      <property name="objectType" value="java.lang.Boolean" />
      <!-- SNIP -->
      </bean>

      TypeDeterminedMethodInvokingFactoryBean extends MethodInvokingFactoryBean, accepting predetermined objectType and so it doesn't have to even try to even determine the target object or class at all, but simply return the given objectType class to AbstractBeanFactory. AbstractBeanFactory cannot complain it any more because the custom MethodInvokingFactoryBean know what the return type is beforehand.

      I think this should be simpler than adding "depends-on" in xml resources (btw, actually there are many more hidden xml resources by hst addon modules, etc. out there, so adding 'depends-on' requires a lot more maintenance efforts in my view, also there might still be some corner cases even with that change), safer and more proper because it doesn't change any bean definitions semantics.

      Attachments

        Issue Links

          Activity

            People

              Unassigned Unassigned
              wko Woonsan Ko (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: