Skip to main content

Spring Expression Language (SpEL)

Introduction

Spring Expression Language (SpEL) is a powerful expression language that supports querying and manipulating an object graph at runtime. It provides a way to configure bean properties dynamically and is widely used across different components of the Spring Framework.

SpEL was introduced in Spring 3.0 and has become an integral part of Spring, especially when working with configuration. It offers features similar to other expression languages like OGNL (Object Graph Navigation Language) or JSF EL (JavaServer Faces Expression Language), but is specifically tailored to work seamlessly with Spring's infrastructure.

Basic Syntax and Features

SpEL expressions are typically enclosed in #{} (hash brackets) when used within Spring configuration files. This distinguishes them from property placeholders which use ${} (dollar brackets).

Simple Expressions

Let's start with some basic expressions:

java
// Literal expressions
"#{'Hello World'}" // Evaluates to "Hello World"
"#{1 + 2}" // Evaluates to 3

// Property access
"#{person.name}" // Accesses the name property of person object

Expression Evaluation in Java Code

To use SpEL programmatically in your Java code:

java
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class SpELDemo {
public static void main(String[] args) {
ExpressionParser parser = new SpelExpressionParser();

// Evaluate a simple expression
Expression exp = parser.parseExpression("'Hello World'");
String message = (String) exp.getValue();
System.out.println(message); // Output: Hello World

// Arithmetic operations
exp = parser.parseExpression("10 * 5");
Integer result = (Integer) exp.getValue();
System.out.println(result); // Output: 50
}
}

SpEL in Spring Configuration

One of the most common uses of SpEL is within Spring configuration files to define bean properties dynamically.

XML Configuration Example

xml
<bean id="mathCalculator" class="com.example.MathCalculator">
<property name="randomNumber" value="#{T(java.lang.Math).random() * 100.0}"/>
</bean>

Java Configuration Example

java
@Configuration
public class AppConfig {
@Bean
public MathCalculator mathCalculator() {
MathCalculator calculator = new MathCalculator();
calculator.setRandomNumber(Math.random() * 100.0);
return calculator;
}
}

Common SpEL Operators and Functions

Operators

SpEL supports various operators:

  • Arithmetic: +, -, *, /, %, ^
  • Relational: ==, !=, <, >, <=, >=
  • Logical: and, or, not
  • Conditional: ?: (ternary)
  • Regular Expression: matches

Examples

java
// Arithmetic
parser.parseExpression("2 + 2").getValue(Integer.class); // 4

// Relational
parser.parseExpression("1 == 1").getValue(Boolean.class); // true

// Logical
parser.parseExpression("true and false").getValue(Boolean.class); // false

// Ternary
parser.parseExpression("'test' == 'test' ? 'yes' : 'no'").getValue(String.class); // "yes"

// Regular expression
parser.parseExpression("'5.00' matches '^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class); // true

Type References

SpEL allows you to reference static methods and fields using the T() operator:

java
// Access static fields
parser.parseExpression("T(java.lang.Math).PI").getValue(Double.class); // 3.141592653589793

// Call static methods
parser.parseExpression("T(java.lang.Math).random()").getValue(Double.class); // Random value between 0.0 and 1.0

Working with Collections

SpEL provides powerful features for working with collections:

List Operations

java
// Create a list
Expression exp = parser.parseExpression("{'a', 'b', 'c', 'd'}");
List<String> list = (List<String>) exp.getValue();
// Output: [a, b, c, d]

// Access list elements (zero-based)
exp = parser.parseExpression("{'a', 'b', 'c', 'd'}[1]");
String item = (String) exp.getValue();
// Output: b

Map Operations

java
// Create a map
Expression exp = parser.parseExpression("{name:'John', age:25}");
Map<String, Object> map = (Map<String, Object>) exp.getValue();
// Output: {name=John, age=25}

// Access map elements
exp = parser.parseExpression("{name:'John', age:25}['name']");
String name = (String) exp.getValue();
// Output: John

Real-world Examples

Example 1: Conditional Bean Configuration

java
@Configuration
public class DatabaseConfig {
@Value("${app.environment}")
private String environment;

@Bean
public DataSource dataSource() {
DataSource ds = new BasicDataSource();

// Use SpEL to set different connection pools based on environment
ds.setMaxConnections(
environment.equals("production") ? 100 : 10
);

return ds;
}
}

Example 2: Using SpEL with Spring Security

SpEL is extensively used in Spring Security for method-level security:

java
@Service
public class UserService {

// Only allow access if the current user's username matches the requested username
@PreAuthorize("#username == authentication.principal.username")
public User loadUserDetails(String username) {
// Load and return user details
}

// Only administrators can delete users
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void deleteUser(Long userId) {
// Delete user logic
}
}

Example 3: Dynamic Property Value in Spring Boot

java
@Component
public class EmailService {

// Get email content from application properties based on the locale
@Value("#{systemProperties['user.language'] == 'fr' ? '${email.greeting.french}' : '${email.greeting.english}'}")
private String emailGreeting;

public void sendWelcomeEmail(String recipient) {
// Use emailGreeting which was dynamically set based on system locale
System.out.println("Sending email to " + recipient + " with greeting: " + emailGreeting);
}
}

SpEL in Annotations

SpEL is widely used in various Spring annotations:

@Value Annotation

The @Value annotation is one of the most common places where SpEL is used:

java
@Component
public class MathComponent {
// Inject a random number between 0 and 100
@Value("#{T(java.lang.Math).random() * 100.0}")
private double randomNumber;

// Inject a system property
@Value("#{systemProperties['user.name']}")
private String username;

// Combine property placeholder and SpEL
@Value("#{${server.max.threads} * 2}")
private int maxThreads;
}

@Cacheable Annotation

SpEL is also used in caching annotations to define dynamic keys:

java
@Service
public class ProductService {

@Cacheable(value = "products", key = "#id")
public Product getProductById(Long id) {
// Logic to fetch product from database
}

@Cacheable(value = "products", condition = "#price > 100")
public List<Product> getProductsByPrice(double price) {
// Only cache expensive products
}
}

Best Practices and Considerations

  1. Keep expressions simple: Complex expressions can be hard to read and maintain.
  2. Consider performance: Expression evaluation has overhead, so avoid using SpEL for performance-critical operations.
  3. Handle errors: Use proper error handling when evaluating expressions.
  4. Test thoroughly: Test SpEL expressions with different inputs to ensure they work correctly.
  5. Security considerations: Be cautious when using SpEL with user input to avoid security vulnerabilities.

Common Errors and Troubleshooting

Type Conversion Issues

java
// This might cause a ClassCastException if the expression doesn't evaluate to a String
String result = parser.parseExpression("1 + 2").getValue(String.class);

// Better approach
String result = parser.parseExpression("1 + 2").getValue().toString();

Null Safety

java
// This might cause a NullPointerException if person is null
parser.parseExpression("person.name").getValue(context);

// Safer approach using Elvis operator
parser.parseExpression("person?.name").getValue(context);

Summary

Spring Expression Language (SpEL) is a powerful feature of the Spring Framework that allows for dynamic expression evaluation at runtime. It provides a concise and flexible way to manipulate object graphs and supports a wide range of operations including arithmetic, logical, and relational operations, as well as method invocation and property access.

We've explored:

  • Basic syntax and features of SpEL
  • How to evaluate expressions programmatically
  • Using SpEL in Spring configuration
  • Working with collections and operators
  • Real-world examples and common use cases
  • Best practices and error handling

SpEL is used extensively throughout the Spring ecosystem, including Spring Core, Spring Security, and Spring Data, making it an essential skill for Spring developers.

Further Resources

Exercises

  1. Create a Spring Boot application that uses SpEL to dynamically configure a bean's property based on the running environment (dev, test, prod).
  2. Write a SpEL expression to filter a list of products based on their price and category.
  3. Implement a custom method in your application that can be called from SpEL expressions.
  4. Create a Spring Security configuration that uses SpEL to implement complex access control rules.
  5. Use SpEL with Spring's caching annotations to implement a dynamic caching strategy.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)