constructor injection with value provided by another bean - spring

I want to pass value to constructor(type string) with value provided by another bean.
Class BeanOne () {
BeanOne (String message) {
...
}
}
Below declaration will work
<bean id="beanOne"
class="com.abc.BeanOne">
<constructor-arg index="0" type="java.lang.String"
value="Hi There" /> // instead of value="Hi There", i want to use bean property (value="someBean.message")
</bean>
However I want another bean (say BeanTwo) to set value for message property for BeanOne. I tried nested property as given below but it does not work. Also message property is not visible directly in the class & is referred internally by another constructor & then by the method so i cannot use property injection& have to use only constructor injection

You can use the MethodInvokingFactoryBean to get your string value and then inject that into your bean.
<bean id="message" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject"><ref local="someBean"></property>
<property name="targetMethod"><value>getMessage</value></property>
</bean>
<bean id="beanOne" class="com.abc.BeanOne">
<constructor-arg index="0" type="java.lang.String" ref="message"/>
</bean>

Related

Spring - how to reference another property within the same bean?

I have the following definition in my configuration:
<bean class="com.project.TimerBean">
<property name="delay" value="30000" />
<property name="interval" value="60000" />
<property name="invokeThis" value="com.project.TargetClass" />
<property name="receiver" value="XYZ" />
<property name="args" value="#{interval}" />
</bean>
I would like to set the value of args to the same value as interval (in this case, 60000) without having to hard-code the value. However, the above snippet doesn't seem to work. How should I change this?
# syntax (Spel Expressions) are supposed to work the way you wrote it. You need to replace
#{interval} to #{beanId.interval}.
For example, if the id of the bean you are creating is timerBean, #{timerBean.interval} is supposed to work. You cannot refer to a property directly even if it is a part of the bean definition.
It only works if the property you are referring to is a part of another bean.
<bean id="beanA" class="org.BeanA">
<property name="prop1" value="1000" />
</bean>
<bean id="beanB" class="org.BeanB">
<property name="prop2" value = "#{beanA.prop1}" />
<property name="prop3" value = "#{beanB.prop2}" />
</bean>
In the above example, prop2 gets initialised from prop1 correctly. But prop3 gets initialised to null.
If you look at AbstractAutowireCapableBeanFactory class and method,
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)
you can see that all the property values in a single bean definition are looped over and values are parsed. After all the values have been successfully parsed, only then they are set on the bean instance. In the above beanA and beanB example when prop3's value is getting parsed, spring looks for the value of prop2 on beanB which is not yet set and hence returns null.
AFAIK, there is no way around this except the way suggested by #Alex
PS: I am using spring version 4.1.6.RELEASE
Move interval value "60000" to the property file
yourVariableName = 60000
and change to:
<property name="interval" value="${yourVariableName}" />
<property name="args" value="${yourVariableName}" />

How to set constructor based injection values

<bean id="someBean" class="someClass" >
<constructor-arg index="0" value=""/>
<constructor-arg index="1" value=""/>
</bean>
</beans>
How can I set values from java code?
You can pass the constructor arguments to getBean method as below. But this will work only if the scope of your bean is configured as prototype.
context.getBean("someBean" , new Object[] {"kswaughs", "Stackoverflow user"} );
If you try to call this method for singleton beans, Spring will throw below error.
org.springframework.beans.factory.BeanDefinitionStoreException: Can only specify arguments for the getBean method when referring to a prototype bean definition

Dependency Injection returned results of bean init-method

I have two simple beans. In the first bean it calls a init-method and return string value.
Now I want to this returned string from first bean init-method , inject to my second bean
helloWorldBean3 property newKey. Please advise me on how to implement this requirement.
<bean id="helloWorldBean2" init-method="loadKey"
class="com.java.snippets.enterprise.services.HelloWorld2">
<property name="key" value="${key.supportiveFile}" />
<bean id="helloWorldBean3"
class="com.java.snippets.enterprise.services.HelloWorld">
<property name="newKey" ref="???" />
</bean>
Try using Spring EL like so:
<bean id="helloWorldBean3"
class="com.java.snippets.enterprise.services.HelloWorld">
<property name="newKey" value=""#{helloWorldBean2.loadKey()}"" />
</bean>

Creating a Spring Bean using FactoryMethod with variable arguments from Spring?

How can we create a bean using FactoryMethod with variable arguments.
public class ConnectionFactoryClass {
public static Connection composeConnection(final Property... properties) {
...
}
}
bean.xml
<bean id="Connection"
class="com.example.ConnectionFactoryClass"
factory-method="composeConnection"
scope="singleton">
<constructor-arg ref="Driver"/>
<constructor-arg ref="Pool"/>
</bean>
Spring is giving me an error saying,
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'Connection' defined in file [./beans.xml]: No matching factory method found: factory method 'composeConnection'
Try the following:
<bean id="Connection"
class="com.example.ConnectionFactoryClass"
factory-method="composeConnection"
scope="singleton">
<constructor-arg>
<array>
<bean ref="Driver" />
<bean ref="Pool" />
</array>
</constructor-arg>
</bean>
I think you are having a problem because the JVM turns a var arg params into an Object Array and you need to pass in a single paramater to the constructor which is the array of objects. I have not tried the above xml so I might have typos in it, but something like the above should work.

How do you acess a property of a bean for reading in a spring xml config file?

I want to do something like the following in spring:
<beans>
...
<bean id="bean1" ... />
<bean id="bean2">
<property name="propName" value="bean1.foo" />
...
I would think that this would access the getFoo() method of bean1 and call the setPropName() method of bean2, but this doesn't seem to work.
What I understood:
You have a bean (bean1) with a
property called "foo"
You have another bean (bean2) with a
property named "propName", wich also
has to have the same "foo" that in
bean1.
why not doing this:
<beans>
...
<bean id="foo" class="foopackage.foo"/>
<bean id="bean1" class="foopackage.bean1">
<property name="foo" ref="foo"/>
</bean>
<bean id="bean2" class="foopackage.bean2">
<property name="propName" ref="foo"/>
</bean>
....
</beans>
Doing this, your bean2 is not coupled to bean1 like in your example. You can change bean1 and bean2 without affecting each other.
If you REALLY need to do the injection you proposed, you can use:
<util:property-path id="propName" path="bean1.foo"/>
You need to use PropertyPathFactoryBean:
<bean id="bean2" depends-on="bean1">
<property name="propName">
<bean class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
<property name="targetBeanName" value="bean1"/>
<property name="propertyPath" value="foo"/>
</bean>
</property>
</bean>
I think you have to inject bean1, then get foo manually because of a timing issue. When does the framework resolve the value of the target bean?
You could create a pointer bean and configure that.
class SpringRef {
private String targetProperty;
private Object targetBean;
//getters/setters
public Object getValue() {
//resolve the value of the targetProperty on targetBean.
}
}
Common-BeanUtils should be helpful.

Resources