I am trying to set up HostConfiguration bean. One of the property it has is called proxyHost. However, the apache HostConfiguration class does not follow the java beans convention. The setter for the proxyHost accepts an argument of type ProxyHost whereas the getter returns a String.
I have the following snippet in my applicationContext.xml.
<bean id="proxyHost" class="org.apache.commons.httpclient.ProxyHost">
<constructor-arg index="0" type="java.lang.String" value="myproxy.com" />
<constructor-arg index="1" type="int" value="8087" />
</bean>
<bean id="hostConfiguration" class="org.apache.commons.httpclient.HostConfiguration">
<property name="proxyHost" ref="proxyHost" />
</bean>
When I try to load the applicationContext for the app I get the following error since HostConfigurationClass does not have a getProxyHost that returns a ProxyHost or a setter that takes a String:-
org.springframework.beans.NotWritablePropertyExcep tion: Invalid property 'proxyHost' of bean class [org.apache.commons.httpclient.HostConfiguration]: Bean property 'proxyHost' is not writable or has an invalid setter method: Does the parameter type of the setter match the return type of the getter?
While searching on the springsource forum I came across this thread where it was recommended to use MethodInvokingFactoryBean to solve this.
I am not exactly sure how using MethodInvokingFactoryBean would help since I would need a return type of ProxyHost from the method getProxyHost() to fix this, right? And I am not also sure about how to use it in this context. I am not clear on the internals of MethodInvokingFactoryBean. Therefore, if someone could please give me an example in the above context how to use MethodInvokingFactoryBean that would be of immense help.
Also is this generally the accepted way to set up beans like HostConfiguration that do not follow convention in spring?
Thanks!
First , instantiate the ProxyHost
(i.e. ProxyHost proxyHost = new ProxyHost("myproxy1.com",8080);
<bean id="proxyHost" class="org.apache.commons.httpclient.ProxyHost">
<constructor-arg index="0" type="java.lang.String" value="myproxy1.com" />
<constructor-arg index="1" type="int" value="8088" />
</bean>
Then instantiate the HostConfiguration object
(i.e. HostConfiguration hostConfiguration = new HostConfiguration();
<bean id="hostConfiguration" class="org.apache.commons.httpclient.HostConfiguration" />
After that , use the MethodInvokingFactoryBean to call setProxyHost() on the HostConfiguration and pass the proxyHost as argument.
(i.e. hostConfiguration.setProxyHost(proxyHost);)
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject">
<ref local="hostConfiguration"/>
</property>
<property name="targetMethod">
<value>setProxyHost</value>
</property>
<property name="arguments">
<ref local="proxyHost"/>
</property>
</bean>
As mentioned in the other answer you can implement a FactoryBean. If you are using spring 3.0 you could also take a look at the Java Configuration - #Configuration / #Bean.
Related
I need a bean like this
<bean id="studentWithSchool" class="com.model.Student" scope="prototype">
<property name="school">
<bean class="com.model.School" scope="prototype"/>
</property>
</bean>
This is OK.
My problem is I have the student returning from a method from a different bean.
I usually load the bean like this when is a property.
<property name='beanProperty' value='#{anotherBean.getBeanProperty()}'/>
But in this case I need the new bean itself being set from the other bean method (School object is returned from another bean method).
This is what I try, and of course this is wrong:
<bean id="studentWithSchool" class="com.model.Student" scope="prototype" value='#{anotherBean.getBeanProperty()}'>
<property name="school">
<bean class="com.model.School" scope="prototype"/>
</property>
</bean>
Is there any workaround?
If I understand you correctly, the studentWithSchool is created and returned by a method in anotherBean. If that's the case, you can use a factory-method:
<bean id="studentWithSchool" factory-bean="anotherBean" factory-method="getBeanProperty" scope="prototype" />
I believe you are trying to use factory patter with Spring . For that you can use factory bean from spring.
<bean id="studentWithSchool" factory-bean="anotherBeanStaticFactory" factory- method="createBeanProperty" scope="prototype"
<property name="school">
<bean class="com.model.School" scope="prototype"/>
</property>
For more detail you can use below link :-
http://docs.spring.io/spring-framework/docs/2.5.6/api/org/springframework/beans/factory/BeanFactory.html
After switching to Spring 3.1 Eclipse started to complain about our current implementation of TokenBasedRememberMeServices. The class extending it has a parameterless constructor which has been deprecated. The new constructor accepts two params.
An extract from applicationContext-security.xml :
<bean id="rememberMeServices" class="MyRememberMeServices"
p:key="${rememberMeServices.key}">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
What's the easiest way of moving to the new API?
Use constructor injection:
<bean id="rememberMeServices" class="MyRememberMeServices">
<constructor-arg value="${rememberMeServices.key}" />
<constructor-arg ref="userDetailsService" />
</bean>
Obviously you'd add a corresponding constructor in your MyRememberMeServices which calls the parent class.
<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.
Short question: If I have class that impelemnts FactoryBean interface, how can I get from FactoryBean object itself instead of FactoryBean.getObject()?
Long question: I have to use 3-rd party Spring based library which is hardly use FactoryBean interface. Right now I always must configure 2 beans:
<!-- Case 1-->
<bean id="XYZ" class="FactoryBean1" scope="prototype">
<property name="steps">
<bean class="FactoryBean2">
<property name="itemReader" ref="aName"/>
</bean>
</property>
</bean>
<bean id="aName" class="com.package.ClassName1" scope="prototype">
<property name="objectContext">
<bean class="com.package.ABC"/>
</property>
</bean>
<!-- Case 2-->
<bean id="XYZ2" class="FactoryBean1" scope="prototype">
<property name="steps">
<bean class="FactoryBean2">
<property name="itemReader" ref="aName2"/>
</bean>
</property>
</bean>
<bean id="aName2" class="com.package.ClassName1" scope="prototype">
<property name="objectContext">
<bean class="com.package.QWE"/>
</property>
</bean>
Actyually defintion of a bean with name "XYZ" (compare with "XYZ2") never will be changed, but because of factory nature I must copy the code for each configuration.
Definition of a bean with name "aName" always will be new (i.e. each configuration will have own objectContext value).
I would like to simplify the configuration have a single factory bean (remove "XYZ2" and rid of link to "aName"):
<bean id="XYZ" class="FactoryBean1" scope="prototype">
<property name="steps">
<bean class="FactoryBean2"/>
</property>
</bean>
<bean id="aName" class="com.package.ClassName1" scope="prototype">
<property name="objectContext">
<bean class="com.package.ABC"/>
</property>
</bean>
<bean id="aName2" class="com.package.ClassName1" scope="prototype">
<property name="objectContext">
<bean class="com.package.QWE"/>
</property>
</bean>
Unfortunately, it's not as simple as I expect. I suppose to glue factory (i.e. XYZ bean from the example) with necessary objects (i.e. "aName", "aName2") at runtime.
The approach doesn't work because when I ask Spring for FactoryBean object it returns to me FactoryBean.getObject() which impossible to instanciate at that time because of missing itemReader value.
I hope that SpringSource foresee my case I can somehome "hook" FactoryBean.getObject() call to provide all necessary properties at runtime.
Another complexity that disturb me a bit it's chains of Factories (Factory1 get an object from Factory2 that I have to "hook" at runtime).
Any ideas will be appreciated.
It's the & (ampersand), not the At-symbol, see Spring Framework documentation: Customizing instantiation logic using FactoryBeans
<property name="factoryBean" ref="&theFactoryBean" />
You can get the factory bean itself using the & syntax in the spring config:
<property name="factoryBean" ref="&theFactoryBean" />
as opposed to:
<property name="createdBean" ref="theFactoryBean" />
Is it possible to set the property of one bean by reading the property of another bean? For instance, suppose I had:
class A {
void setList(List list);
}
class B {
List getList();
}
I would like Spring to instantiate both classes, and call A's setList method, passing in the result of calling B's getList method. The Spring configuration might look something like:
<bean id="b" class="B"/>
<bean id"a" class="A">
<property name="list" ref="b" ref-property="list"/>
</bean>
Alas, this made-up XML does not work.
Why not just inject B into A? Because I do not want to introduce the extra dependency. A is only dependent List, not on B.
in addition to #Kevin's answer if you are using spring 3.0 it is possible to do this with the new spring expression language
<bean id="a" class="A">
<property name="list"
value="#{b.list}"/>
</bean>
spring 3.0 documentation
There are a couple of ways. Here is one:
<bean id="b" class="B"/>
<bean id="a" class="A">
<property name="list">
<bean class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
<property name="targetObject" ref="b"/>
<property name="propertyPath" value="list"/>
</bean>
</property>
</bean>
Also see the <util:property-path/> element
If you are trying to do the same for a constructor then do this.
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg type="javax.sql.DataSource" value="#{jdbc.dataSource}">
</constructor-arg>
</bean>
Here "jdbc" is as mentioned below that has property "dataSource" with getter and setter and initilized as:
<bean id="jdbc" class="com.la.activator.DataSourceProvider">
<property name="myDataSourcePool" ref="dsPoolService"/>
</bean>