Spring Expression Language (SpEL) provides a powerful expression language for querying and manipulating object graphs at runtime.
—
This document covers SpEL's expression evaluation capabilities, including the core interfaces, standard implementations, and evaluation patterns.
public class SpelExpressionParser extends TemplateAwareExpressionParser {
public SpelExpressionParser();
public SpelExpressionParser(SpelParserConfiguration configuration);
public SpelExpression parseRaw(String expressionString) throws ParseException;
// Inherited from ExpressionParser:
public Expression parseExpression(String expressionString) throws ParseException;
public Expression parseExpression(String expressionString, ParserContext context)
throws ParseException;
}{ .api }
The SpelExpressionParser is thread-safe and should be reused across multiple parsing operations for better performance.
public class SpelExpression implements Expression {
// Configuration
public void setEvaluationContext(EvaluationContext evaluationContext);
public EvaluationContext getEvaluationContext();
// Compilation
public boolean compileExpression();
public void revertToInterpreted();
// AST Access
public SpelNode getAST();
public String toStringAST();
// Expression Interface Methods
public String getExpressionString();
public Object getValue() throws EvaluationException;
public <T> T getValue(Class<T> desiredResultType) throws EvaluationException;
public Object getValue(Object rootObject) throws EvaluationException;
public Object getValue(EvaluationContext context) throws EvaluationException;
public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException;
public <T> T getValue(EvaluationContext context, Object rootObject, Class<T> expectedResultType)
throws EvaluationException;
public Class<?> getValueType() throws EvaluationException;
public Class<?> getValueType(Object rootObject) throws EvaluationException;
public Class<?> getValueType(EvaluationContext context) throws EvaluationException;
public Class<?> getValueType(EvaluationContext context, Object rootObject)
throws EvaluationException;
public TypeDescriptor getValueTypeDescriptor() throws EvaluationException;
public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException;
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException;
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject)
throws EvaluationException;
public boolean isWritable(Object rootObject) throws EvaluationException;
public boolean isWritable(EvaluationContext context) throws EvaluationException;
public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException;
public void setValue(Object rootObject, Object value) throws EvaluationException;
public void setValue(EvaluationContext context, Object value) throws EvaluationException;
public void setValue(EvaluationContext context, Object rootObject, Object value)
throws EvaluationException;
}{ .api }
public interface ParserContext {
boolean isTemplate();
String getExpressionPrefix();
String getExpressionSuffix();
// Constants
ParserContext TEMPLATE_EXPRESSION = new TemplateParserContext();
}{ .api }
public class TemplateParserContext implements ParserContext {
public TemplateParserContext();
public TemplateParserContext(String expressionPrefix, String expressionSuffix);
public boolean isTemplate();
public String getExpressionPrefix();
public String getExpressionSuffix();
}{ .api }
public class LiteralExpression implements Expression {
public LiteralExpression(String literalValue);
public String getExpressionString();
public Object getValue() throws EvaluationException;
public <T> T getValue(Class<T> expectedResultType) throws EvaluationException;
public Object getValue(Object rootObject) throws EvaluationException;
public Object getValue(EvaluationContext context) throws EvaluationException;
public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException;
public <T> T getValue(EvaluationContext context, Object rootObject, Class<T> expectedResultType)
throws EvaluationException;
public Class<?> getValueType();
public Class<?> getValueType(Object rootObject);
public Class<?> getValueType(EvaluationContext context);
public Class<?> getValueType(EvaluationContext context, Object rootObject);
public TypeDescriptor getValueTypeDescriptor();
public TypeDescriptor getValueTypeDescriptor(Object rootObject);
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context);
public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject);
public boolean isWritable(Object rootObject);
public boolean isWritable(EvaluationContext context);
public boolean isWritable(EvaluationContext context, Object rootObject);
public void setValue(Object rootObject, Object value);
public void setValue(EvaluationContext context, Object value);
public void setValue(EvaluationContext context, Object rootObject, Object value);
}{ .api }
public class CompositeStringExpression implements Expression {
public CompositeStringExpression(String expressionString, Expression[] expressions);
// Implements all Expression interface methods
// Evaluates each sub-expression and concatenates results as strings
}{ .api }
ExpressionParser parser = new SpelExpressionParser();
// Literals
Expression exp = parser.parseExpression("'Hello World'");
String result = exp.getValue(String.class); // "Hello World"
exp = parser.parseExpression("42");
Integer number = exp.getValue(Integer.class); // 42
exp = parser.parseExpression("true");
Boolean bool = exp.getValue(Boolean.class); // true
// Mathematical operations
exp = parser.parseExpression("2 + 3 * 4");
Integer math = exp.getValue(Integer.class); // 14
exp = parser.parseExpression("10 / 3.0");
Double division = exp.getValue(Double.class); // 3.3333333333333335
// String operations
exp = parser.parseExpression("'Hello' + ' ' + 'World'");
String concat = exp.getValue(String.class); // "Hello World"
// Logical operations
exp = parser.parseExpression("true and false");
Boolean logical = exp.getValue(Boolean.class); // false
exp = parser.parseExpression("2 > 1 ? 'yes' : 'no'");
String conditional = exp.getValue(String.class); // "yes"{ .api }
public class Person {
private String name;
private int age;
private Address address;
// getters and setters...
}
public class Address {
private String city;
private String country;
// getters and setters...
}
Person person = new Person();
person.setName("John");
person.setAge(30);
ExpressionParser parser = new SpelExpressionParser();
// Direct property access
Expression exp = parser.parseExpression("name");
String name = exp.getValue(person, String.class); // "John"
// Method invocation
exp = parser.parseExpression("name.toUpperCase()");
String upperName = exp.getValue(person, String.class); // "JOHN"
// Nested property access
exp = parser.parseExpression("address?.city");
String city = exp.getValue(person, String.class); // null (safe navigation)
// Property assignment (requires StandardEvaluationContext)
StandardEvaluationContext context = new StandardEvaluationContext(person);
exp = parser.parseExpression("name");
exp.setValue(context, "Jane");{ .api }
List<String> names = Arrays.asList("John", "Jane", "Bob");
Map<String, Integer> ages = Map.of("John", 30, "Jane", 25, "Bob", 35);
int[] numbers = {1, 2, 3, 4, 5};
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("names", names);
context.setVariable("ages", ages);
context.setVariable("numbers", numbers);
// List access
Expression exp = parser.parseExpression("#names[0]");
String firstName = exp.getValue(context, String.class); // "John"
// Map access
exp = parser.parseExpression("#ages['John']");
Integer age = exp.getValue(context, Integer.class); // 30
// Array access
exp = parser.parseExpression("#numbers[2]");
Integer number = exp.getValue(context, Integer.class); // 3
// Collection methods
exp = parser.parseExpression("#names.size()");
Integer size = exp.getValue(context, Integer.class); // 3
// Collection filtering and projection
exp = parser.parseExpression("#names.?[length() > 3]"); // Filter
List<String> filtered = (List<String>) exp.getValue(context); // ["John", "Jane"]
exp = parser.parseExpression("#names.![toUpperCase()]"); // Projection
List<String> projected = (List<String>) exp.getValue(context); // ["JOHN", "JANE", "BOB"]{ .api }
StandardEvaluationContext context = new StandardEvaluationContext();
// Setting variables
context.setVariable("greeting", "Hello");
context.setVariable("name", "World");
// Using variables
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("#greeting + ' ' + #name");
String message = exp.getValue(context, String.class); // "Hello World"
// Registering functions
context.registerFunction("reverse",
String.class.getDeclaredMethod("valueOf", Object.class));
exp = parser.parseExpression("#reverse('hello')");
String reversed = exp.getValue(context, String.class);
// Built-in variables (when available)
exp = parser.parseExpression("#this"); // Current object
exp = parser.parseExpression("#root"); // Root object{ .api }
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
// Type references
Expression exp = parser.parseExpression("T(java.lang.Math).PI");
Double pi = exp.getValue(context, Double.class); // 3.141592653589793
exp = parser.parseExpression("T(java.lang.Math).max(2, 3)");
Integer max = exp.getValue(context, Integer.class); // 3
// Constructor invocation
exp = parser.parseExpression("new java.util.Date()");
Date date = exp.getValue(context, Date.class);
exp = parser.parseExpression("new String('hello').toUpperCase()");
String upper = exp.getValue(context, String.class); // "HELLO"{ .api }
ExpressionParser parser = new SpelExpressionParser();
Map<String, Object> vars = new HashMap<>();
vars.put("name", "John");
vars.put("age", 30);
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariables(vars);
// Template with multiple expressions
String template = "Hello #{#name}, you are #{#age} years old and next year you'll be #{#age + 1}!";
Expression exp = parser.parseExpression(template, ParserContext.TEMPLATE_EXPRESSION);
String result = exp.getValue(context, String.class);
// "Hello John, you are 30 years old and next year you'll be 31!"{ .api }
public class Customer {
private Address address;
// getters and setters...
}
Customer customer = new Customer(); // address is null
ExpressionParser parser = new SpelExpressionParser();
// Safe navigation operator (?.): prevents NullPointerException
Expression exp = parser.parseExpression("address?.city");
String city = exp.getValue(customer, String.class); // null (no exception)
// Without safe navigation (would throw NullPointerException)
// exp = parser.parseExpression("address.city"); // Throws exception{ .api }
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("name", null);
// Elvis operator (?:): provides default value for null
Expression exp = parser.parseExpression("#name ?: 'Unknown'");
String name = exp.getValue(context, String.class); // "Unknown"
context.setVariable("name", "John");
name = exp.getValue(context, String.class); // "John"{ .api }
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("text", "Hello World");
// Pattern matching
Expression exp = parser.parseExpression("#text matches '[A-Z].*'");
Boolean matches = exp.getValue(context, Boolean.class); // true
// Case-insensitive matching
exp = parser.parseExpression("#text matches '(?i)hello.*'");
matches = exp.getValue(context, Boolean.class); // true{ .api }
// Enable compilation for better performance
SpelParserConfiguration config = new SpelParserConfiguration(
SpelCompilerMode.IMMEDIATE,
Thread.currentThread().getContextClassLoader()
);
SpelExpressionParser parser = new SpelExpressionParser(config);
SpelExpression expression = parser.parseRaw("name.toUpperCase() + age.toString()");
// First evaluation interprets the expression
String result1 = expression.getValue(person, String.class);
// Subsequent evaluations use compiled bytecode (much faster)
String result2 = expression.getValue(person, String.class);
// Check if expression is compiled
boolean isCompiled = expression.compileExpression(); // true if successfully compiled
// Revert to interpreted mode if needed
expression.revertToInterpreted();{ .api }
// Cache frequently used expressions
public class ExpressionCache {
private final Map<String, Expression> cache = new ConcurrentHashMap<>();
private final ExpressionParser parser = new SpelExpressionParser();
public Expression getExpression(String expressionString) {
return cache.computeIfAbsent(expressionString, parser::parseExpression);
}
}
// Usage
ExpressionCache cache = new ExpressionCache();
Expression exp = cache.getExpression("name.toUpperCase()");
String result = exp.getValue(person, String.class);{ .api }
Install with Tessl CLI
npx tessl i tessl/maven-org-springframework--spring-expression