Intentionally setting a Spring bean to null - java

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).
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?

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); 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

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;
}
}
<bean id="jmsConnectionFactory" class = "com.sample.NullFactoryBean" />

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.

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.

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:
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
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;
}
}

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

Can you make use of the special <null> bean element ? e.g.
<bean class="ExampleBean">
<property name="email"><null/></property>
</bean>
from the doc, section 3.3.2.5

Related

What happens when we define bean with different names with Annotations and XML config?

The coach object is created with Annotations and coach2 is created with XML configuration file. They both refering to the tennisCoach class.
In singleton scope beans refer to the same place in memory but in this situation memory place is different.
I have two questions.
Why Spring lets us create two objects?
Why it doesn't give an error about why an id is assigned to this object with annotation and we define the object again in XML or vice versa.
Does Spring create objects in prototype scope?
Coach coach = context.getBean("tennisCoach", Coach.class);
Coach coach2 = context.getBean("myCoach", Coach.class);
System.out.println(coach); //output: demo.TennisCoach#451001e5
System.out.println(coach2); //output: demo.TennisCoach#2b40ff9c
applicationContext.xml
<bean id="myCoach" class="demo.TennisCoach"></bean>
TennisCoach.java
#Component
public class TennisCoach implements Coach {...}
I know that one definition is enough for bean but I was just wondering about this situation.
Let me be more clear. Scope prototype creates a new bean every time you inject it. So if you have bean A and you inject it in bean B and C you will have two instance of bean A created.
Indeed let’s make some examples with singletons with xml and annotation. let’s say you have this xml configuration:
<bean id="myCoach1" class="demo.TennisCoach"></bean>
<bean id="myCoach2" class="demo.TennisCoach"></bean>
<bean id="bean1" class="demo.Bean1">
<property name=“coach” ref=“myCoach1” />
</bean>
<bean id="bean2" class="demo.Bean2">
<property name=“coach” ref=“myCoach2”/>
</bean>
So what’s happening here we are creating two beans of type demo.TennisCoach and injecting them by name in bean1 and bean2.
We can also use annotation configuration to achieve the same results:
#Configuration
public class Configuration {
#Bean(name = “myCoach1”)
public TennisCoach createMyCoach1() {
return new TennisCoach();
}
#Bean(name = “myCoach2”)
public TennisCoach createMyCoach2() {
return new TennisCoach();
}
#Bean
public Bean1 createBean1(#Qualifaer(“myCoach1” TennisCoach coach) {
return new Bean1(coach);
}
#Bean
public Bean2 createBean2(#Qualifaer(“myCoach2” TennisCoach coach) {
return new Bean2(coach);
}
}
Note the usage of #Qualifier to tell spring witch bean to inject. If you don’t use it spring doesn’t know which of the two TennisCoach should inject because by default it injects by type.
The same happens with #Autowired it by default injects by type but you can combine it with #Qualifier to inject the correct bean if you have more than one of the same type.
You can even mix xml and annotation (I don’t suggest it:
#Configuration
#ImportResource({“classpath:application-context.xml”})
public class Configuration {
#Bean
public Bean1 createBean1(#Qualifaer(“myCoach1” TennisCoach coach) {
return new Bean1(coach);
}
#Bean
public Bean2 createBean2(#Qualifaer(“myCoach2” TennisCoach coach) {
return new Bean2(coach);
}
}

Injecting object into Spring Configuration

I am turning old xml/java configuration into pure java config. In xml I used injection of parameters into configuration file like this:
<bean class="com.project.SpringRestConfiguration">
<property name="parameters" ref="parameters" />
</bean>
#Configuration
public class SpringRestConfiguration {
private Parameters parameters;
public void setParameters(Parameters parameters) {
this.parameters = parameters;
}
// #Bean definitions
...
}
Is it possible to inject Parameters in javaconfig? (Without the need of using autowiring!)
#Configuration
#Import(SpringRestConfiguration.class)
EDIT:
With #Import I can't see any chance to inject Parameters into SpringRestConfiguration
Basically you would need to use #Autowired but you can still use a name and not type interpretation like this:
#Configuration
public class SpringRestConfiguration {
#Autowired
#Qualifier("parameters") // Somewhere in your context you should have a bean named 'parameters'. It doesn't matter if it was defined with XML, configuration class or with auto scanning. As long as such bean with the right type and name exists, you should be good.
private Parameters parameters;
// #Bean definitions
...
}
This solves the confusion problem you mentioned when using #Autowired - there's no question here which bean is injected, the bean that is named parameters.
You can even do a little test, leave the parameters bean defined in the XML as before, use #Autowired, see that it works. Only then migrate parameters to #Configuration class.
In my answer here you can find a complete explanation of how you should migrate XML to #Configuration step by step.
You can also skip the private member altogether and do something like this:
#Configuration
public class SpringRestConfiguration {
#Bean
public BeanThatNeedsParamters beanThatNeedsParamters (#Qualifier("parameters") Parameters parameters) {
return new BeanThatNeedsParamters(parameters)
}
}
If I have understood your question properly, this is what you are trying to do :
#Component
public class SomeConfiguration {
#Bean(name="parameters")
public Parameters getParameters(){
Parameters parameters = new Parameters();
// add your stuff
return parameters;
}
#Bean(name="springRestConfiguration")
public SpringRestConfiguration springRestConfiguration(){
SpringRestConfiguration springRestConfiguration = new SpringRestConfiguration();
springRestConfiguration.setParametere(getParameters());
return springRestConfiguration;
}
}
and use it like :
ApplicationContext appContext = new AnnotationConfigApplicationContext(SomeConfiguration.class);
SpringRestConfiguration springRestConfiguration = (SpringRestConfiguration) appContext.getBean("springRestConfiguration");

Defining the request scope as prototype for integration tests

When writing integration tests with Spring 3.1, I usually define the request scope to be a SimpleThreadScope, with the following XML context configuration:
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="request">
<bean class="org.springframework.context.support.SimpleThreadScope" />
</entry>
</map>
</property>
</bean>
To define the request scope to be backed by a prototype scope implementation, I thought to change the class to be an implementation of the prototype scope. However I was not able to locate any.
Looking at the Scope Interface Javadoc, in the section All Known Implementing Classes, I see listed: AbstractRequestAttributesScope, PortletContextScope, RequestScope, ServletContextScope, SessionScope, SimpleThreadScope... nothing that looks like a prototype scope.
How can I define the request scope as prototype for integration tests?
UPDATE: I've managed to make my integration tests pass by creating my own prototype scope, which I've defined as follow, so my question now is, whether the following implementation is correct, or it has to be fixed.
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.config.Scope;
public class PrototypeScope implements Scope {
private static final Log logger = LogFactory.getLog(PrototypeScope.class);
public Object get(String name, ObjectFactory objectFactory) {
return objectFactory.getObject();
}
public Object remove(String name) {
return null;
}
public void registerDestructionCallback(String name, Runnable callback) {
logger.warn("PrototypeScope does not support destruction callbacks. "
+ "Consider using a RequestScope in a Web environment.");
}
public Object resolveContextualObject(String key) {
return null;
}
public String getConversationId() {
return Thread.currentThread().getName();
}
}
UPDATE 2: I am using TestNG and my Integration tests look like this:
#Test
#ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class MyIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {
#Resource
private MyBeanThatShouldBePrototype bean;
#Transactional
public void testCase() {
...
In fact it's working in a different way - Spring checks if bean is a prototype, and then clones its definition and just populate new bean, so there is no backing class for holding such beans. If you want to look at the implementation please visit:
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean and you will find:
if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
If you want to use prototype scope in tests you can just manually create this bean by invoking new MyObjectThatShouldBePrototype() and then configure it as a Spring bean by using AutowireCapableBeanFactory (injected/autowired into your test):
#Autowired
AutowireCapableBeanFactory beanFactory;
public MyObjectThatShouldBePrototype getBean() {
MyObjectThatShouldBePrototype bean = new MyObjectThatShouldBePrototype();
beanFactory.autowireBean(bean);
return bean;
}
Of course there are several ways to create beans - you can find then here http://www.kubrynski.com/2013/09/injecting-spring-dependencies-into-non.html
Something like this is not working for you?
#Test
#ContextConfiguration(locations = { "classpath:META-INF/spring/test-context.xml" },
classes = MyIntegrationTest.TestConfig.class)
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class MyIntegrationTest extends AbstractTransactionalTestNGSpringContextTests {
#Resource
private MyBeanThatShouldBePrototype bean; // protype bean produced by spring
#Transactional
public void testCase() {
...
}
#Configuration
public static class TestConfig {
#Bean
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public MyBeanThatShouldBePrototype myBeanThatShouldBePrototype() {
return new MyBeanThatShouldBePrototype();
}
}
}
Probably you could go another way?
What about writing a beanfactorypostprocessor that changes the request scoped bean candidates to prototype instead?
I havent tried it myself but you should be able to apply this to any bean declared as request scoped and set the prototype flag.
In the spring context for your unit tests you define this processor and in the context for integration tests this postprocessor would not be around.

SpringBeanAutowiringInterceptor - Configure to autowire by name instead of by type?

I'm using a SpringBeanAutowiringInterceptor in an EJB3 stateless session bean, as described in the Spring documentation.
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class) // Allows spring injection for its setter methods
public class MyClassImpl extends MyAbstractClass implements MyClass
{
....
#Autowired
public void setMyCustomService2(MyService svc) {
this.service = svc;
}
And in SpringConfig.xml:
<bean id="myCustomService1" class="...MyService"/>
<bean id="myCustomService2" class="...MyService"/>
When Spring tries to autowire this I get
No unique bean of type [...MyService ] is defined:
expected single matching bean but found 2: [myCustomService1 , myCustomService2]
Unfortunately, it seems EJB autowiring defaults to byType mode, and I can't find a way to change it to byName mode.
Is this possible, and if so, how?
Have you tried with a Qualifier?
#Autowired
#Qualifier("myCustomService1")
public void setMyCustomService2(MyService svc) {
this.service = svc;
}

injecting ConversionService into a custom Converter

Using Spring mvc-3. I am writing a custom Converter which needs access to other Converters registered to a ConversionService.
How can I accomplish this? I tried writing my custom converter as:
class CustomConverter<X, Y>{
#Autowired ConversionService service;
//+getter & setters of service
public Y convert(X input){
// I need access to service to lookup simple conversions such as
// String array to Long array etc..
}
}
And I registered my custom converter via applicationContext.xml
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name = "converters">
<list>
<bean class="CustomConverter"/>
</list>
</property>
</bean>
However, spring refuses to inject service into my CustomConverter(its always null). How can I accomplish this?
Thank you!
I have come across same problem. There's an issue SPR-6415 in Spring JIRA covering this problem. I've giving here my solution based on discussion in this issue. It's the same principle like answer of #nmervaillie but you don't have to implement your own ConversionServiceFactoryBean.
/**
* Base class of #{code Converter} that need to use {#code ConversionService}.
* Instances of implementing classes must be spring-managed to inject ConversionService.
*
* #author Michal Kreuzman
*/
public abstract class CoversionServiceAwareConverter<S, T> implements Converter<S, T> {
#Inject
private ConversionService conversionService;
protected ConversionService conversionService() {
return conversionService;
}
/**
* Add this converter to {#code ConverterRegistry}.
*/
#SuppressWarnings("unused")
#PostConstruct
private void register() {
if (conversionService instanceof ConverterRegistry) {
((ConverterRegistry) conversionService).addConverter(this);
} else {
throw new IllegalStateException("Can't register Converter to ConverterRegistry");
}
}
}
#Component
public class SampleConverter extends CoversionServiceAwareConverter<Object, Object> {
#Override
public String convert(Object source) {
ConversionService conversionService = conversionService();
// Use conversionService and convert
}
}
I have used something like this recently to solve this problem.
Use a custom factory :
public class MyConversionServiceFactoryBean extends ConversionServiceFactoryBean {
#Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
ConversionService conversionService = getObject();
ConverterRegistry registry = (ConverterRegistry) conversionService;
// register converters that need a nested conversion service
registry.addConverter(new MyCustomConverter(conversionService));
}
}
which is declared like this :
<bean id="conversionService"
class="com.company.MyConversionServiceFactoryBean">
<property name="converters">
<list>
... declare standard converters here ...
</list>
</property>
</bean>
I solved this problem in spring-ws centric application. The main components of this solutions are:
declaring Converter implementations as spring beans
using #Lazy from spring-context on the injection points in the converters
inject all discovered converters in a ConversionServiceFactoryBean
SampleConverter
#Component
public class SampleConverter implements Converter<Source, Target> {
private ConversionService conversionService;
#Inject
#Lazy
public SampleConverter(ConversionService conversionService){
this.conversionService = conversionService;
}
#Override
public Target convert(Source source){
Target target = new Target();
...
target.setTargetDetails(conversionService.convert(source.getSourceDetails, TargetDetails.class);
...
and the Configuration:
#Configuration
public class ConversionServiceConfig {
#Bean
public ConversionService conversionService(Set<Converter<?,?>> converters){
ConversionServiceFactoryBean csfb = new ConversionServiceFactoryBean();
csfb.setConverters(converters);
csfb.afterPropertiesSet();
return csfb.getObject();
}
...
The #Lazy annotations circumvents the egg-chicken problem by injecting a proxy and thus delaying the resolution of the conversionservice bean until it is really used.
Main problem (that i've encountered) is when you use ConversionServiceFactoryBean for building conversion service that includes converters that use conversion service as well is that you get error because of ConversionServiceFactoryBean.getObject method that provides instance of conversion service is being called prior to ConversionServiceFactoryBean.afterPropertiesSet where that conversion service instance is actually created.
So, to avoid this behavior, you just need to create conversion service prior to ConversionServiceFactoryBean.getObject is called. I've made it in constructor of class that extends ConversionServiceFactoryBean.
Example:
try {
Field serviceField = ConversionServiceFactoryBean.class.getDeclaredField("conversionService");
conversionServiceField.setAccessible(true);
conversionServiceField.set(this, createConversionService());
} catch (NoSuchFieldException | IllegalAccessException fieldAccessError) {
fieldAccessError.printStackTrace();
//or do some log output here, it's up to you
}
Than you can use converters that uses conversion service as well.
Hope it helps.

Categories

Resources