How does the Spring 3 expression language interact with property placeholders?

Spring 3 introduced a new expression language (SpEL) that can be used in bean definitions. The syntax itself is reasonably well defined.

It is not clear how, if at all, SpEL interacts with the property placeholder syntax that was already present in previous versions. Does SpEL have support for property placeholders, or do I need to combine the syntax of both mechanisms and hope that they combine?

Let me give you a concrete example. I want to use the syntax of the ${xyz} property, but with the addition of the "default" syntax provided by the elis operator to handle cases when ${xyz} is undefined.

I tried the following syntaxes without success:

  • #{xyz?:'defaultValue'}
  • #{${xyz}?:'defaultValue'}

First one gives me

The field or property 'x' cannot be found on an object of type 'Org.springframework.beans.factory.config.BeanExpressionContext'

which suggests that SpEL does not recognize this as a placeholder for properties.

The second syntax throws an exception saying that the placeholder is not recognized, so the calling placeholder is called, but does not work properly, because the property is undefined.

The documents do not mention this interaction, so either such a thing is impossible or not documented.

Who succeeded?




Ok, I came up with a small, standalone test case. It all works as it is:

Bean definitions first:

 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd "> <context:property-placeholder properties-ref="myProps"/> <util:properties id="myProps"> <prop key="xyz">Value A</prop> </util:properties> <bean id="testBean" class="test.Bean"> <!-- here is where the magic is required --> <property name="value" value="${xyz}"/> <!-- I want something like this <property name="value" value="${abc}?:'Value B'"/> --> </bean> </beans> 

Then the trivial class bean:

batch test;

 public class Bean { String value; public void setValue(String value) { this.value = value; } } 

And finally, a test case:

 package test; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class PlaceholderTest { private @Resource Bean testBean; @Test public void valueCheck() { assertThat(testBean.value, is("Value A")); } } 

The task is to come up with a SpEL expression in the beans file, which allows me to specify a default value in cases where ${xyz} cannot be resolved, and this default value should be specified as part of the expression, and not externalized in another set of properties.

+46
java spring spring-el
Jan 11 '10 at 11:45
source share
8 answers

To access the property placeholder from a SpEL expression, you can use the following syntax: #{'${xyz}'} . Hovewer, it cannot solve your problem with the elvis operator and default values, because it throws an exception if ${xyz} cannot be resolved.

But you do not need SpEL to declare default values ​​for properties:

 <context:property-placeholder location="..." properties-ref="defaultValues"/> <bean id = "defaultValues" class = "org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="properties"> <props> <prop key="xyz">ZZZ</prop> </props> </property> </bean> <bean ...> <property name = "..." value = "${xyz}" /> </bean> 
+24
Jan 11 '10 at
source share

You seem to have missed the colon:

 #{ ${xyz} ?: 'defaultValue' } 
+11
Jan 11 '10 at 12:22
source share

If you just want to set the default value for the placeholder, see this :

  <property name="value" value="${xyz:defaultValue}"/> 

If you want to test the interaction between SpEL and placeholder using this:

  <!-- set value "77-AA-BB-CC-88" when property "xyz" not exist --> <property name="value" value="77-#{'AA-${xyz:BB}-CC'}-88"/> 
+8
Jun 13 '13 at 9:45
source share

${myProps.item:defaultValue} means that when myProps.item does not exist, use defaultValue . This behavior is the default property placeholder.

#{defaultValue} means the SpEL value for the literal value.

So ${myProps.item:#{defaultValue}} means that myProps.item does not exist, then it computes the SpEL value and assigns it to the target field.

Example:

${redis.auth:#{null}} means that when the redis.auth properties redis.auth not exist, set it to null .

+6
Apr 13 '15 at 10:37
source share

In fact, the Property-Placeholder can solve your problems on your own. That is, you can explicitly specify default options in the Spring context using the properties property. You can then specify the location for the parameters to be used and set the localOverride property to true . In this case, all the properties that will be found in external resources (specified in the location property) override the default values ​​(explicitly defined in the context).

Hope I helped.

+3
Feb 01 '11 at 13:39
source share

You need to add this to run it in your example.

 <bean id="testBean" class="elvis.Bean"> <!-- here is where the magic is required <property name="value" value="${xyz}"/> --> <!-- I want something like this --> <property name="value" value="#{myProps.get('abc')?:'Value B'}"/> </bean> 

Your approach does not work because Spring is trying to evaluate the ${abc} object a with member b with element c , which leads to NPE because a does not exist.

+3
Mar 14 2018-12-12T00:
source share

You can:

 <bean id="testBean" class="test.Bean"> <!-- if 'abc' not found, then value="Value B" ---> <property name="value" value="${abc:Value B}"/> </bean> 

or

  ... <!-- if 'abc' not found , but 'ab' found ,then value=${ab} if 'ab' also not found , then value="a" --> <property name="value" value="${abc:${ab:a}"/> ... 

or ...

  <!-- if 'abc' not found , but 'ab' found ,then value=${ab} if 'ab' also not found , then value="a" --> <property name="value" value="#{ '${abc:}' ?: '${ab:a}' }"/> ... 
+1
Jul 06 '16 at 7:05
source share

I tried the following and it worked (rather ugly):

#{ myProps.getProperty('xyz')?:'Value B' }

0
Jul 24 2018-12-12T00:
source share



All Articles