views:

724

answers:

5

Hi all.

I have a singleton bean definition like this:

<bean id="exampleBean" class="com.examples.ExampleBean">
  <property name="exampleBean2">
    <bean class="com.examples.ExampleBean2" />
  </property>
</bean>

where ExampleBean could be:

public class ExampleBean {
  private ExampleBean2 exampleBean2;

  public ExampleBean() { }

  public ExampleBean2 getExampleBean2() { return exampleBean2; }
  public void setExampleBean2(ExampleBean2 exampleBean2) { this.exampleBean2 = exampleBean2; }
}

The problem is that, in certain conditions, the com.examples.ExampleBean2 class might not exist at runtime witch will cause an error when the IoC tries to instantiate exampleBean.

What I need is to ignore this error from IoC and allow the exampleBean to be created but leaving the exampleBean2 property null.

So the question is: is this possible in any way?

Thanks for all your help.

+1  A: 

Is it an option to declare an init-method on your ExampleBean, and in this init-method check if the class ExampleBean2 exists, and if so setting it?

<bean id="exampleBean" class="com.examples.ExampleBean" init-method="init"/>

Maybe a better way of doing things here would be to use some form of the NullPattern, where you always provide an implementation of ExampleBean2, even if it only is its 'null' value.

eljenso
eljenso, I'll take a look at init-method. I already have a workaround for this and that is similar to the NullPattern you described. Thanks. +1
bruno conde
A: 

maybe lazy-init will do it, but i think spring will at least check if the bean implementation class is available at creation of the application context

Michael Lange
Michael, lazy-init doesn't solve it because when exampleBean is instantiated, all of it's dependencies are also instantiated (lazy or not) and that includes exampleBean2
bruno conde
+1  A: 

If I got it right ExampleBean2 isn't loaded when Spring tries to instantiate the beans. Is this correct? In that case I don't thing you could do much with Spring's built in capabilities.

Perhaps you could create a container class that will always be present. This class will check if ExampleBean2 is loaded and if yes, it will instantiate an instance of it. The container class will have an Object property that could either be null or the instance of the ExampleBean2.

kgiannakakis
kgiannakakis, ExampleBean2 is loaded when ExampleBean is instantiated. I still want to instantiate ExampleBean even if ExampleBean2 fails because the class doesn't exist. I already have a workaround for this and that is similar to what you described. Thanks. +1
bruno conde
A: 

Perhaps this will work:

public class NullFactoryBean implements FactoryBean {

    @Override
    public Object getObject() throws Exception {
        return null;
    }

    @Override
    public Class<?> getObjectType() {
        return Object.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }

}

And then...

public class ClassNotFoundPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
            String beanClassName = beanDefinition.getBeanClassName();
            try {
                Class.forName(beanClassName);
            } catch (ClassNotFoundException e) {
                beanDefinition.setBeanClassName(NullFactoryBean.class.getName());
            }
        }
    }

}

And then...

<beans>
    <bean id="exampleBean" class="com.examples.ExampleBean">
        <property name="exampleBean2">
            <bean class="com.examples.ExampleBean2" />
        </property>
    </bean>

    <bean class="ClassNotFoundPostProcessor" />
</beans>

EDIT: Sorry about that, it appears that this did not catch the inner beans. I missed this detail when I tested it. It only catches top-level beans. By the way, com.examples.ExampleBean probably won't load anyway because it itself depends directly upon the ExampleBean2 class, which the virtual machine won't find, causing an Error

Adam Paynter
+3  A: 

If you use autowire, what you wish to achieve is possible.

<bean class="com.examples.ExampleBean" autowire="byType" />
<bean class="com.examples.ExampleBean2" />

Or via annotations

@Autowired(required=false)
ExampleBean2 exampleBean2;
Kent Lai