Spring Expression Language (SpEL) provides a powerful expression language for querying and manipulating object graphs at runtime.
npx @tessl/cli install tessl/maven-org-springframework--spring-expression@6.2.0The Spring Expression Language (SpEL) is a powerful expression language that supports querying and manipulating an object graph at runtime. It offers many features including method invocation, accessing/setting properties, array/collection/map indexing, conditional operators, variables, user-defined functions, and more.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>6.2.8</version>
</dependency>Gradle:
implementation 'org.springframework:spring-expression:6.2.8'// Core expression interfaces
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ParserContext;
// Standard SpEL implementation
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.standard.SpelExpression;
// Evaluation contexts
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
// Configuration
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.SpelCompilerMode;
// Value types
import org.springframework.expression.TypedValue;
import org.springframework.core.convert.TypeDescriptor;
// Exceptions
import org.springframework.expression.ExpressionException;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.ParseException;{ .api }
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();
// Returns: "Hello World"
// Mathematical expressions
Expression mathExp = parser.parseExpression("2 + 3 * 4");
Integer result = mathExp.getValue(Integer.class);
// Returns: 14{ .api }
public class Person {
private String name;
private int age;
// getters and setters...
}
Person person = new Person();
person.setName("John");
person.setAge(30);
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression("name");
String name = exp.getValue(person, String.class);
// Returns: "John"
// Property navigation
exp = parser.parseExpression("name.length()");
Integer length = exp.getValue(person, Integer.class);
// Returns: 4{ .api }
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(
"Hello #{name}, you are #{age} years old!",
ParserContext.TEMPLATE_EXPRESSION
);
EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();
String message = exp.getValue(context, person, String.class);
// Returns: "Hello John, you are 30 years old!"{ .api }
SpEL's architecture is built around several core abstractions:
The standard implementation uses reflection-based resolvers and supports compilation to bytecode for improved performance.
public interface ExpressionParser {
Expression parseExpression(String expressionString)
throws ParseException;
Expression parseExpression(String expressionString, ParserContext context)
throws ParseException;
}{ .api }
public interface Expression {
String getExpressionString();
// getValue methods
Object getValue() throws EvaluationException;
<T> T getValue(Class<T> desiredResultType) throws EvaluationException;
Object getValue(Object rootObject) throws EvaluationException;
<T> T getValue(Object rootObject, Class<T> desiredResultType) throws EvaluationException;
Object getValue(EvaluationContext context) throws EvaluationException;
<T> T getValue(EvaluationContext context, Class<T> desiredResultType) throws EvaluationException;
Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException;
<T> T getValue(EvaluationContext context, Object rootObject, Class<T> desiredResultType)
throws EvaluationException;
// getValueType methods
Class<?> getValueType() throws EvaluationException;
Class<?> getValueType(Object rootObject) throws EvaluationException;
Class<?> getValueType(EvaluationContext context) throws EvaluationException;
Class<?> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException;
// getValueTypeDescriptor methods
TypeDescriptor getValueTypeDescriptor() throws EvaluationException;
TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException;
TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException;
TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject)
throws EvaluationException;
// isWritable methods
boolean isWritable(Object rootObject) throws EvaluationException;
boolean isWritable(EvaluationContext context) throws EvaluationException;
boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException;
// setValue methods
void setValue(Object rootObject, Object value) throws EvaluationException;
void setValue(EvaluationContext context, Object value) throws EvaluationException;
void setValue(EvaluationContext context, Object rootObject, Object value)
throws EvaluationException;
}{ .api }
public class TypedValue {
public static final TypedValue NULL = new TypedValue(null);
public TypedValue(Object value);
public TypedValue(Object value, TypeDescriptor typeDescriptor);
public Object getValue();
public TypeDescriptor getTypeDescriptor();
public boolean equals(Object other);
public int hashCode();
public String toString();
}{ .api }
public interface EvaluationContext {
// Root object access
TypedValue getRootObject();
// Accessor chains (default implementations return empty lists)
List<PropertyAccessor> getPropertyAccessors();
List<IndexAccessor> getIndexAccessors(); // since 6.2
List<ConstructorResolver> getConstructorResolvers();
List<MethodResolver> getMethodResolvers();
// Specialized resolvers
BeanResolver getBeanResolver();
TypeLocator getTypeLocator();
TypeConverter getTypeConverter();
TypeComparator getTypeComparator();
OperatorOverloader getOperatorOverloader();
// Variable management
void setVariable(String name, Object value);
Object lookupVariable(String name);
// Assignment support (default implementation)
TypedValue assignVariable(String name, Supplier<TypedValue> valueSupplier); // since 5.2.24
boolean isAssignmentEnabled(); // since 5.3.38
}{ .api }
For detailed information about expression evaluation capabilities, see Expression Evaluation.
public class SpelParserConfiguration {
public static final int DEFAULT_MAX_EXPRESSION_LENGTH = 10000;
public static final String SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME =
"spring.expression.compiler.mode";
public SpelParserConfiguration();
public SpelParserConfiguration(SpelCompilerMode compilerMode, ClassLoader compilerClassLoader);
public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections);
public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections,
int maximumAutoGrowSize);
public SpelParserConfiguration(SpelCompilerMode compilerMode, ClassLoader compilerClassLoader,
boolean autoGrowNullReferences, boolean autoGrowCollections,
int maximumAutoGrowSize);
public SpelParserConfiguration(SpelCompilerMode compilerMode, ClassLoader compilerClassLoader,
boolean autoGrowNullReferences, boolean autoGrowCollections,
int maximumAutoGrowSize, int maximumExpressionLength);
public SpelCompilerMode getCompilerMode();
public ClassLoader getCompilerClassLoader();
public boolean isAutoGrowNullReferences();
public boolean isAutoGrowCollections();
public int getMaximumAutoGrowSize();
public int getMaximumExpressionLength();
}{ .api }
public enum SpelCompilerMode {
OFF, // No compilation, interpreted mode only (default)
IMMEDIATE, // Compile immediately after first interpretation
MIXED // Switch between interpreted and compiled modes as needed
}{ .api }
For comprehensive configuration details, see SpEL Configuration.
SpEL provides two main evaluation context implementations:
// Read-only data binding
SimpleEvaluationContext context = SimpleEvaluationContext
.forReadOnlyDataBinding()
.build();
// Read-write data binding with method access
SimpleEvaluationContext context = SimpleEvaluationContext
.forReadWriteDataBinding()
.withInstanceMethods()
.withArrayAccess()
.build();{ .api }
StandardEvaluationContext context = new StandardEvaluationContext();
context.setRootObject(myObject);
context.setVariable("myVar", "Hello World");
context.registerFunction("reverse",
StringUtils.class.getDeclaredMethod("reverse", String.class));{ .api }
For complete evaluation context documentation, see Evaluation Contexts.
SpEL supports flexible property and index access through configurable accessors:
public interface PropertyAccessor extends TargetedAccessor {
boolean canRead(EvaluationContext context, Object target, String name)
throws AccessException;
TypedValue read(EvaluationContext context, Object target, String name)
throws AccessException;
boolean canWrite(EvaluationContext context, Object target, String name)
throws AccessException;
void write(EvaluationContext context, Object target, String name, Object newValue)
throws AccessException;
}{ .api }
public interface IndexAccessor extends TargetedAccessor {
boolean canRead(EvaluationContext context, Object target, Object index)
throws AccessException;
TypedValue read(EvaluationContext context, Object target, Object index)
throws AccessException;
boolean canWrite(EvaluationContext context, Object target, Object index)
throws AccessException;
void write(EvaluationContext context, Object target, Object index, Object newValue)
throws AccessException;
}{ .api }
For details on property and index access, see Property and Index Access.
SpEL supports method invocation and object construction through resolvers:
@FunctionalInterface
public interface MethodResolver {
MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
List<TypeDescriptor> argumentTypes) throws AccessException;
}{ .api }
public interface ConstructorResolver {
ConstructorExecutor resolve(EvaluationContext context, String typeName,
List<TypeDescriptor> argumentTypes) throws AccessException;
}{ .api }
For method and constructor resolution details, see Method and Constructor Resolution.
SpEL provides extensive type system support through various interfaces:
public interface TypeConverter {
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
Object convertValue(Object value, TypeDescriptor sourceType, TypeDescriptor targetType)
throws TypeConversionException;
}{ .api }
public interface TypeLocator {
Class<?> findType(String typeName) throws EvaluationException;
}{ .api }
For complete type system documentation, see Type System Support.
SpEL provides a comprehensive exception hierarchy for error handling:
public abstract class ExpressionException extends RuntimeException {
protected String expressionString;
protected int position = -1;
public String getExpressionString();
public int getPosition();
public String toDetailedString();
public String getSimpleMessage();
}{ .api }
For comprehensive error handling information, see Error Handling.
SpelParserConfiguration config = new SpelParserConfiguration(
SpelCompilerMode.IMMEDIATE,
Thread.currentThread().getContextClassLoader()
);
SpelExpressionParser parser = new SpelExpressionParser(config);
SpelExpression expression = parser.parseRaw("name.toUpperCase()");
// Expression will be compiled to bytecode after first evaluation{ .api }
StandardEvaluationContext context = new StandardEvaluationContext();
context.setVariable("greeting", "Hello");
context.registerFunction("randomInt",
Math.class.getDeclaredMethod("random"));
Expression exp = parser.parseExpression("#greeting + ' ' + #randomInt() * 100");{ .api }
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
Expression exp = parser.parseExpression("@myBean.someMethod()");{ .api }
For detailed coverage of advanced features, see Advanced Features.