Spring Expression Language SpEL

spring-framework-expression-language-spel-feature-image

Spring Expression Language (SpEL) is a powerful expression language that supports querying and manipulating an object graph at runtime.

This tutorial shows various examples of ways to use SpEL expressions with XML and annotation based configuration. We also know how to evaluate an expression using SpEL classes and interfaces.

I. Overview

In both cases: XML based configuration and Annotation based configuration, the syntax to define the expression is: #{ expression.. }

1. XML based configuration
	
		
		
		
	
2. Annotation based configuration
	@Value("#{0xFFFF}")
	private int a;
	
	@Value("#{null}")
	private Object object;

	@Value("#{'xyz' instanceof T(Integer)}")
	private boolean b;
3. Expression Evaluation

SpEL classes and interfaces are located in the packages org.springframework.expression. We parse an expression string by using interface ExpressionParser and evaluate it by using interface Expression.

		ExpressionParser parser = new SpelExpressionParser();

		Expression exp = parser.parseExpression("'Java Sample Approach'");
		String message = (String) exp.getValue();
		System.out.println(message);

		exp = parser.parseExpression("'Java Sample Approach'.concat('.com')");
		message = (String) exp.getValue();
		System.out.println(message);

We can catch a ParseException when calling parser.parseExpression() or a EvaluationException when calling exp.getValue().

II. Functionality
– mathematical, logical, relational or ternary operators
	// mathematical operator
	@Value("#{42 % 10}")
	private int modulo; // 2

	@Value("#{2 ^ 8}")
	private double power; // 256.0

	// logical operator
	@Value("#{!true}")
	private boolean not; // false

	// logical and relational operator
	@Value("#{123 > 100 && 100 <= 111}")
	private boolean and; // true

	// ternary operator
	@Value("#{ (50^2/40) > 50? 'right' : 'wrong' }")
	private String ternary; // right

We can also use XML based configuration for cases in which annotation based configuration is OK.
For example:

	
		
		
	
– regular expressions with matches
	// regular expression
	@Value("#{'Java Sample Approach' matches '[a-zA-Z\\s]+' }")
	private boolean regex; // true

	// regular expression
	@Value("#{'Java Sample Approach 2015' matches '[a-zA-Z\\s]+' }")
	private boolean invalidRegex; // false
– access properties

SpEL supports nested properties with standard syntax: object.prop1.prop2.prop3

		ExpressionParser parser = new SpelExpressionParser();

		exp = parser.parseExpression("'Java Sample Approach'.bytes.length");
		int length = (int) exp.getValue(); // 20

Another way to get properties is using EvaluationContext, we can also set property value:

public class Customer {
	private String firstName;
	private String lastName;
	public int age;

	// constructors, getters and setters
}

public class ExpressionEvaluation {
	public static void run() {
		Customer customer = new Customer("Adam", "Johnson");

		ExpressionParser parser = new SpelExpressionParser();

		exp = parser.parseExpression("firstName");
		EvaluationContext eContext = new StandardEvaluationContext(customer);
		String firstName = (String) exp.getValue(eContext); // Adam

		// without Context
		exp = parser.parseExpression("lastName");
		String lastName = (String) exp.getValue(customer); // Johnson

		// set Value
		parser.parseExpression("age").setValue(eContext, 42);
		// customer.age = 42
}

To access resource properties myapp.properties:

config.string.key=stringValue
config.string.keyNull=This is NULL
config.int.key=1886
config.boolean.key=true

We can use SpEL by this way:

	
		
		
		
	
	
	

Run the example, we will get the result:

Display [a=stringValue, b=1886, c=true]
– invoking constructors

The example will construct new String and new Customer object with constructor methods.

		ExpressionParser parser = new SpelExpressionParser();
		exp = parser.parseExpression("new String('Java Sample Approach')");
		message = exp.getValue(String.class); // Java Sample Approach

		Customer myCustomer = parser.parseExpression(
				"new com.javasampleapproach.spel.bean.Customer('Jack', 'Smith', 26)")
				.getValue(Customer.class);
		// Customer [firstName=Jack, lastName=Smith, age=26]
– array constructions
		// array construction
		int[] arr1 = (int[]) parser.parseExpression("new int[4]").getValue();
		System.out.println(arr1.length); // 4

		// with initializer
		int[] arr2 = (int[]) parser.parseExpression("new int[]{1,2,3}").getValue();
		System.out.println(arr2.length); // 3
– inline Lists and Maps
		// inline list
		List numbers = (List) parser.parseExpression("{1,2,3}").getValue();
		System.out.println(numbers); // [1, 2, 3]
		
		// inline Map
		Map customerInfo = (Map) parser.parseExpression(
				"{name:'Adam Johnson', age:'42'}")
				.getValue();
		System.out.println(customerInfo); // {name=Adam Johnson, age=42}
		
		Map mapOfMaps = (Map) parser.parseExpression(
				"{name:{first:'Adam',last:'Johnson'}, birthday:{day:19, month:'Aug', year:1974}}")
				.getValue();
		System.out.println(mapOfMaps);
		// {name={first=Adam, last=Johnson}, birthday={day=19, month=Aug, year=1974}}
– access List and Map objects

Assume that we need to get item from List and Map of an object:

@Component("customersInfo")
public class CustomersInfo {
	private List customers = new ArrayList<>();
	private Map remainYearTimes = new HashMap<>();

	public CustomersInfo() {
		customers.add("Adam Johnson");
		customers.add("Jack Smith");
		customers.add("David Williams");
		customers.add("Kim Smith");
		customers.add("Peter Davis");
		
		remainYearTimes.put("Adam", 1);
		remainYearTimes.put("Jack", 2);
		remainYearTimes.put("David", 3);
		remainYearTimes.put("Kim", 4);
		remainYearTimes.put("Peter", 5);
	}

	// getters and setters
}

By using annotation-based configuration:

@Configuration
@ComponentScan("com.javasampleapproach.spel.bean")
public class AppConfig {
	
	// list
	@Value("#{customersInfo.customers[0]}")
	private String list; // Adam Johnson
	
	// map
	@Value("#{customersInfo.remainYearTimes['Adam']}")
	private String map; // 1
}

By using xml-based configuration:

	



	
		
		
	
– method invocation

The example will invoke method substring() and toUpperCase() in expression.

		String subString = parser.parseExpression(
				"'Java Sample Approach'.substring(0, 4).toUpperCase()")
				.getValue(String.class);
		System.out.println(subString);
		// JAVA
– collection selection and projection

Selection is a powerful feature. We can get a new Collection by selecting entries from an old Collection.
Syntax: collection.?[selectionExpression]
Projection allows a collection to drive the evaluation of a sub-expression and the result is a new collection with evaluation content.
Syntax: collection.![projectionExpression]

	// collection
	@Value("#{customersInfo.remainYearTimes}")
	private Map remainYearTimes;
	// {Adam=1, David=3, Peter=5, Jack=2, Kim=4}

	// collection selection
	@Value("#{customersInfo.remainYearTimes.?[value > 2]}")
	private Map mapSelection;
	// {David=3, Peter=5, Kim=4}

	// collection projection
	@Value("#{customersInfo.remainYearTimes.![value > 2]}")
	private List mapProjection;
	// [false, true, true, false, true]

The example gets a new collection (Map) in which all remainYearTimes are larger than 2, then evaluates with a List of Boolean value in which each item is a evaluated result of corresponding item in the old collection.

– assignment

In the example about access properties above, we assign a value to a property using setValue()

		parser.parseExpression("age").setValue(eContext, 42);

Now we can also assign with clearer expression String: age = 43 using getValue()

		// Customer [firstName=Adam, lastName=Johnson, age=42]

		// assignment
		parser.parseExpression("age = 43").getValue(eContext, Integer.class);
		// Customer [firstName=Adam, lastName=Johnson, age=43]
– types

T operator can be used to specify an instance of java.lang.Class.

	@Value("#{T(Integer)}")
	private Class type; // class java.lang.Integer

We can also invoke Static methods of this class instance.

	
		
		
	
– bean references

SpEL can be used to reference to a Bean or field/method of that Bean.

	
		
		
		
	

	
		
		
		
	

	
		
		
	

service bean references to anotherCustomer bean.
anotherCustomer bean references to newCustomer bean method getAge() and field lastName.
Run the example, we will get the result similar this (depending on random value, we will get different results):

Customer [firstName=Adam, lastName=Bale, age=7]
Customer [firstName=Smith, lastName=Bale, age=16]
CustomerService [name=SERVICE FOR VIP, customer=Customer [firstName=Smith, lastName=Bale, age=16]]
III. Source code
1. Technology

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.1.RELEASE (It’s OK if you use Eclipse)

2. Project Structure

spel-structure

3. Download Link

spring-expression-language

4. Check results

– Config maven build:
clean install
– Run project with mode Java Application
– Check results in Console Screen.



By grokonez | November 10, 2016.

Last updated on September 25, 2018.



Related Posts


    Got Something To Say:

    Your email address will not be published. Required fields are marked *

    *