Take the following configuration:
<beans>
<bean name="myToyota" class="Car">
<property name="contents">
<list>
<bean class="Wheel">
<property name="designation"><value>front-left</value></property>
<property name="parent"><ref bean="myToyota"/></property>
</bean>
<bean class="Wheel">
<property name="designation"><value>front-right</value></property>
<property name="parent"><ref bean="myToyota"/></property>
</bean>
</list>
</property>
</bean>
</beans>
Is it possible to build this graph without directly referencing myToyota from the Wheel beans? (Maybe using SpEL).
My concern is that I can not copy-paste the description of the Wheels to an other Car bean without introducing the possibility of broken references (that's me forgetting to adjust the parent property by hand).
In other words: is there a way an inner bean can referece it's containing bean without knowing its name?
What if you do something like the following:
public class Car {
private List contents;
public List getContents() {
return contents;
}
public void setContents(List contents) {
this.contents = contents;
for (Iterator iterator = contents.iterator(); iterator.hasNext();) {
Wheel object = (Wheel) iterator.next();
object.setParent(this);
}
}
}
Related
I am facing a strange problem with Spring, a bean is not initialized completely with injected dependency. It works fine if a thread sleep of minimal 5 seconds is introduced before accessing that bean.
This is not a case of notify/wait as this is in control of Spring.
Another pointer is that the bean's methods are static and variable is also static.
Any hints will be appreciated.
Here's the code
public final class UserPreferencesUtils {
/** siamHandlerFacade variable. */
private static SiamHandlerFacade siamHandlerFacade;
=====
public static String getSubscriberXXXX() {
try {
// Here the above is being used
// This method is also static
showSubscriberProfile = siamHandlerFacade
.retrieveSubscriberProfile(retrieveSubscriberProfile);
} catch (WebServiceClientException ex) {
ex.getMessage();
bean configuration
<bean id="userPreferenceUtils" class="aero.sita.voyager.ias.client.commons.utils.UserPreferencesUtils">
<property name="siamHandlerFacade" ref="siamServiceManagerRemoteService"></property>
<property name="queryLMData" ref="queryLMData"></property>
</bean>
<bean id="siamServiceManagerRemoteService"
class="aero.sita.voyager.ias.client.commons.webserviceproxy.SiamHandlerFacadeImpl">
<property name="siamWebServiceCallProxy" ref="siamWebServiceCallProxy"/>
<property name="officeWebServiceCallProxy" ref="officeWebServiceCallProxy"/>
<property name="subscriberWebServiceCallProxy" ref="subscriberWebServiceCallProxy"/>
<property name="masterAgreementWebServiceCallProxy" ref="masterAgreementWebServiceCallProxy"/>
<property name="agreementWebServiceCallProxy" ref="agreementWebServiceCallProxy"/>
<property name="userProfileWebServiceCallProxy" ref="userProfileWebServiceCallProxy"/>
</bean>
I have two lists generated with a FactoryBean and I would like to initialize a bean with the merged version of this two. Is there a way doing this?
<bean id="listA" class="XFactoryBean" >
...
</bean>
<bean id="listB" class="YFactoryBean">
...
</bean>
<bean >
<property name="AwithB" ...>
</bean>
There is a solution that works with static lists (http://vikdor.blogspot.hu/2012/10/using-collection-merging-in-spring-to.html), but does not work with those generated lists.
Java #Configuration FTW:
#Configuration
public class Config {
#Resource
private List listA;
#Resource
private List listB;
#Bean
public List AwithB() {
List mergedList = new ArrayList(listA);
listB.addAll(listB);
return mergedList;
}
}
Much less boilerplate.
There is a sublte bug with the ListMergerFactoryBean solution above.
Config:
<util:list id="listA" value-type="java.lang.String">
<value>fooA</value>
<value>barA</value>
</util:list>
<util:list id="listB" value-type="java.lang.String">
<value>fooB</value>
<value>barB</value>
</util:list>
<util:list id="listC" value-type="java.lang.String">
<value>fooC</value>
<value>barC</value>
</util:list>
<bean id="AwithB" class="com.util.ListMergerFactoryBean">
<property name="listOfLists">
<list>
<ref bean="listA" />
<ref bean="listB" />
</list>
</property>
</bean>
<bean id="AwithC" class="com.util.ListMergerFactoryBean">
<property name="listOfLists">
<list>
<ref bean="listA" />
<ref bean="listC" />
</list>
</property>
</bean>
With this config you might be surprised when bean AwithB has the expected content of AwithC. ListA is a singleton and the getObject method alters it, therefore alters it for all users of ListMergerFactoryBean, even though the bean factory is not a singleton. The fix is to not re-use the first list in the listOfLists:
#Override
public List getObject() throws Exception {
List mergedList = new ArrayList();
for (List list : listOfLists) {
mergedList.addAll(list);
}
return mergedList;
}
After checking the SpEL-related solutions (how to extend a list in spring config) and extending the ListFactoryBean (http://ericlefevre.net/wordpress/2008/04/02/merging-lists-in-a-spring-configuration-file/) I came up with the following solution:
config:
<bean id="AwithB" class="com.util.ListMergerFactoryBean">
<property name="listOfLists">
<list>
<ref bean="listA" />
<ref bean="listB" />
</list>
</property>
</bean>
java:
public class ListMergerFactoryBean implements FactoryBean<List> {
private List<List> listOfLists;
#Override
public List getObject() throws Exception {
List mergedList = new ArrayList();
for (List list : listOfLists) {
mergedList.addAll(list);
}
return mergedList;
}
#Override
public Class<?> getObjectType() {
return (new ArrayList()).getClass();
}
#Override
public boolean isSingleton() {
return false;
}
public void setListOfLists(List<List> listOfLists) {
this.listOfLists = listOfLists;
}
}
UPDATE: I have eliminated a bug using Aron Bartle's solution. Thanks!
I need to wire a property for a given object without using a bean id, if possible. Autowiring doesn't work, because the type of the property is Object and is, hence, not specific at all. Is there a way to autowire by class or interface like this:
<bean class="NonSpecificClassThing">
<property name="targetObject">
<a:wire-by-type type="com.things.MyInterface"/>
</property>
</bean>
<bean class="com.things.MyInterfaceImpl"/>
Is something like this possible?
Apparently you can do something like this :
target class :
public class NonSpecificClassThing {
private Object targetObject;
// do something;
public getTargetObject() {
return targetObject;
}
public void setTargetObject(Object targetObject) {
this.targetObject = targetObject;
}
}
spring context :
<bean class="NonSpecificClassThing">
<property name="targetObject">
<ref bean="com.things.MyInterfaceImpl"/>
</property>
</bean>
<bean class="com.things.MyInterfaceImpl"/>
I am trying to inject the aspects in a service. For this service I am creating a proxied object using classic way.
I have written a bean- baseProxy of type (ProxyFactoryBean) which contains a list of all the required advices.
<bean id="baseProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>methodInvocationAdvice</value>
</list>
</property>
</bean>
I am creating a proxy for the service like this :
<bean id="singproxy" parent="baseProxy">
<property name="target" ref="singtarget" />
<property name="targetClass" value="com.spring.learning.SingingService"></property>
</bean>
Which doesn't work but when I revert these two properties and write like this :
<bean id="singproxy" parent="baseProxy">
<property name="targetClass" value="com.spring.learning.SingingService"></property>
<property name="target" ref="singtarget" />
</bean>
To my surprise it works fine. In spring does it matter on the order for bean ? Or its a special case with ProxyFactoryBean?
I tried with Spring 3.0 I am not sure same behavior exists with previous versions.
Concerning target and targetClass, It's one or the other, but not both. Here's the relevant source (from org.springframework.aop.framework.AdvisedSupport), a parent class of ProxyFactoryBean:
public void setTarget(Object target) {
setTargetSource(new SingletonTargetSource(target));
}
public void setTargetSource(TargetSource targetSource) {
this.targetSource = (targetSource != null ? targetSource : EMPTY_TARGET_SOURCE);
}
public void setTargetClass(Class targetClass) {
this.targetSource = EmptyTargetSource.forClass(targetClass);
}
As you can see, both setTarget() and setTargetClass() write to the same field, so the last assignment wins.
I want to fill a bean list property using Spring properties place holder.
Context file
<bean name="XXX" class="XX.YY.Z">
<property name="urlList">
<value>${prop.list}</value>
</property>
</bean>
Properties File
prop.list.one=foo
prop.list.two=bar
Any help would be much appreciated
Use a util:properties element to load your properties. You can use PropertyPlaceholderConfigurer to specify the path to your file:
<bean name="XXX" class="XX.YY.Z">
<property name="urlList">
<util:properties location="${path.to.properties.file}"/>
</property>
</bean>
Update I've misunderstood the question; you only want to return properties where key starts with specific string. The easiest way to achieve that would be to do so within setter method of your bean. You'll have to pass the string to your bean as a separate property. Extending the above declaration:
<bean name="XXX" class="XX.YY.Z" init-method="init">
<property name="propertiesHolder">
<!-- not sure if location has to be customizable here; set it directly if needed -->
<util:properties location="${path.to.properties.file}"/>
</property>
<property name="propertyFilter" value="${property.filter}" />
</bean>
In your XX.YY.Z bean:
private String propertyFilter;
private Properties propertiesHolder;
private List<String> urlList;
// add setter methods for propertyFilter / propertiesHolder
// initialization callback
public void init() {
urlList = new ArrayList<String>();
for (Enumeration en = this.propertiesHolder.keys(); en.hasMoreElements(); ) {
String key = (String) en.nextElement();
if (key.startsWith(this.propertyFilter + ".") { // or whatever condition you want to check
this.urlList.add(this.propertiesHolder.getProperty(key));
}
} // for
}
If you need to do this in many different places you can wrap the above functionality into a FactoryBean.
A simpler solution:
class Z {
private List<String> urlList;
// add setters and getters
}
your bean definition
<bean name="XXX" class="XX.YY.Z">
<property name="urlList" value="#{'${prop.list}'.split(',')}"/>
</bean>
Then in your property file:
prop.list=a,b,c,d
<bean id="cpaContextSource" class="org.springframework.ldap.core.support.LdapContextSource">
<property name="urls">
<bean class="org.springframework.util.CollectionUtils" factory-method="arrayToList">
<constructor-arg type="java.lang.Object">
<bean class="org.springframework.util.StringUtils" factory-method="tokenizeToStringArray">
<constructor-arg type="java.lang.String" value="${myList}"/>
<constructor-arg type="java.lang.String" value=" "/>
</bean>
</constructor-arg>
</bean>
</property>
where:
myList=http://aaa http://bbb http://ccc
The only way i see here is, implement the interface 'MessageSourceAware' to get the messageResource, and then manually populate your list.
class MyMessageSourceAwareClass implemets MessageSourceAware{
public static MessageSource messageSource = null;
public void setMessageSource(MessageSource _messageSource) {
messageSource = _messageSource;
}
public static String getMessage( String code){
return messageSource.getMessage(code, null, null );
}
}
--- Properties File ---
prop.list=foo;bar;one more
Populate your list like this
String strlist = MyMessageSourceAwareClass.getMessage ( "prop.list" );
if ( StringUtilities.isNotEmptyString ( strlist ) ){
String[] arrStr = strList.split(";");
myBean.setList ( Arrays.asList ( arrStr ) );
}
Just add the following Bean definition
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:myprops.properties</value>
</list>
</property>
</bean>
To use it like so please note port is defined in myprops.properties
<bean id="mybean" class="com.mycompany.Class" init-method="start">
<property name="portNumber" value="${port}"/>
</bean>
There are several ways , one of them is below.
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
cfg.postProcessBeanFactory(factory);