Spring injection tricks - java

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>

Related

Create bean in xml from method

I have a class MyFactory which can create MyClass:
package com.mypackage
#Component
public class MyFactory{
#Bean
public MyClass createMyClass() {
return // magic class creation... ;
}
}
How to use that method to create a bean with xml?
<bean id="myClass" factory-method="com.mypackage.MyFactory.createMyClass"/>
doesn't work...
Remove the #Bean annotation from the factory method:
package com.mypackage;
#Component
public class MyFactory{
public MyClass createMyClass() {
return // magic class creation... ;
}
}
And then in XML:
<bean id="myClass" factory-bean="myFactory" factory-method="createMyClass"/>
If you also want the factory to be configured via XML, then remove the #Component annotation from class MyFactory and create it in XML as well:
<bean id="myFactory" class="com.mypackage.MyFactory"/>
<bean id="myClass" factory-bean="myFactory" factory-method="createMyClass"/>
See the documentation: Instantiation by Using an Instance Factory Method

Spring Test mock one dependency

Suppose I have these two parts of XML Spring config in two distinct files;
//daoContext.xml
<bean id="myDao" class="com.MyDao"/>
//logicContext.xml
<bean id="myLogic" class="com.MyLogic">
<constructor-arg ref="myDao"/><!--or other type of injection--?
</bean>
And there is the test class:
#ContextConfiguration("logicContext.xml")
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
#Autowired
private MyLogic myLogic;
#Test
public void testMyTestable() {
//...
}
}
Now, what I want is to be able to mock MyDao class and inject is somehow into MyLogic which is to be injected in BaseLogicTest so I can use MyLogic with a mocked MyDao. Is this possible using Spring/Spring Test?
The simplest solution is load all your xml. And manually replace dependence in test case.
#ContextConfiguration("logicContext.xml")
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
#Autowired
private MyLogic myLogic;
#Before
public void injectTestDoubles() {
myLogic.setMyDao(...);
}
#DirtiesContext
#Test ...//test methods
}
But this corrupts the application context, so you need #DirtiesContext if you need "real" myDao in other test case sharing the same application context.
The most popular solution (my personal opinion :P ) is using mockito and a test-specific xml.
//daoContext.xml
<bean id="myDao" class="com.MyDao"/>
//logicContext.xml
<bean id="myLogic" class="com.MyLogic">
<constructor-arg ref="myDao"/><!--or other type of injection--?
</bean>
//test-logicContext.xml
<bean id="myDao" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="com.MyDao" />
</bean>
#ContextConfiguration({"logicContext.xml", "test-logicContext.xml"})
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
#Autowired
private MyLogic myLogic;
#Autowired
private MyDao myDao;//retrieve mock so you could define expectations
#Test //test methods
#After public void clearMocks() {
Mockito.reset(myDao);//this is important if you have several test methods
}
}
And this solution works for other mock framework like easyMock.
You can do this by creating a FactoryBean to create the MyDao (or any) mock to be injected into your MyLogic instance.
public class FactoryBeanForMocks<T> implements FactoryBean<T> {
private Class<T> mockClass;
public FactoryBeanForMocks(Class<T> mockClass) {
super();
this.mockClass = mockClass;
}
#Override
public T getObject() throws Exception {
return Mockito.mock(mockClass);
}
#Override
public Class<?> getObjectType() {
return mockClass;
}
#Override
public boolean isSingleton() {
return true;
}
}
Make the factory bean entry into your logicContext.xml so that a mock of MyDao can be injected into MyLogic:
//logicContext.xml
<bean id="myLogic" class="com.MyLogic">
<constructor-arg ref="myDao"/><!--or other type of injection--?
</bean>
<bean id="myDao" class="x.y.z.FactoryBeanForMocks">
<constructor-arg name="mockClass" value="x.y.MyDao"></constructor-arg>
</bean>
And this is your test class:
#ContextConfiguration("logicContext.xml")
public class BaseLogicTest extends AbstractTestNGSpringContextTests {
#Autowired
private MyLogic myLogic;
//You can inject the mock myDao into it so that you can stub/verify method calls on it
#Autowired
private MyDao myDao;
#Test
public void testMyTestable() {
//...
when(myDao.process()).thenReturn("a");//stubbing myDao.process()
assertEquals("a", myLogic.processRequest());// assuming myLogic.processRequest() calls myDao.process()
}
}

How to handle cyclic dependency in spring

For example i have two beans:
class Bean1 {
private SomeService service1;
private SomeService servive2;
private Bean2 bean2;
public void doStuff() {
service1.doActualStuff();
}
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
public Bean2 getBean2() { return this.bean2 }
}
class Bean2 {
private Bean1 bean1;
private SomeService3 service3;
public void init() {
bean1.doStuff();
}
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
}
Now if i try to configure them in spring in the folllowing way:
<bean id="service1" class="SomeService">
...
</bean>
<bean id="bean1" class="Bean1">
<property name="bean2" ref="bean2"/>
<property name="service1" ref="service1"/>
...
</bean>
<bean id="bean2" class="Bean2" init-method="init">
<property name="bean1" ref="bean1"/>
...
</bean>
Init method of bean2 is executed. Bean2 has injected bean1, but bean1 itself is not fully initialized so calling bean1.doStuff() that will call service1.doActualStuff() will return into NPE. Why bean1 is not fully initialized?
Spring caches singleton beans in a not-fully-initialized state for injection into places that would otherwise be an unresolvable circular reference. In your case, the initialization order would be something like this:
Instantiate bean1 (meaning call the constructor only, not init methods)
Add bean1 to the singleton cache to handle circular dependencies
Start injecting bean1's dependencies
Instantiate bean2 to satisfy bean1's dependency
Add bean2 to the singelton cache to handle circular dependencies
Start injecting bean2's dependencies--one of these is the cached bean1 instance, which is still not fully initialized
Finish injecting bean2's dependencies
Call bean2's init method--uhoh! bean1 still isn't initted yet!
Done creating bean2
(If you actually made it this far...) Finish injecting bean1's dependencies
No init method on bean1, but this is where it would be called
Done creating bean1
Consider rethinking your design to untangle the dependencies between bean1 and bean2.
How about if you inject the first bean programatically:
class Bean2 {
private Bean1 bean1;
private SomeService3 service3;
public void init() {
bean1.doStuff();
}
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
//HERE
this.bean1.setBean2(this);
}
}
Remove the first injection from your spring xml:
<bean id="service1" class="SomeService">
...
</bean>
<bean id="bean1" class="Bean1">
<!-- NOT NEEDED ANYMORE <property name="bean2" ref="bean2"/> -->
<property name="service1" ref="service1"/>
...
</bean>
<bean id="bean2" class="Bean2" init-method="init">
<property name="bean1" ref="bean1"/>
...
</bean>

Spring JUnit4 manual-/auto-wiring dilemma

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)

Prototype scope not working

I've created a prototype scoped bean in my application and I'm injecting that to another bean using a setter. But when I'm using the injected bean in my class it is always using the same instance instead of new instance every time.
Here is a snapshot of the code
<bean name="prototypeScope" Class="A" scope="prototype">
</bean>
<bean Class="Consumer">
<property name="a" ref="prototypeScope" />
</bean>
public class Consumer{
privare A a;
public void setA(A a){
this.a = a;
}
public void consume(){
a.doSomething();
}
}
Regards
It is an common mistake related to prototype scoped beans.
A new instance of the prototype scoped bean will be created only when we request a copy of the bean from the application context, not every time we call a method on the instance.
In your case you are injecting the prototype scoped bean to another bean using the setter of the later, so then the second class is created a new instance of the prototype scoped bean will be created. But it will use the same instance as long as it is replace by another instace mannualy by you.
If you want a new instance of the prototype scoped bean during a particular operation like a method call, you have to get a new instance of the bean from the application content.
Ex:
<bean name="prototypeScope" Class="A" scope="prototype">
</bean>
<bean Class="Consumer">
</bean>
Java code:
public class Consumer implements ApplicationContextAware{
privare ApplicationContext context;
public void setApplicationContext(ApplicationContext context){
this.context = context;
}
public void consume(){
A a = context.getBean("prototypeScope", A.class);
a.doSomething();
}
}
In this example when ever the consume method is called a new instance of class A is created.
There are two main ways to deal with the Singleton-Bean-has-Prototype-dependency problem.
One is tight coupling to the applicationContext, as in Ram's answer, the other is Lookup Method Injection.
Basically, you make your bean class abstract and add an abstract method for the dependency, something like this:
public abstract class MyBean{
public abstract MyService lookupService();
}
Then you add a bean definition something like this:
<bean id="myBean" class="fiona.apple.sucks.MyBean">
<!-- sorry, just wanted to insert sucks after Spring's fiona apple example,
didn't think about the connotations :-) -->
<lookup-method name="lookupService"/>
</bean>
Now Spring will create a CGLib subclass of your bean class that will return a new Prototype instance for every time you call myBean.lookupService().
I used such approach once..
First I declared a bean
<bean id="notSingelton" class="com.Foo" singleton="false" />
Then made an interface
public interface FooFactory {
Foo make(String name);
}
wrapped it into ServiceLocatorFactoryBean
<bean id="fooFactory"
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface" value="com.FooFactory" />
</bean>
<bean id="consumer" class="com.Consumer">
<constructor-arg ref="fooFactory" />
</bean>
And consumer class looked something like that:
public class Consumer {
private FooFactory fooFactory;
public Consumer(FooFactory fooFactory) {
this.fooFactory = fooFactory;
}
public void consume(){
Foo foo = fooFactory.make("notSingelton");
foo.doSomething();
}
}

Categories

Resources