UPDATED: Resolution summary as of 12/9/2016
According to @altazar's answer below, this is now possible as of Spring 4.2!
Old resolution summary as of 3/29/2012
As of this date, Spring SpEL could not execute inside a class
attribute of a <bean>
.
Original question:
I'm trying to implement a dynamic class
attribute for a Spring bean, ultimately set using a combination of a PropertyPlaceHolder
property and a SpEL expression. The purpose is to choose either a production or debug version of a class to instantiate. It is not working and I'm wondering if it is possible to achieve.
So far, I have the following:
Flat properties file:
is.debug.mode=false
Spring XML config:
<bean id="example"
class="#{ ${is.debug.mode} ?
com.springtest.ExampleDebug :
com.springtest.ExampleProd}"
/>
Spring bootstrap Java code:
// Get basic ApplicationContext - DO NOT REFRESH
FileSystemXmlApplicationContext applicationContext = new
FileSystemXmlApplicationContext
(new String[] {pathSpringConfig}, false);
// Load properties
ResourceLoader resourceLoader = new DefaultResourceLoader ();
Resource resource = resourceLoader.getResource("file:" + pathProperties);
Properties properties = new Properties();
properties.load(resource.getInputStream());
// Link to ApplicationContext
PropertyPlaceholderConfigurer propertyConfigurer =
new PropertyPlaceholderConfigurer() ;
propertyConfigurer.setProperties(properties) ;
applicationContext.addBeanFactoryPostProcessor(propertyConfigurer);
// Refresh - load beans
applicationContext.refresh();
// Done
Example example = (Example) applicationContext.getBean("example");
Error message (with a lot of whitespace removed for clarity):
Caused by: java.lang.ClassNotFoundException:
#{ true ? com.springtest.ExampleDebug : com.springtest.ExampleProd}
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
. . .
As you can see by the "true
" in the message, the is.debug.mode
property is successfully loaded and substituted. But something else is going wrong. Is it my bootstrap sequence in the Java? Or the SPeL syntax in the XML? Or a different issue?
BTW I am aware of the new 3.1 profiles feature, but I would like to do this via SPeL for a variety of reasons. Also I realize I'm using a filesystem-based context and paths - I have reasons for that too.
You could accomplish what you intend with a factoryBean:
<bean id="example" class="MyFactoryBean">
<property name="class" value="#{ ${is.debug.mode} ? com.springtest.ExampleDebug : com.springtest.ExampleProd}"/>
</bean>
where MyFactoryBean is a trivial FactoryBean implementation returning instance of indicated class.
You can do this.
debug.class=com.springtest.ExampleDebug
#debug.class=com.springtest.ExampleProd
and then
<bean id="example" class="${debug.class}"/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With