The Spring Expression Language (SpEL) is an expression language that supports querying and manipulating an object graph at runtime. In this post we'll see examples of using SpEL with both XML and annotation based configuration.
The expression language supports the following functionality:
- Literal expressions
- Boolean, relational and mathematical operators
- Regular expressions
- Class expressions
- Accessing properties, arrays, lists, and maps
- Method invocation
- Assignment
- Calling constructors
- Bean references
- Inline lists
- Inline maps
- Ternary operator
SpEL expressions in Bean Definitions
Syntax to define the expression is of the form #{ <expression string> }. For example assigning a literal expression using SpEL.
If using XML configuration
<bean id="address" class="com.knpcode.springproject.Address"> <property name="pinCode" value = "#{'110001'}" /> </bean>
If using @Value annotation
@Component public class Address { ... ... @Value("#{'302001'}") private String pinCode; ... ... }
SpEL Relational operators
SpEL supports the following relational operators. You can use the symbol or alphabetic equivalent (in case of XML document)
- lt (<)
- gt (>)
- le (<=)
- ge (>=)
- eq (==)
- ne (!=)
- not (!)
@Component public class Values { @Value("#{6 < 7}") private boolean valueLessThan; @Value("#{6 == 7}") private boolean valueEqual; @Value("#{6 == 7}") private boolean valueNotEqual; // Using alphabetic @Value("#{6 ge 7}") private boolean valueGreaterEqual; public boolean isValueLessThan() { return valueLessThan; } public boolean isValueEqual() { return valueEqual; } public boolean isValueNotEqual() { return valueNotEqual; } public boolean isValueGreaterEqual() { return valueGreaterEqual; } }Output
isValueLessThan()-true isValueEqual()-false isValueNotEqual()-false isValueGreaterEqual()-false
SpEL Logical operators
SpEL supports the following logical operators. You can use the symbol or alphabetic equivalent.
- and (&&)
- or (||)
- not (!)
@Component public class Values { @Value("#{6 < 7 && 7 < 8} ") private boolean valueLessThan; @Value("#{6 == 7 and 7 == 7}") private boolean valueEqual; @Value("#{6 != 7 || 8 != 8}") private boolean valueNotEqual; @Value("#{!(6 lt 7)}") private boolean valueNotOperator; public boolean isValueLessThan() { return valueLessThan; } public boolean isValueEqual() { return valueEqual; } public boolean isValueNotEqual() { return valueNotEqual; } public boolean isValueNotOperator() { return valueNotOperator; } }Output
isValueLessThan()-true isValueEqual()-false isValueNotEqual()-true isValueNotOperator()-false
SpEL Mathematical operators
SpEL supports the following mathematical operators.
- addition operator (+) can be used with both numbers and strings.
- subtraction operator (-)
- multiplication operator (*)
- division operator (/)
- modulus (%)
- exponential power (^)
Subtraction, multiplication, and division operators can be used only on numbers.
SpEL Mathematical operators example@Component public class Values { @Value("#{6 + 8} ") private int valueAddition; @Value("#{'Hello ' + 'World'}") private String valueStringAddition; @Value("#{17 div 5}") private int valueDivision; @Value("#{17 % 5}") private int valueModDivision; @Value("#{2^3}") private double valuePower; public int getValueAddition() { return valueAddition; } public String getValueStringAddition() { return valueStringAddition; } public int getValueDivision() { return valueDivision; } public int getValueModDivision() { return valueModDivision; } public double getValuePower() { return valuePower; } }Output
valueAddition- 14 valueStringAddition- Hello World valueDivision- 3 valueModDivision- 2 valuePower- 8.0
SpEL Bean reference and Method invocation example
In this example we’ll see how to reference a bean and how to invoke a method on a bean using Spring expression language. For that we’ll have two classes Person and Address and Person will have Address bean reference.
Address classimport org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class Address { @Value("100") private String houseNo; @Value("The Mall") private String street; @Value("Shimla") private String city; @Value("HP") private String state; // As SpEL literal @Value("#{'171004'}") private String pinCode; public String getHouseNo() { return houseNo; } public String getStreet() { return street; } public String getCity() { return city; } public String getState() { return state; } public String getPinCode() { return pinCode; } public void setHouseNo(String houseNo) { this.houseNo = houseNo; } public void setStreet(String street) { this.street = street; } public void setCity(String city) { this.city = city; } public void setState(String state) { this.state = state; } public void setPinCode(String pinCode) { this.pinCode = pinCode; } }Person class
import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class Person { @Value("#{'Suresh'}") private String name; @Value("34") private int age; // SpEL Bean reference @Value("#{address}") private Address address; @Value("#{address.city}") private String personCity; // SpEL Method invocation @Value("#{person.getInfo()}") private String personInfo; public String getName() { return name; } public int getAge() { return age; } public Address getAddress() { return address; } public String getPersonCity() { return personCity; } public String getPersonInfo() { return personInfo; } public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } public void setAddress(Address address) { this.address = address; } public void setPersonCity(String personCity) { this.personCity = personCity; } public void setPersonInfo(String personInfo) { this.personInfo = personInfo; } public String getInfo(){ return getName() + " - Address " + getAddress().getHouseNo() + ", " + getAddress().getStreet() + ", " + getAddress().getCity() + ", " + getAddress().getState() + ", " + getAddress().getPinCode(); } }Output
Person State HP Person City Shimla Person Info Suresh - Address 100, The Mall, Shimla, HP, 171004
XML configuration with SpEL expressions for the same beans can be done as given below, note that one difference is that getInfo() method is in Address bean.
<?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" 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"> <bean id="address" class="com.knpcode.springexample.Address"> <property name="houseNo" value = "100" /> <property name="street" value = "The Mall" /> <property name="city" value = "Shimla" /> <property name="state" value = "HP" /> <property name="pinCode" value = "#{'171004'}" /> </bean> <bean id="person" class="com.knpcode.springexample.Person"> <property name="name" value = "#{'Suresh'}" /> <!-- Bean reference through SpEL --> <property name="address" value = "#{address}" /> <property name="personCity" value = "#{address.city}" /> <!-- SpEL Method invocation--> <property name="personInfo" value = "#{address.getInfo()}" /> </bean> </beans>
The safe navigation operator is used to avoid a NullPointerException. Typically, when you have a reference to an object, you might need to verify that it is not null before accessing methods or properties of the object. The safe navigation operator returns null, if an object reference is null, instead of throwing an exception.
For example there is an Address class with properties as given below. Note that city doesn’t have any value.
@Component public class Address { @Value("100") private String houseNo; @Value("The Mall") private String street; private String city; @Value("HP") private String state; // As SpEL literal @Value("#{'171004'}") private String pinCode;
Now you try to get the city in personCity property of the Person class and change it to all upper case.
@Component public class Person { @Value("#{'Suresh'}") private String name; @Value("34") private int age; // SpEL Bean reference @Value("#{address}") private Address address; @Value("#{address.city.toUpperCase()}") private String personCity;
This assignment throws UnsatisfiedDependencyException as city itself is returned as null.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'person': Unsatisfied dependency expressed through field 'personCity'; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1011E: Method call: Attempted to call method toUpperCase() on null context object
To avoid the exception safe navigation operator (?.) can be used, now personCity itself is returned as null.
@Value("#{address.city?.toUpperCase()}") private String personCity;
SpEL Ternary and Elvis operators
You can use the ternary operator for performing if-then-else conditional logic inside the expression.
@Component public class Values { @Value("#{10} ") private int value1; @Value("#{20}") private int value2; @Value("#{30}") private int value3; public int getValue1() { return value1; } public int getValue2() { return value2; } public int getValue3() { return value3; } public void setValue1(int value1) { this.value1 = value1; } public void setValue2(int value2) { this.value2 = value2; } public void setValue3(int value3) { this.value3 = value3; } }
In the ConditionOps class value for the property ternaryValue is calculated using SpEL ternary operator. If value1 is greater than value3 then ternaryValue is equal to value1 otherwise it is equal to value3.
@Component public class ConditionOps { @Value("#{values.value1 gt values.value3 ? values.value1 : values.value3 }") private int ternaryValue; public int getTernaryValue() { return ternaryValue; } public void setTernaryValue(int ternaryValue) { this.ternaryValue = ternaryValue; } }SpEL Elvis operator example
The Elvis operator is a shortening of the ternary operator syntax. With the ternary operator syntax, you usually have to repeat a variable twice when checking if the variable is null and then return the variable if not null or a default value if null.
@Value("#{values.name != null ? values.name : \"Unknown\"}") private String displayName;
In such scenario you can use the Elvis operator-
@Value("#{values.name ?: \"Unknown\"}") private String displayName;
SpEL with regular expression
SpEL uses matches operator with regular expression. The matches operator returns true if regular expression matches the given value otherwise false.
@Value("#{values.email matches '[a-zA-Z0-9._]+@[a-zA-Z0-9]+\\.com'}") private boolean isEmail;
That's all for the topic Spring Expression Language (SpEL) Tutorial. If something is missing or you have something to share about the topic please write a comment.
You may also like
- Spring Dependency Injection With Examples
- Injecting Prototype Bean into a Singleton Bean in Spring
- Spring Data JPA Example
- ThreadLocal Class in Java With Examples
- ZonedDateTime in Java With Examples
- File Name Same as Class Name in Java
- Name Mangling in Python With Examples
- React App Flow - create-react-app Structure
No comments:
Post a Comment