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" />
Related
I need to pass currentDate as String to my sendMetaStatsTask tasklet appended in subject .
Now, if I create a bean with scope="step" using following xml
<bean id="sendMetaStatsTask" class="org.springframework.batch.core.step.tasklet.MethodInvokingTaskletAdapter" scope="step">
<property name="targetObject">
<bean class="com.nextag.catalog.springbatch.tasklets.GenerateReportFromQueriesTasklet">
<property name="mailTo" value="#{jobParameters['MAIL_TO']}"/>
<property name="mailFrom" value="#{jobParameters['MAIL_FROM']?:'wizereporter#nextag.com'}"/>
<property name="mailSubject" value="#{jobParameters['PARTNER_DOMAIN']+' Affiliate Seller Report - '+ currentDate.toString()}"/>
</bean>
</property>
<property name="targetMethod" value="execute"/>
</bean>
<bean id="fastDateFormat" class="org.apache.commons.lang.time.FastDateFormat" factory-method="getInstance">
<constructor-arg value="dd/MM/yyyy"/>
</bean>
<bean id="currentDate" class="java.util.Date" factory-bean="fastDateFormat" factory-method="format" scope="step">
<constructor-arg>
<bean class="java.util.Date"/>
</constructor-arg>
</bean>
It throws :-
Error creating bean with name 'currentDate' defined in BeanDefinition
defined in file
[/home/nextag/Apache6/tomcat/webapps/nextag/WEB-INF/classes/META-INF/spring/batch/jobs/seller-meta-stats-logging-job.xml]:
Initialization of bean failed; nested exception is
java.lang.IllegalStateException: Cannot create scoped proxy for bean
'scopedTarget.currentDate': Target type could not be determined at the
time of proxy creation.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
However, it works fine in case I use prototype .
Need to ask why it is not working in step scope, am I missing something ?
You need to tell the bean currentDate scope proxy so any injection is only valid to scope step. A good explanation is here
<bean id="fastDateFormat" class="org.apache.commons.lang.time.FastDateFormat" factory-method="getInstance">
<constructor-arg value="dd/MM/yyyy"/>
</bean>
<bean id="currentDate" class="java.util.Date" factory-bean="fastDateFormat" factory-method="format" scope="step">
<aop:scoped-proxy/>
<constructor-arg>
<bean class="java.util.Date"/>
</constructor-arg>
</bean>
Say I have the following beans defined.
<bean id="testBean1" class="org.springframework.beans.TestBean" scope="prototype">
<property name="hariColor" value="Black"/>
<property name="spouse">
<bean class="org.springframework.beans.TestBean">
<property name="age" value="11"/>
</bean>
</property>
</bean>
<bean id="testBean2" class="org.springframework.beans.TestBean" scope="prototype">
<property name="hariColor" value="Black"/>
<property name="spouse">
<bean class="org.springframework.beans.TestBean">
<property name="age" value="19"/>
</bean>
</property>
</bean>
I have a set of beans with hairColor Black, another set of beans with hairColor Blonde etc.. Is there a way in Spring to group all Black hair color beans together and define the hairColor in only one place rather than specifying for each bean?
Yes you can achieve it via abstract="true" element in Spring's bean as explained below
<bean id="blackHairColor" abstract="true">
<property name="prop1" ref="someBlackBean"/>
<property name="prop2" ref="someOtherBlackBean"/>
</bean>
<bean id="blondeHairColor" abstract="true">
<property name="prop1" ref="someBlondeBean"/>
<property name="prop2" ref="someOtherBlondeBean"/>
</bean>
<bean id="someBean1" class="a.b.c.d" parent="blackHairColor">
<property name="someOtherProp" ref="someRef1"/>
</bean>
<bean id="someBean2" class="a.b.c.d" parent="blondeHairColor">
<property name="someOtherProp" ref="someRef1"/>
</bean>
Here we define two abstract beans with respective properties. Do note that these abstract beans do not have a class attached to them and thus creates a set of common properties which could be re-used in other bean(s).
To inherit the abstract bean simply mention their id in the parent element of bean definition. Also note that the bean class does not need to inherit any class to inherit another bean i.e. class a.b.c.d do not need to inherit any class for the bean inheritance to work.
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
Suppose I have my own bean which contains another beans hardcoded.
How to join this with Spring configuration?
First way is to use factory-method:
<bean id="bean1" class="myClass1"/>
<bean id="bean1.member" factory-bean="bean1" factory-method="getMember"/>
<bean id="bean2" class="myClass2">
<property name="collaborator" ref="bean1.member"/>
</bean>
Another way is to use EL:
<bean id="bean1" class="myClass1"/>
<bean id="bean2" class="myClass2">
<property name="collaborator" value="#{bean1.member}"/>
</bean>
In latter case Spring does not realize the dependency. Anyway, Bean Graph in Eclipse displays beans unrelated.
Are there better ways? May be I may implement some interface with MyClass1 so that it will treated as container or context?
You should create a separate bean for bean1.member and inject it into bean1
<bean id="bean3previouslyMember" class="myCompoundBean"/>
<bean id="bean1" class="myClass1">
<property name="member" ref="bean3previouslyMember"/>
</bean>
<bean id="bean2" class="myClass2">
<property name="collaborator" ref="bean3previouslyMember"/>
</bean>
Unless myClass1 is not modifiable and has no setter, this is generally what we do.
I need to do very similar thing to what is described in Injecting Entitymanager via XML and not annnotations, but I need to inject from XML the real, container-created, entity manager, so that it behaves exactly as if there is a real #PersistenceContext annotation. I've found a LocalEntityManagerFactoryBean (notice missing "Container" word), but I'm affraid that it creates a new entity manager factory and therefore entity manager won't be compatible with that injected via real #PersistenceContext annotation.
I will describe the reason, because it is weird and maybe the solution to my problem is to choose completely different approach. I'm using PropertyPlaceholderConfigurer in my spring configuration and in this configurer I'm referencing other beans. I'm experiencing a bug that autowiring doesn't work in those referenced beans. I don't know why and how PropertyPlaceholderConfigurer turns off autowiring in those referenced beans but the fact is, that if I replace autowiring by xml configuration for those beans, everything works. But I'm unable to replace autowiring of EntityManager, since it's not standard spring bean, but jndi-loaded something I don't fully understand.
One way or the other, is there some solution?
in spring-bean.xml ,
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="USER_TEST"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect"/>
</property>
<property name="jpaPropertyMap">
<props>
<prop key="eclipselink.weaving">false</prop>
</props>
</property>
<bean id="PersonDao" class="com.xxx.java.person.persistence.PersonDAO">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="earlyInitializedApplicationSettingsService" class="...services.impl.ApplicationSettingsServiceImpl" autowire-candidate="false">
<property name="applicationSettingsDao">
<bean class="....impl.ApplicationSettingsDaoImpl">
<property name="entityManager">
<bean class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory">
<bean class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/persistence/somePersistenceUnit"/>
</bean>
</property>
</bean>
</property>
</bean>
</property>
</bean>
Notice mainly the fact, that I'm not using standard jee:jndi-lookup, because it didn't work (in the conditions created by PropertyPlaceholderConfigurer) and that was the source of my confusion. When I used direct JndiObjectFactoryBean, it worked.