Useful things spring expression language SpEL
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 a string value to the upper case, calculate a 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.
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}"/>
Sometimes there is a need to wire some constants 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
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}"/>
Insert random value
<bean id="myBean" class="x.y.z.MyBean">
<property name="randomValue" value="#{T(java.lang.Math).random()}" />
</bean>
Insert one of the predefined formats from java.time.format.DateTimeFormatter
class:
<property name="format"
value="#{T(java.time.format.DateTimeFormatter).BASIC_ISO_DATE}"/>
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 property prop
would get null
value if method()
returns null
.
Note that you will still get BeanCreationException
if you try to set null value to a property of the primitive type.
In the following example, strLength
will get the 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.
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}" />
Spring Expression Language also supports pattern matching with its matches
operator. The result of the matching operation is a boolean value: true
if the value matches 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 the string returned by otherMean.method()
is composed of digits, e.g., 12319845753123
.
As you could see, the Spring Expression Language is pretty 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 a list of useful things about SpEL can grow with next Spring releases.
Happy coding!