Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 265 Vote(s) - 3.53 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Intentionally setting a Spring bean to null

#1
I'm using Spring to inject JMS connection factory into my Java application. Since this factory is only required within the production environment, not while I'm developing though, I put the bean definition into a separate XML which I include into my main applicationContext.xml. In production environments this extra file contains the regular bean definition. In my local dev environment I'd like this bean to be null. Trying to simply remove the bean definition all-toghether obviously caused an error when Spring came across a reference ID it didn't know.

So I tried creating a factory bean that would simply return null. If I do this, Spring (2.5.x) complains that the factory returned null although based on the Spring API doc of the FactoryBean interface I expected this to work (see [Spring API doc][1]).

The XML looks something like this:

<bean id="jmsConnectionFactoryFactory" class="de.airlinesim.jms.NullJmsConnectionFactoryFactory" />

<bean id="jmsConnectionFactory" factory-bean="jmsConnectionFactoryFactory" factory-method="getObject"/>

What would be the "correct" way of doing this?


[1]:

[To see links please register here]

Reply

#2
Can you make use of the special `<null>` bean element ? e.g.

<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>

from [the doc][1], section 3.3.2.5


[1]:

[To see links please register here]

Reply

#3
Some noted above, axtact's answer doesn't work in Autowiring contextes, where Spring will rely on correct information from the getObjectType() method. So you might end up with errors like:

<pre>
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [xxxxxxxxxxxxx] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=yyyyyyyyyyyyyyyy)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:920)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:789)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:703)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotatio
</pre>

So here's a small variation which involves allowing users to force the objectype at construction. Using a property instead of a constructor-arg didn't work because Spring doesn't fully initialize the beans in this context.

public class NullFactoryBean implements FactoryBean {
private final Class<?> objectType;

public NullFactoryBean(Class<?> objectType) {
this.objectType = objectType;
}

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

@Override
public Class<?> getObjectType() {
return objectType;
}

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

#4
`factory-bean`/`factory-method` doesn't work with `null`, but a custom `FactoryBean` implementation works fine:

public class NullFactoryBean implements FactoryBean<Void> {

public Void getObject() throws Exception {
return null;
}

public Class<? extends Void> getObjectType() {
return null;
}

public boolean isSingleton() {
return true;
}
}

<!-- language: lang-xml -->

<bean id="jmsConnectionFactory" class = "com.sample.NullFactoryBean" />
Reply

#5
For anyone coming to this question, keep in mind that simply setting the @Autowired annotation as optional will do the trick (i.e. Spring will leave the reference null if no qualifying bean is found).

@Autowired(required = false)
private SomeClass someBean

Note that you would have to do this everywhere the bean is referenced, which may be a bigger hassle than creating a null-factory as mentioned above.
Reply

#6
In tests null beans can also be injected like this:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = NullTest.class)
@Configuration
public class NullTest {

@Bean(name = "em")
public IEntityManager em() { return null; }
@Bean
public PlatformTransactionManager tm() { return null; }

@Resource
private SomeBean someBean; // this would get em and tm fields autowired to nulls
Reply

#7
I'm pretty sure that Spring won't allow you to associate `null` with a bean id or alias. You can handle this by setting properties to null.

Here's how you did this in Spring 2.5

<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>

In Spring 3.0, you should also be able to use the [Spring expression language (SpEL)][1]; e.g.

<bean class="ExampleBean">
<property name="email" value="#{ null }"/>
</bean>

or any SpEL expression that evaluates to `null`.

And if you are using a placeholder configurator you could possibly even do this:

<bean class="ExampleBean">
<property name="email" value="#{ ${some.prop} }`"/>
</bean>

where `some.prop` could be defined in a property file as:

some.prop=null

or

some.prop=some.bean.id


[1]:

[To see links please register here]

Reply

#8
For anyone else who comes across this: another approach if you're using Java 8 is to use the `Supplier` functional interface to wrap a potentially null bean:

```
@Bean
@Scope("singleton")
public Supplier<SomeBean> getSomeBean() {
SomeBean myBean = null; // or can set to a SomeBean instance
return () -> myBean;
}
```

With `@Autowired` constructor injection using this looks like:

```
private SomeBean someBean;

@Autowired
SomeService(Supplier<SomeBean> someBeanSupplier) {
this.someBean = someBeanSupplier.get();
}
```

Then the `someBean` field in `SomeService` can either be null or non-null.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through