Spring configuration pass property to referenced bean - java

I have the following setup:
<bean id="b1" class="SomeClass">
<property name="foo" ref="foo1"/>
</bean>
<bean id="b2" class="SomeClass">
<property name="foo" ref="foo2"/>
</bean>
<bean id="foo1" class="FooClass">
<constructor-arg index="0"><ref bean="dataSource1"/></constructor-arg>
...other constructor args
</bean>
<bean id="foo2" class="FooClass">
<constructor-arg index="0"><ref bean="dataSource2"/></constructor-arg>
...other constructor args
</bean>
Is there a way I can avoid duplicating the FooClass? What I want to do in bean b1 and b2 is add the reference to FooClass but specify the data source all other constructor arguments are the same.
Thanks
Jim

If you want some member of your class to be dynamically initialized\populated on every call to the corresponding getter, you can try the Lookup Method Injection. Read pp. 3.3.4.1 here.
So even if the class that contains the dynamic member was created in scope=singletone (the default for spring bean container) every time you will acces the field that has a lookup method assigned, you will get an appropriate object according to the business logic implemented inside the lookup method.
Also, I found a good example in Spring documentation - I think it is very clear. Take a look at "3.4.6.1 Lookup method injection"

what you are doing here is , autowiring class with constructure, as aviad said , you can use setter and getter method for your datasource injections
<bean id="foo" class="FooClass">
<constructor-arg index="0">datasource</constructor-arg>
...other constructor args
</bean>
<bean>your datasource bean1</bean>
<bean>your datasource bean2</bean>
and in your implementation you can set your data source as below
#Autowire
private FooClass foo;
foo.setDataSource(datasourcebean1);
you fooClass
public void FooClass(Datasource datasource){
private Datasource datasource;
public void setDatSource(Datasource datasource);
public Datasource getDataSource();
}
EDIT- as per spring documentation, you can pass constructor argument if that doesnt change in terms of its value. But in your case for FooClass you want to pass different datasource at different occasion (hope i get it correctly), so in this case you need to just pass datasouce instance either datasource 1 or datasource 2 during spring initialization, as spring will expect constructor argument while initialing FooClass. later during runtime pass different datasource and set your datasource using setter method.
bean spring config
<bean id="foo" class="FooClass">
<constructor-arg index="0" ref="datasource1"></constructor-arg>
...other constructor args
</bean>
public class FooClass(){
// on spring initialization, it will inject datasource1
public void FooClass(DataSource dataSource){
}
have your setter and getter method for datasource
}
where in your calling service
public class dataBaseInvoke(){
public Datasource datasource2
public FooClass fooClass;
inside method{
fooClass.setDatasource(datasource2);
fooClass.addFoo();
}
}

Considering your implementation, you may want to go for the Bean Definition Inheritance.
From Spring documentation:
A bean definition can contain a lot of configuration information,
including constructor arguments, property values, and
container-specific information such as initialization method, static
factory method name, and so on. A child bean definition inherits
configuration data from a parent definition. The child definition can
override some values, or add others, as needed. Using parent and child
bean definitions can save a lot of typing. Effectively, this is a form
of templating.
Basically what it says is that you could have a kind of "Template for your Bean Definition" mark it as abstract and use it in other compatible beans as parent to inherit those configurations.
This sample was taken from spring documentation:
<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
So at this point this bean isn't instantiated and will be used for bean definition inheritance purpose only.
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>
Here you could see that org.springframework.beans.DerivedTestBean is used to instantiate the bean but it will use all definition of the parent, plus, it will override the property name. The class doesn't needs to be specified on the parent, but if specified on the parent (inheritedTestBean) and not on the child (inheritsWithDifferentClass) the parent class will be used to instantiate the child. Not everything is inherited as we can see here:
A child bean definition inherits constructor argument values, property
values, and method overrides from the parent, with the option to add
new values. Any initialization method, destroy method, and/or static
factory method settings that you specify will override the
corresponding parent settings.
The remaining settings are always taken from the child definition:
depends on, autowire mode, dependency check, singleton, scope, lazy
init.
Here is a sample using your classes:
<!-- the way you are already using it -->
<bean id="b1" class="SomeClass">
<property name="foo" ref="foo1"/>
</bean>
<!-- if you use it just once, you could declare it inside the bean that uses it -->
<bean id="b2" class="SomeClass">
<property name="foo">
<bean id="foo1" class="FooClass" parent="foo">
<constructor-arg index="0"><ref bean="dataSource1"/></constructor-arg>
</bean>
</property>
</bean>
<!-- here no class definition, only the default configuration -->
<bean id="foo" abstract="true">
<!-- constructor arg 0 is defined only on child beans -->
<constructor-arg index="1" value="whatever1" />
<constructor-arg index="2" value="whatever2" />
<constructor-arg index="3" value="whatever3" />
<constructor-arg index="4" value="whatever4" />
</bean>
<bean id="foo2" class="FooClass">
<constructor-arg index="0"><ref bean="dataSource2"/></constructor-arg>
</bean>

Use abstract bean
<bean id="foo" class="FooClass">
// Set all properties except datasoure
<property name="..." />
</bean>
<bean id="foo1" parent="foo">
<property name="datasource" ref="ds1" />
</bean>
<bean id="foo2" parent="foo">
<property name="datasource" ref="ds2" />
</bean>
Of course you have to use empty contructor instantiation and expose FooClass properties with accessors. If you don't need foo1 and foo2 in other places go for inner beans.

Related

Why does parameter injection in Bean A break property resolution Bean B? (Both of type of type PropertyPlaceholderConfigurer)

I have two PropertyPlaceholderConfigurer beans in my project.
Bean A: (Defined as XML)
<bean id="propertyConfigurer" class="org.jasypt.spring3.properties.EncryptablePropertyPlaceholderConfigurer">
<constructor-arg ref="configurationEncryptor" />
<property name="order" value="0" />
<property name="locations">
<list>
<value>classpath:/app-dev.properties</value>
<value>classpath:/common-dev.properties</value>
</list>
</property>
</bean>
Bean B: (Defined as Java Config)
#Bean(name = "customPropertiesUtil")
public static CustomPropertiesUtil customPropertiesUtil(StandardPBEStringEncryptor configurationEncryptor) {
CustomPropertiesUtil customPropertiesUtil = new CustomPropertiesUtil ();
customPropertiesUtil.setSystemPropertiesModeName("SYSTEM_PROPERTIES_MODE_OVERRIDE");
customPropertiesUtil.setLocation(new ClassPathResource("mail-dev.properties"));
customPropertiesUtil.setOrder(1);
customPropertiesUtil.setIgnoreUnresolvablePlaceholders(false);
customPropertiesUtil.setStandardPBEStringEncryptor(configurationEncryptor);
return customPropertiesUtil;
}
The bean configurationEncryptor is defined in XML as:
<bean id="configurationEncryptor" class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor">
<property name="config" ref="environmentVariablesConfiguration" />
</bean>
Bean B is created in a #Configuration class.
The odd thing is, if I remove the parameter injection shown in Bean B, everything works as expected. However, I need the encryptor to resolve some encrypted properties and the only way it is NOT NULL is to inject it using parameter injection. (see Why is an #Autowired field within a #Configuration class null?)
My question is how come, having a bean injected into the #Bean (Bean B) method cause Bean A to fail?

Spring - List of bean references from properties files?

I have this:
<bean class="...">
<constructor-arg name="beans">
<list>
<ref bean="beanA" />
<ref bean="beanB" />
</list>
</constructor-arg>
</bean>
I want to configure the list via a properties file, something like:
Properties file:
beans=beanA,beanB
XML file:
<bean class="...">
<constructor-arg name="beans">
<list refs="${beans}" />
</constructor-arg>
</bean>
Is something like this possible with Spring?
Edit: Just to give some context in case there are alternative solutions to the problem, this is for an application that has to write to multiple databases, and I want to configure which databases are enabled in the properties file, so that I don't have to maintain separate XML files for dev/production.
My first though is to use a FactoryBean where you inject the property ${beans} and the application context. Then in the factory bean, you loop on on every bean id/name and you call the context to retrieve the bean by name/id. Then you constructs your bean with your constructor and the list you have just built.
use annotation i.e.
#Value("${beans}")
private Class<? extends YourBean>String[] beanList;

How to inject child dependency using byType autowiring?

I have two child classes(PermanentEmployee and ContractEmployee) of Employee class.
I want spring to inject the dependencies under TextEditor1 by type . Along with this i want to inject the PermanentEmployee depndency under TextEditor1.
similarily want to inject the contractEmployee dependency under TextEditor2. Rest should be injected
automatically by type?
<bean id="textEditor1" class="com.TextEditor" autowire="byType">
<property name="employee" ref="permanentEmployee" />
</bean>
<bean id="textEditor2" class="com.TextEditor" autowire="byType">
<property name="employee" ref="contractEmployee" />
</bean>
<bean id="permanentEmployee" class="com.PermanentEmployee" >
</bean>
<bean id="contractEmployee" class="com.ContractEmployee">
</bean>
But i get the error Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: saying two match are found ?
Update :- i also tried below but it didn't work either
<bean id="textEditor1" class="com.TextEditor" autowire="byType">
<qualifier type="permanentEmployee"/>
</bean>
I think that's because those two com.PermanentEmployee and com.ContractEmployee are implementing another interface like com.Employee?
That way, Spring will recognize those same type and can't choose which bean Spring have to auto-wire into the bean.
So you might need to add those byName, not byType in this case.
If you change those injection with #Autowired annotation or #Resource annotation, you can use #Qualifier( for Autowired ) or name property of Resource annotation to specify bean name.

Bean #Autowired by default in spring

I'm working with SpringFramework and Java. I use Spring xml files to define the flow of the architecture and also the beans that will be used in the Java part.
I have two beans of the same class in my xml file, but they have different arguments for the constructor:
<bean id="beanA" class="Class" >
<constructor-arg><value>valueA1</value></constructor-arg>
<constructor-arg><value>ValueA2</value></constructor-arg>
</bean>
<bean id="beanB" class="Class" >
<constructor-arg><value>valueB1</value></constructor-arg>
<constructor-arg><value>valueB2</value></constructor-arg>-->
</bean>
Is there a way to set one of the beans as default in order to #Autowired it from Java? And, when I want to use the non default bean, apply the #Qulifier("beanName") annotation.
try primary attribute, eg
<bean id="b1" class="test.B" />
<bean id="b2" class="test.B" />
<bean id="b3" class="test.B" primary="true" />
this guarantees that b3 bean will be injected here
public class Test {
#Autowired
B b;
...
Finally I used a the next thing: I have a setter (setClassValue(Class classValue)) in the java code for the class I want to use. Then, I set the property autowire-candidate to false in the bean that it's not going to be the default one:
<bean id="beanA" class="Class" autowire-candidate="false">
<constructor-arg><value>valueA1</value></constructor-arg>
<constructor-arg><value>valueA2</value></constructor-arg>
</bean>
<bean id="beanB" class="Class" >
<constructor-arg><value>valueB1</value></constructor-arg>
<constructor-arg><value>valueB2</value></constructor-arg>
</bean>
Then, in the xml file where I'm defining the bean of the class that is going to #Autowired the Class, I use the java setClassValue(Class classValue) method on this way:
<bean id="classThatAutowire" class="ClassThatAutowire" >
<property name="classValue" ref="beanA" />
</bean>
In the Java code yo will have #Autowired the beanB and then, set the beanA. It's not the best practice, but it works.

constructor-arg and property together in bean definition

<bean id="cObject" scope="request" class="x.y.z.CClass"/>
<bean id="bObject" scope="request" class="x.y.z.BClass"/>
<bean id="aObject" scope="request" class="x.y.z.AClass">
<constructor-arg ref="bObject" />
<property name="cRef" ref="cObject" />
</bean>
aObject.cRef is not getting set for some reason. Note that constructor-arg and property are used in the same definition. I have not seen an example / post with similar feature.
On same sources my colleague discover:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'service.MenuService#0'
defined in class path resource [spring-beans/integrator.xml]:
Could not resolve matching constructor (hint: specify index/type/name
arguments for simple parameters to avoid type ambiguities)
while my host, test and production servers have no such error.
With:
<bean class="service.MenuService">
<constructor-arg index="0" type="java.lang.String" value="#{user}"/>
<constructor-arg index="1" type="java.lang.String" value="#{password}"/>
<constructor-arg index="2" type="java.lang.String" value="#{uri}"/>
<property name="system" value="OPRT"/>
<property name="client" value="OPRT"/>
</bean>
while there are only one 3-args constructor in bean.
The reason to use constructor - it perform some additional actions on non-Spring library by invoking init() method. And set args as fields.
So I change spring-beans.xml to:
<bean class="service.MenuService" init-method="init">
<property name="login" value="#{user}"/>
<property name="password" value="#{password}"/>
<property name="httpsUrl" value="#{uri}"/>
<property name="system" value="OPRT" />
<property name="client" value="OPRT" />
</bean>
Take attention to init-method= part.
UPDATE After all I wrote simple XML config and step through Spring source code in debugger. Seems that with Spring 3.x it's possible to combine constructor-arg and property in XML bean definition (check doCreateBean in AbstractAutowireCapableBeanFactory.java, which call createBeanInstance and populateBean next).
See also https://softwareengineering.stackexchange.com/questions/149378/both-constructor-and-setter-injection-together-in-spring/
Mixing <constructor-arg> and <property> is generally a bad idea.
There is only one good reason for using <constructor-arg>, and that is to create immutable objects.
However, your objects are not immutable if you can set their properties. Don't use <constructor-arg>. Redesign the class, use an initializer method annotated with #PostConstruct if you need to apply some logic at bean creation time.

Categories