Spring JUnit4 manual-/auto-wiring dilemma - java

I ran into an issue that can only be explained with my fundamental lack of understanding of Spring's IoC container facilities and context setup, so I would ask for clarification regarding this.
Just for reference, an application I am maintaing has the following stack of technologies:
Java 1.6
Spring 2.5.6
RichFaces 3.3.1-GA UI
Spring framework is used for bean management with Spring JDBC module used for DAO support
Maven is used as build manager
JUnit 4.4 is now introduced as test engine
I am retroactively (sic!) writing JUnit tests for the application and what suprised me is that I wasn't able to inject a bean into a test class by using setter injection without resorting to #Autowire notation.
Let me provide set up an example and accompanying configuration files.
The test class TypeTest is really simple:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest {
#Autowired
private IType type;
#Test
public void testFindAllTypes() {
List<Type> result;
try {
result = type.findAlltTypes();
assertNotNull(result);
} catch (Exception e) {
e.printStackTrace();
fail("Exception caught with " + e.getMessage());
}
}
}
Its context is defined in TestStackOverflowExample-context.xml:
<context:property-placeholder location="classpath:testContext.properties" />
<context:annotation-config />
<tx:annotation-driven />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${db.connection.driver.class}" />
<property name="url" value="${db.connection.url}" />
<property name="username" value="${db.connection.username}" />
<property name="password" value="${db.connection.password}" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="beanDAO" class="com.example.BeanDAOImpl">
<property name="ds" ref="dataSource"></property>
<property name="beanDAOTwo" ref="beanDAOTwo"></property>
</bean>
<bean id="beanDAOTwo" class="com.example.BeanDAOTwoImpl">
<property name="ds" ref="dataSource"></property>
</bean>
<bean id="type" class="com.example.TypeImpl">
<property name="beanDAO" ref="beanDAO"></property>
</bean>
TestContext.properties is in classpath and contains only db-specific data needed for datasource.
This works like a charm but my question is - why doesn't it work when I try to manually wire beans and perform setter injection as in:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest {
private IType type;
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
What am I missing here? What part of configuration is wrong here? When I try to manually inject beans via setters, test fails because this part
result = type.findAlltTypes();
is resolved as null in runtime. I've, of course, consulted the Spring reference manual and tried various combinations of XML configuration; all I could conclude is that Spring was unable to inject beans because it somehow fails to properly dereference Spring Test Context reference but by using #Autowired this happens "automagically" and I really can't see why is that because JavaDoc of both Autowired annotation and its PostProcessor class doesn't mention this.
Also worth adding is the fact that #Autowired is used in application only here. Elsewhere only manual wiring is performed, so this also brings forth question - why is it working there and not here, in my test? What part of DI configuration am I missing? How does #Autowired get reference of Spring Context?
EDIT:
I've also tried this but with same results:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest implements ApplicationContextAware{
private IType type;
private ApplicationContext ctx;
public TypeTest(){
super();
ctx = new FileSystemXmlApplicationContext("/TypeTest-context.xml");
ctx.getBean("type");
}
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
Any other ideas, perhaps?
EDIT2:
I've found a way without resorting to writing own TestContextListener or BeanPostProcessor. It is suprisingly simple and it turns out that I was on the right track with my last edit:
1) Constructor-based context resolving:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest{
private IType type;
private ApplicationContext ctx;
public TypeTest(){
super();
ctx = new FileSystemXmlApplicationContext("/TypeTest-context.xml");
type = ctx.getBean("type");
}
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
2) By implementing ApplicationContextAware interface:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class TypeTest implements ApplicationContextAware{
private IType type;
private ApplicationContext ctx;
public IType getType () {
return type;
}
public void setType(IType type) {
this.type= type;
}
#Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.ctx = ctx;
type = (Type) ctx.getBean("type");
}
#Test
public void testFindAllTypes(){
//snip, snip...
}
}
Both of these approaches properly instanced beans.

If you take a look at the source of org.springframework.test.context.support.DependencyInjectionTestExecutionListener, you will see the following method (formatted and commented for clarity):
protected void injectDependencies(final TestContext testContext)
throws Exception {
Object bean = testContext.getTestInstance();
AutowireCapableBeanFactory beanFactory = testContext.getApplicationContext()
.getAutowireCapableBeanFactory();
beanFactory.autowireBeanProperties(bean,
AutowireCapableBeanFactory.AUTOWIRE_NO,
// no autowiring!!!!!!!!
false
);
beanFactory.initializeBean(bean, testContext.getTestClass().getName());
// but here, bean post processors are run
testContext.removeAttribute(REINJECT_DEPENDENCIES_ATTRIBUTE);
}
So the test object is a bean without auto-wiring. However, #AutoWired, #Resource etc, don't use the autowiring mechanism, they use BeanPostProcessor. And so the dependencies are injected if and only if the annotations are used (or if you register some other BeanPostProcessor that does it).
(The above code is from Spring 3.0.x, but I bet it was the same in 2.5.x)

Related

Spring injection tricks

I have: injecting MyClass and String objects into Utils at constructor.
Questions:
How does it works when in Utils bean definition (look at beans definition section) I mentioned only the second argument of Utils constructor?
How to pass MyClass mock into Utils object in unit tests? I mean how to redefine the bean definition?
Utils.java
public class Utils {
#Inject
public Utils(MyClass obj, String val) {
this.obj = obj;
this.val = val;
}
Beans definition:
<bean class="com.mypack.MyClass"/>
<bean id="utils" class="com.mypack.Utils">
<constructor-arg value="bucket" />
</bean>
You can define define another(test) context for the unit tests:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "my-test-context.xml",
"some-other-context.xml" })
public class SkipSampleFunctionalTests {
#Autowired
private SomeBean bean;
...
}
If you want to override only one bean, you can import your main(core) context int the test context and change only the desired bean:
<import resource="main-context.xml"/>
<bean id="x" class="com.asd.MyClass">
<property name="y" ref="y"/>
</bean>

Retrieving property/value as string from Spring bean

I have the following in my context.xml:
<bean id="myBean" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>file:${specific.dir}/file1.properties</value>
<value>file:${specific.dir}/file2.properties</value>
<value>file:${specific.dir}/file3.properties</value>
<value>file:${specific.dir}/file4.properties</value>
</list>
</property>
</bean>
I am retrieving this bean in a POJO through a static spring application context, and going through the debugger this does seem to work.
Is there anyway for me to retrieve the four values in the list, and the property name in this POJO?
my staticSpringApplicationContext is as follows :
public class StaticSpringApplicationContext implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
public void setApplicationContext(ApplicationContext context) throws BeansException {
CONTEXT = context;
}
public static Object getBean(String beanName) {
return CONTEXT.getBean(beanName);
}
}
and following this in my POJO I have:
StaticSpringApplicationContext.getBean("myBean");
Any help or guidance is greatly appreciated. I have had more trouble with Spring than I care to admit.
You can use spring #Value annotation, smth like this:
#Component
public MyClass {
#Value("${some.prop.name1}")
private String myProp1;
}
file1.properties:
some.prop.name1=value1
I hope it will be helpful. Good luck.
Whether you can do this will depend on the bean definition. It must have a setLocations() method (or be correctly annotated) via which Spring will inject the values.
You would retrieve the values using a getter method on the bean if one exists. If not you will need to modify the bean.

How to set MDB programmatic and dynamically

I am using Spring3.1 on standalone env.
I set topic with jms templates this way:
<bean id="mm1sessionsTopicSendingTemplate" class="org.springframework.jndi.JndiObjectFactoryBean"
depends-on="jmsServerManagerImpl">
<property name="jndiName">
<value>/topic/mm1sessionsTopic</value>
</property>
</bean>
For this topic I set MDB with DefaultMessageListenerContainer this way:
<bean id="mm1sessionDispatcherListener"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="pubSubDomain" value="true" />
<property name="concurrentConsumers" value="1" />
<property name="destination" ref="mm1sessionsTopicSendingTemplate" />
<property name="messageListener" ref="mm1SessionMDB" />
<property name="sessionAcknowledgeModeName" value="AUTO_ACKNOWLEDGE" />
</bean>
In this way I must set mm1SessionMDB in advanced via xml:
<bean id="mm1SessionMDB" class="com.mdb.SessionMDB">
<property name="feedPropertiesDTO" ref="feedListenerMarketMaker1Properties" />
</bean>
But I need my application to create the MDB instances programmaticly.
I mean i want to create the mdb's via the code since each MDB will have different validation values for the messages that it will retrieve from the topic(via the feedPropertiesDTO)
basically I will have pool of MDB's with the same logic but each one will have different properties. the creation time of the MDB'S must be on runtime.
is that possible?
thanks,
ray.
I think you can use factory method for instantating your MDB bean and use method
Object getBean(String name, Object... args) throws BeansException;
of the ApplicationContext in your code to instantiate bean frogramatically.
As I know this method allows you to path argument to factory method.
Here what is said in java doc for this method:
Return an instance, which may be shared or independent, of the specified bean.
Allows for specifying explicit constructor arguments / factory method
arguments, overriding the specified default arguments (if any) in the
bean definition.
I have never used this approach but I think it colud work for your case.
EDIT.
Here is an example that demonstrates about what I'm talkin (It is very simple but I don't have enough time to write more complicated).
Suppose that have interface and two it's implementations:
public interface StringMakerInterface {
// Just return simple String depending on concrete implementation.
String returnDummyString();
}
public class StringMakerImpl1 implements StringMakerInterface {
public String returnDummyString() {
return "test bean impl 1";
}
}
public class StringMakerImpl2 implements StringMakerInterface{
public String returnDummyString() {
return "test bean impl 2";
}
}
And we have one class that uses concrete implementation of this interface and to which we should dinamically inject conctrete implementation:
public class StringPrinter {
private StringMakerInterface stringMaker;
public StringMakerInterface getStringMaker() {
return stringMaker;
}
public void setStringMaker(StringMakerInterface stringMaker) {
this.stringMaker = stringMaker;
}
public StringPrinter() {
}
// Just print dummy string, returned by implementation
public void printString() {
System.out.println(stringMaker.returnDummyString());
}
}
Here is configuration class for my example:
#Configuration
public class TestFactoryMethodConfig {
#Bean(name = "stringMaker1")
public StringMakerImpl1 stringMaker1() {
return new StringMakerImpl1();
}
#Bean(name = "stringMaker2")
public StringMakerImpl2 stringMaker2() {
return new StringMakerImpl2();
}
#Bean(name = "stringPrinter")
#Scope(value = "prototype")
public StringPrinter stringPrinter(#Qualifier("stringMaker1") StringMakerInterface stringMaker) {
StringPrinter instance = new StringPrinter();
instance.setStringMaker(stringMaker);
return instance;
}
}
And here is a test case that demonstrates dinamically injection at the runtime:
#RunWith(value = SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={TestFactoryMethodConfig.class})
public class TestFactoryMethod {
#Autowired
private ApplicationContext applicationContext;
#Resource(name = "stringMaker1")
private StringMakerInterface stringMaker1;
#Resource(name = "stringMaker2")
private StringMakerInterface stringMaker2;
#Test
public void testFactoryMethodUsage() {
StringPrinter stringPrinter1 = (StringPrinter) applicationContext.getBean("stringPrinter", stringMaker1);
StringPrinter stringPrinter2 = (StringPrinter) applicationContext.getBean("stringPrinter", stringMaker2);
stringPrinter1.printString();
stringPrinter2.printString();
}
}

How to collect and inject all beans of a given type in Spring XML configuration

One of the strongest accents of the Spring framework is the Dependency Injection concept. I understand one of the advices behind that is to separate general high-level mechanism from low-level details (as announced by Dependency Inversion Principle).
Technically, that boils down to having a bean implementation to know as little as possible about a bean being injected as a dependency, e.g.
public class PrintOutBean {
private LogicBean logicBean;
public void action() {
System.out.println(logicBean.humanReadableDetails());
}
//...
}
<bean class="PrintOutBean">
<property name="loginBean" ref="ShoppingCartBean"/>
</bean>
But what if I wanted to a have a high-level mechanism operating on multiple dependent beans?
public class MenuManagementBean {
private Collection<Option> options;
public void printOut() {
for (Option option:options) {
// do something for option
}
//...
}
}
I know one solution would be to use #Autowired annotation in the singleton bean, that is...
#Autowired
private Collection<Option> options;
But doesn't it violate the separation principle? Why do I have to specify what dependents to take in the very same place I use them (i.e. MenuManagementBean class in my example)?
Is there a way to inject collections of beans in the XML configuration like this (without any annotation in the MMB class)?
<bean class="MenuManagementBean">
<property name="options">
<xxx:autowire by-type="MyOptionImpl"/>
</property>
</bean>
Old question and in Spring 3.1 it is possible:
public class PluginPrototypeTest extends ASpringWebTest {
#Autowired
Collection<IDummyRepo> repos;
#Test
public void cacheTest() {
assertNotNull(repos);
assertEquals(2, repos.size());
for(IDummyRepo r: repos){
System.out.println(r.getName());
}
}
}
#Repository
public class DummyRepo implements IDummyRepo {
#Override
public String getName(){
return "DummyRepo";
}
}
#Repository
public class DummyRepo2 implements IDummyRepo {
#Override
public String getName(){
return "DummyRepo2";
}
}
There's no out-of-the-box facility to do this, no. However, if you want a way of collecting all beans of a given type into a collection, without using an #Autowired list, then it's easy to write a custom FactoryBean to do it for you:
public class BeanListFactoryBean<T> extends AbstractFactoryBean<Collection<T>> {
private Class<T> beanType;
private #Autowired ListableBeanFactory beanFactory;
#Required
public void setBeanType(Class<T> beanType) {
this.beanType = beanType;
}
#Override
protected Collection<T> createInstance() throws Exception {
return beanFactory.getBeansOfType(beanType).values();
}
#Override
public Class<?> getObjectType() {
return Collection.class;
}
}
and then
<bean class="MenuManagementBean">
<property name="options">
<bean class="BeanListFactoryBean">
<property name="beanType" class="MyOptionImpl.class"/>
</bean>
</property>
</bean>
However, this all seems like a lot of effort to avoid putting #Autowired in your original class. It's not much of a violation of SoC, if it is at all - there's no compiltime dependency, and no knowledge of where the options are coming from.
Alternative to #Autowired, using a context file: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-autowire
So you'd have:
<bean class="MenuManagementBean" autowire="byType" />
Other properties can be specified, as normal, and that would override the autowiring only for those properties.

Intentionally setting a Spring bean to null

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

Categories

Resources