PDA

View Full Version : PropertyPlaceholderConfigurer for bean class



bpryor
Oct 19th, 2004, 03:22 PM
I have just started to use Spring in a Tapestry web application. I'm currently making heavy use of Tapestry "extensions" which are managed objects just like Spring beans upon which properties can be set.

I am planning on using the Spring stack to eliminate these Tapestry extensions, making the service objects into Spring beans. The initial target use of Spring then is as a simple service manager / locator.

The application is heavily customized - a common idiom we use is to have an interface with a different concrete implementation for each client.

So what I really wanted to do was:


<bean id="serviceBean" class="$&#123;client.service.class&#125;" />

... and use the PropertyPlaceholderConfigurer to replace the token with the actual name of the concrete service class for a client.

However, it seems that the PropertyPlaceholderConfigurer is useful only for replacing <property> values, which makes sense given its name.

Is there a better way to accomplish this using Spring?

An additional note: I would like to have a single applicationContext.xml file - each client would have their own client.properties with customized values.

irbouho
Oct 19th, 2004, 03:40 PM
try the following:

<bean id="serviceBean" class="java.lang.Class" factory-method="forName">
<constructor-arg>
<value>$&#123;client.service.class&#125;</value>
</constructor-arg>
</bean>

HTH

bpryor
Oct 19th, 2004, 04:07 PM
Thanks for the suggestion. That does almost what I'm looking for, except that the service bean ends up being a java.lang.Class instead of an instance of that class. Using that idea, I found that something like this works:



<bean id="serviceFactory" class="java.lang.Class" factory-method="forName" singleton="false">
<constructor-arg><value>$&#123;client.service.class&#125;</value></constructor-arg>
</bean>
<bean id="serviceBean" factory-bean="serviceFactory" factory-method="newInstance" />


Is there a way to accomplish this with a single <bean> declaration?

jbetancourt
Oct 19th, 2004, 06:28 PM
The most direct route is not possible. I don't think Spring allows migration of bean attributes to elements so that an inline bean definitions could be used here, but maybe that would be useful in many other situations. [not implying this is what you are looking for, of course].




Not possible?

<bean id="serviceBean" factory-method="newInstance">
<property name="factory-bean">
<bean class="java.lang.Class" factory-method="forName" singleton="false">
<constructor-arg><value>$&#123;client.service.class&#125;</value></constructor-arg>
</bean>
</property>
</bean>







Thanks for the suggestion. That does almost what I'm looking for, except that the service bean ends up being a java.lang.Class instead of an instance of that class. Using that idea, I found that something like this works:



<bean id="serviceFactory" class="java.lang.Class" factory-method="forName" singleton="false">
<constructor-arg><value>$&#123;client.service.class&#125;</value></constructor-arg>
</bean>
<bean id="serviceBean" factory-bean="serviceFactory" factory-method="newInstance" />


Is there a way to accomplish this with a single <bean> declaration?

cmgharris
Oct 20th, 2004, 02:35 AM
You could write your own factory bean class, e.g. ClassInstantiatingFactoryBean, implementing FactoryBean and having the class name as a property.

Then you'd get your instance with

<bean id="serviceBean" class="foo.bar.ClassInstantiatingFactoryBean">
<property name="className"><value>$&#123;client.service.class&#125;</value></property>
</bean>

.NET Guy
Oct 20th, 2004, 02:46 AM
How about this approach? It does mean writing some code though :?



public class Activator &#123;

public static object createInstance &#40;string clazz&#41; &#123;
return Activator.createInstance &#40;Class.forName &#40;clazz&#41;&#41;;
&#125;

public static object createInstance &#40;Class clazz&#41; &#123;
return clazz.newInstance &#40;&#41;;
&#125;
&#125;




<bean id="serviceBean" class="Activator" factory-method="createInstance">
<constructor-arg>
<value>$&#123;client.service.class&#125;</value>
</constructor-arg>
</bean>


I have (obviously) left out all error checking, etc :wink:

bpryor
Oct 20th, 2004, 08:20 AM
Thanks for all the suggestions. I ended up writing a simple class instantiator factory that does a Class.forName and a newInstance() based off a className argument. I used a single bean declaration with factory-method, passing in the className as a constructor-arg.

This approach allows me to set properties on the created beans as well as specify their class.