In this post, I would like to share several useful things about Spring Expression Language which can help you with Spring framework configuration.

Spring XML wiring style is sufficient in most cases. Sometimes, however, you need to perform wiring that is much more difficult or sometimes even impossible without writing extra Java code e.g. convert string value to upper case, calculate numeric value etc.

In order to improve configuration and address many difficult wirings, Spring 3 introduced the Spring Expression Language (SpEL for short), a very powerful way of wiring values into a bean's properties or constructor arguments that supports querying and manipulating an object graph at runtime.

In order to navigate properties you just need to use a period (.) to indicate a nested property value e.g.

<property name="property" value="#{otherBean.property}"/>

You can also call a method of otherBean and wire return value of the method e.g.

<property name="property" value="#{otherBean.method()}"/>

You can chain method to amend your wired value even further. Let's wire length of a string returned from the method():

<property name="strLength" value="#{otherBean.method().length()}"/>

Note that the two following statements are giving the same results:

<property name="property" ref="otherBean"/>
<property name="property" value="#{otherBean}"/>

Accessing class-scoped methods and properties

Sometimes there is a need to wire some constans or results of a static method, say, I would like to configure my bean with minimum integer value Integer.MIN_VALUE.

SpEL introduced T() operator which gives you access to static methods and constants on a given class.

A few examples:

  1. Insert minimum or maximum integer value:

     <property name="prop" value="#{T(java.lang.Integer).MIN_VALUE}"/>
     <property name="prop" value="#{T(java.lang.Integer).MAX_VALUE}"/>
    
  2. Insert random value

     <bean id="myBean" class="x.y.z.MyBean">
         <property name="randomValue" value="#{T(java.lang.Math).random()}" />
     </bean>
    
  3. Insert one of the predefined formats from java.time.format.DateTimeFormatter class:

     <property name="format" value="#{T(java.time.format.DateTimeFormatter).BASIC_ISO_DATE}"/>
    

How to avoid exceptions

Let's say that you would like to wire result of a method call, of type String, and convert it to uppercase. The following example does that:

<property name="propertyName" value="#{otherBean.method().toUpperCase()}"/>

But if method() returns null value, you would get BeanExpressionException caused by SpelEvaluationException Method call: Attempted to call method toUpperCase() on null context object. Luckily SpEL provides null-safe operator which allows you to avoid exception and insert null value if any of the chain properties is null.

Instead of a single period (.) you need to precede a period with a question mark (?). So your configuration would look like this:

<property name="prop" value="#{otherBean.method()?.toUpperCase()}"/>

The prop property would get null value if method() returns null.

Note that you will still get BeanCreationException if try to set null value to a property of primitive type.

In the following example strLength will get length of a string returned by method().

<property name="strLength" value="#{otherBean.method()?.length()}" />

If method() returns null you will get BeanCreationException caused by:

java.lang.IllegalArgumentException: Cannot convert value of type [null] to required type [int] for property 'strLength'

That can be resolved by conditional evaluation though.

Conditional evaluation

What if you want to wire one value if a condition is true and a different value otherwise? For example, I want to wire string length or -1 if the string is null. In that case, we can use SpEL's ternary operator (?:):

<property name="strLength" 
    value="#{otherBean.method() != null ? otherBean.method().length() : -1}" />

Regular Expressions

Spring Expression Language also supports pattern matching with its matches operator. The result of maching operation is a boolean value: true if the value mathes the regular expression, false otherwise.

We can use regular expressions matching to test different string type properties e.g. let's check if one of the values is composed of digits only:

<property name="onlyDigits" value="#{otherMean.method() matches '\d+'}" />

The value of onlyDigits will be true only if string returned by otherMean.method() is composed of digits e.g. 12319845753123.

Conclusions

As you could see, the Spring Expression Language is a very powerful expression language helping you to improve your beans configuration file. It is also worth mentioning that SpEL is based on a technology agnostic API allowing other expression language implementations to be integrated should the need arise. So list of useful things about SpEL can grow with next Spring releases.