Spring Dependency Injection - Using instantiated object - java

Within Spring DI, can you "use" your bean within it's own definition? For example, if I have a bean called getTest1 with an inner bean declared within it, can I pass getTest1 to the constructor of that inner bean?
I'm wondering if I can implement a decorator patter-like solution using Spring DI for a work project but don't have much time to play around with it. Thanks!

Haven't tested it but I think you need something like this
<bean id="a" class="com.AClass">
<property name="aProperty" value="y">
<property name="bean2">
<bean class="com.BClass">
<constructor-arg ref="a"/>
</bean>
</property>
</bean>
check here for more help on referencing one bean inside another

The decorator pattern can be expressed in the following way using XML:
<bean id="decorated" class="Outer">
<constructor-arg>
<bean class="Middle">
<constructor-arg>
<bean class="Inner"/>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
This is equivalent to the following Java code:
Common decorated = new Outer(new Middle(new Inner()));
Consider Using #Configuration approach to make this more Java-friendly:
#Bean
public Common outer() {
return new Outer(middle());
}
#Bean
public Common middle() {
return new Middle(inner());
}
#Bean
public Common inner() {
return new Inner();
}

Related

Creating 2 beans of the same class with different constructor-args and using autowiring

Hi I working on a project, in which I need to create 2 instances of bean of same class but different constructor-args. Right now have functionality only for "production environment", so I have xml file like:
<context:component-scan base-package="com.xxx.yyy" />
<bean id="id1" class="someCompanySpecificURLForTheClass" scope="singleton"/>
<bean name="name1" factory-bean="id1" factory-method="createFullClient">
<constructor-arg index="0">
<ref bean="someJSONBean"/>
</constructor-arg>
<constructor-arg value="productionEnv" index="1"/>
</bean>
</beans>
Now I need to include functionality for testing environment also. So I changed the xml file to:
<context:component-scan base-package="com.xxx.yyy" />
<context:component-scan base-package="com.zzz.yyy" />
<bean id="id1" class="someCompanySpecificURLForTheClass" scope="prototype"/>
<bean name="name1" factory-bean="id1" factory-method="createFullClient">
<constructor-arg index="0">
<ref bean="someJSONBean"/>
</constructor-arg>
<constructor-arg value="${value.name}" index="1"/>
</bean>
In the 2 Java files, I use #Autowired annotations on the method of setClients() and on creating object of someJSONBean.
But I am receiving errors:
BeanCreationException: could not autowire method: public void com.zzz.yyy.sometthing.setClients(someCompanySpecificURLForTheClass) throws IllegalArgumentException and UnsupportedEncodingException.
nested exception is defined: NoSuchBeanDefinitionException: no unique bean of type(someCompanySpecificURLForTheClass) is defined: expected single matching bean, found 2(name1, name2).
I am new to spring framework. can anyone tell whats happening wrong, is the autowiring that i am doing wrong? how can i solve this?
Edit:
Here someCompanySpecificURLForTheClass is the same class and beans(name1 and name2) use this bean as a factory bean with different constructor-arguments.
I am using spring 3.1.
After searching a lot, I think I can use placeholder for the constructor-args value right?
The above is the edited xml file being used.
Updated code in the Java classes:
1.
#ConfigAdapter
class class1{
#Autowired
private someJSONBean obj;
#Autowired
#Value("${value.name:thisismyvalue}")
public void setClients(){}
}
#ConfigAdapter
class class2{
#Autowired
private someJSONBean obj;
#Autowired
#Value("${value.name:thisismyvalue}")
public void setClients(){}
}
But I get the following error:
ConversionNotSupportedException: failed to convert 'java.lang.string' to 'someCompanySpecificURLForTheClass'.
nested execption is IllegalStateException
Cannot convert 'java.lang.string' to 'someCompanySpecificURLForTheClass' of required type: no matching editors or conversion strategy found.
Am I specifying the annotation value wrongly?
Why is this happening?
You have to use #Qualifier Annotation along withe #Autowired. Since your are creating two beans of the same class, spring does not know which one to autowire. You can give a hint using #Qualifer("id/name") annotation.
#Autowired
#Qualifier("name1")
//yourProperty
or
#Autowired
#Qualifier("name2")
//yourProperty
Check out this link .
If you want to inject both the beans into your class, then your have two create two different properties, each pointing to a different instance.
#Autowired
#Qualifer("name1")
//property1
#Autowired
#Qualifer("name2")
//property2

Spring Di via setter dynamic constructor parameters

I'm beginner with spring framework, and I'm following this tutorial to applicate DI via setter. All works fine, but I'd like add to my class CsvOutputGenerator a constructor with one dynamic parameter, passed on the fly while I getting bean from Application context.
How can I do that?
I've already change my spring configuration in this way:
...
<bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator">
<constructor-arg type="java.lang.String" value="Test"/>
</bean>
...
but in this way is static value for my constructor.
You can pass it via system property for example
<constructor-arg lazy-init="true" type="java.lang.String" value="#{ systemProperties['some.key']}"/>
Try something else, even though Spring isn't made to be used like this (note the "prototype" scope):
<bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator" scope="prototype" />
And then in your code you can do something like this:
CsvOutputGenerator myBean = (CsvOutputGenerator) context.getBean("CsvOutputGenerator", "testing testing");
This is the method in the API that I used above.
The below content is based on the above question and comments.
Say u have a class URLRepo with attribute String url. url is initialized to value.
Then you can do something like this, to wire your CsvOutputGenerator
public class URLRepo {
private String url = "your value";
getters and setters
}
<bean id="urlRepo" class="com.*.*.MyURLRepo"/>
<bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator">
<constructor-arg type="java.lang.String" value="urlRepo.url"/>
</bean>
hope this is what you are looking for.

Nesting abstract beans in Spring and init-method does not seem to work

I have the following construct Spring XML (Spring 3.1):
<bean id="taskRunner" abstract="true" init-method="startThreads"
class="my.class.TaskRunner" />
...
<bean id="taskRunnerA" parent="taskRunner">
<constructor-arg name="foo">...</constructor-arg>
<property name="bar">...</property>
</bean>
And I am trying to separate out the init method into a higher level abstract bean:
<bean id="taskRunnerLauncher" abstract="true" init-method="startThreads" />
<bean id="taskRunner" abstract="true" depends-on="taskRunnerLauncher"
class="my.class.TaskRunner" />
...
<bean id="taskRunnerA" parent="taskRunner">
<constructor-arg name="foo">...</constructor-arg>
<property name="bar">...</property>
</bean>
Somehow this does not work, i.e. startThreads() is never invoked in the second case. Does anybody know why? Does Spring support nested abstract beans?
My idea for doing this is so I can override "taskRunnerLauncher" in unit tests and set it to "mock" or "java.lang.Object" and suppress startThreads() call (which starts new thread and making it a pain to test).
Does anybody know why?
The taskRunnerLauncher bean is set to be abstract. This means it will only act as a template for other beans. Spring will not actually create a bean for it. Therefore there won't be any invocation of startThreads because there is nothing to invoke it on.
Found the problem. I mistakenly used depends-on instead of parent attribute on taskRunner bean.

Scope of Spring beans enforcement

I have a scenario for example.
<bean id="xyzService" class="XyzServiceImpl" scope="prototype">
<property name="aDependency" ref="aDependency" />
<property name="bDependency" ref="bDependency" />
</bean>
<bean id="useService" class="UseServiceImpl">
<property name="xyzService" ref="xyzService"/>
</bean>
Java Class :
public class XyzServiceImpl implements XyzService{
private ADependency aDependency= null;
private BDependency bDependency= null;
// getters and setters...
}
public class UseServiceImpl implements UseService {
private XyzService xyzService= null;
// getters and setters...
xyzService.doSomething();
}
Now every time inside the UseServiceImpl I expect a new Instance of xyzService, but i always return the same singleton instance. Also there is a scenario that the aDependency and bDependency may internally have again some more references to other beans.
Now I have a question like how do I get an new Instance of xyzService. Am I doing something wrong?
By default scope of spring bean is singleton , You need to mark the scope prototype to instruct spring
<bean id="beanId" class="some.class.Name" scope="prototype"/>
Spring will create new instance on each request of Bean
See
bean scopes
I could easily find the solution by implementing the ApplicationContextAware Interface which has the getter and setter method for context. From the context I can say getBean and get the new Instance
public class UseServiceImpl implements UseService,ApplicationContextAware {
private ApplicationContext context;
XyzService xyzService= context.getBean(XyzServiceImpl.class);
// getter and setter for applicationContext
private XyzService xyzService= null;
// getters and setters...
xyzService.doSomething();
}
If you have the following:
<bean id="xyzService" class="XyzServiceImpl" scope="prototype">
<property name="aDependency" ref="aDependency" />
<property name="bDependency" ref="bDependency" />
</bean>
<bean id="useService1" class="UseServiceImpl">
<property name="xyzService" ref="xyzService"/>
</bean>
<bean id="useService2" class="UseServiceImpl">
<property name="xyzService" ref="xyzService"/>
</bean>
Then you should be able to verify that the xyzService property for useService1 and useService2 do contain different instances of xyzService. That's the effect of declaring xyzService to be scoped as a prototype. If you really want new instances of the xyzService bean to be available during the lifetime of the useService bean, I think you'll need a different approach - take a look at the documentation for Method injection.
In your example, every time you request spring container an instance of userService, it will return the singleton instance and injecting a new instance of xyzService.
However, when spring creates a new instance of xyzService, it will use the singleton instance of aDependency and bDependency unless otherwise they are also defined as prototype.

problem in Spring session scope bean with AOP

I want to inject currentUser instance in HomeController class. so for every request, HomeController will have currentUser object.
My configuration:
<bean id="homeController" class="com.xxxxx.actions.HomeController">
<property name="serviceExecutor" ref="serviceExecutorApi"/>
<property name="currentUser" ref="currentUser"/>
</bean>
<bean id="userProviderFactoryBean" class="com.xxxxx.UserProvider">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="currentUser" factory-bean="userProviderFactoryBean" scope="session">
<aop:scoped-proxy/>
</bean>
But I am getting following error.
Caused by: java.lang.IllegalStateException: Cannot create scoped proxy for bean 'scopedTarget.currentUser': Target type could not be determined at the time of proxy creation.
at org.springframework.aop.scope.ScopedProxyFactoryBean.setBeanFactory(ScopedProxyFactoryBean.java:94)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1350)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
What is the problem? and Is there any better/simple alternative?
Cheers.
With scoped-proxies, Spring still needs to know the type of the bean when the context is initialized, and in this case it's failing to do so. You need to try and give it more information.
I notice that you're only specifying factory-bean in your definition of currentUser, with no factory-method specified. I'm actually rather surprised that that's a valid definition, since the two are normally used together. So try adding the factory-method attribute to currentUser, which specifies the method on userProviderFactoryBean which creates the user bean. That method needs to have a return type of your User class, which Spring will use to infer the type of currentUser.
Edit: OK, after your comment below, it seems you've misunderstood how to use factory beans in Spring. When you have a bean of type FactoryBean, you don't need to use the factory-bean attribute as well. So instead of this:
<bean id="userProviderFactoryBean" class="com.xxxxx.UserProvider">
<property name="userDao" ref="userDao"/>
</bean>
<bean id="currentUser" factory-bean="userProviderFactoryBean" scope="session">
<aop:scoped-proxy/>
</bean>
You just need this:
<bean id="currentUser" class="com.xxxxx.UserProvider" scope="session">
<aop:scoped-proxy/>
<property name="userDao" ref="userDao"/>
</bean>
Here, UserProvider is a FactoryBean, and Spring knows how to handle that. The end result will be that the currentUser bean will be whatever UserProvider generates, rather than an instance of UserProvider itself.
The factory-bean attribute is used when the factory is not a FactoryBean implementation, but just a POJO, and it allows you to tell Spring explicitly how to use the factory. But because you're using FactoryBean, there's no need for this attribute.

Categories

Resources