Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting a Spring bean class name using a SpEL expression and PropertyPlaceHolder

Tags:

java

spring

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.

like image 672
sparc_spread Avatar asked Feb 22 '23 00:02

sparc_spread


2 Answers

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.

like image 174
mrembisz Avatar answered Feb 23 '23 12:02

mrembisz


You can do this.

debug.class=com.springtest.ExampleDebug
#debug.class=com.springtest.ExampleProd

and then

<bean id="example" class="${debug.class}"/>
like image 41
chalimartines Avatar answered Feb 23 '23 13:02

chalimartines