0
# SpEL Configuration
1
2
This document covers SpEL's configuration capabilities, including parser configuration, compiler settings, and performance tuning options.
3
4
## Parser Configuration
5
6
### SpelParserConfiguration Class
7
8
```java
9
public class SpelParserConfiguration {
10
// Constants
11
public static final int DEFAULT_MAX_EXPRESSION_LENGTH = 10000;
12
public static final String SPRING_EXPRESSION_COMPILER_MODE_PROPERTY_NAME =
13
"spring.expression.compiler.mode";
14
15
// Constructors
16
public SpelParserConfiguration();
17
public SpelParserConfiguration(SpelCompilerMode compilerMode, ClassLoader compilerClassLoader);
18
public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections);
19
public SpelParserConfiguration(boolean autoGrowNullReferences, boolean autoGrowCollections,
20
int maximumAutoGrowSize);
21
public SpelParserConfiguration(SpelCompilerMode compilerMode, ClassLoader compilerClassLoader,
22
boolean autoGrowNullReferences, boolean autoGrowCollections,
23
int maximumAutoGrowSize, int maximumExpressionLength);
24
25
// Accessors
26
public SpelCompilerMode getCompilerMode();
27
public ClassLoader getCompilerClassLoader();
28
public boolean isAutoGrowNullReferences();
29
public boolean isAutoGrowCollections();
30
public int getMaximumAutoGrowSize();
31
public int getMaximumExpressionLength();
32
}
33
```
34
{ .api }
35
36
### Basic Configuration Examples
37
38
```java
39
// Default configuration
40
SpelParserConfiguration defaultConfig = new SpelParserConfiguration();
41
42
// Configuration with compilation enabled
43
SpelParserConfiguration compiledConfig = new SpelParserConfiguration(
44
SpelCompilerMode.IMMEDIATE,
45
Thread.currentThread().getContextClassLoader()
46
);
47
48
// Configuration with auto-grow features
49
SpelParserConfiguration autoGrowConfig = new SpelParserConfiguration(
50
true, // autoGrowNullReferences
51
true, // autoGrowCollections
52
100 // maximumAutoGrowSize
53
);
54
55
// Complete configuration
56
SpelParserConfiguration fullConfig = new SpelParserConfiguration(
57
SpelCompilerMode.MIXED, // compilerMode
58
Thread.currentThread().getContextClassLoader(), // compilerClassLoader
59
true, // autoGrowNullReferences
60
true, // autoGrowCollections
61
1000, // maximumAutoGrowSize
62
50000 // maximumExpressionLength
63
);
64
65
// Use configuration with parser
66
SpelExpressionParser parser = new SpelExpressionParser(fullConfig);
67
```
68
{ .api }
69
70
## Compiler Configuration
71
72
### SpelCompilerMode Enum
73
74
```java
75
public enum SpelCompilerMode {
76
OFF, // No compilation, interpreted mode only (default)
77
IMMEDIATE, // Compile immediately after first interpretation
78
MIXED // Switch between interpreted and compiled modes as needed
79
}
80
```
81
{ .api }
82
83
### Compilation Modes Explained
84
85
#### OFF Mode (Default)
86
87
```java
88
SpelParserConfiguration config = new SpelParserConfiguration(
89
SpelCompilerMode.OFF,
90
null
91
);
92
SpelExpressionParser parser = new SpelExpressionParser(config);
93
94
// All expressions will be interpreted, no compilation
95
Expression exp = parser.parseExpression("name.toUpperCase() + ' ' + age");
96
// Always uses interpretation, slower but more flexible
97
```
98
{ .api }
99
100
#### IMMEDIATE Mode
101
102
```java
103
SpelParserConfiguration config = new SpelParserConfiguration(
104
SpelCompilerMode.IMMEDIATE,
105
Thread.currentThread().getContextClassLoader()
106
);
107
SpelExpressionParser parser = new SpelExpressionParser(config);
108
109
SpelExpression exp = parser.parseRaw("name.toUpperCase() + ' ' + age");
110
111
// First evaluation triggers compilation
112
String result1 = exp.getValue(person, String.class); // Interpreted + compiled
113
// Subsequent evaluations use compiled code
114
String result2 = exp.getValue(person, String.class); // Compiled (much faster)
115
```
116
{ .api }
117
118
#### MIXED Mode
119
120
```java
121
SpelParserConfiguration config = new SpelParserConfiguration(
122
SpelCompilerMode.MIXED,
123
Thread.currentThread().getContextClassLoader()
124
);
125
SpelExpressionParser parser = new SpelExpressionParser(config);
126
127
// Expressions can switch between interpreted and compiled modes
128
// based on success/failure of compilation and execution patterns
129
SpelExpression exp = parser.parseRaw("complexExpression()");
130
```
131
{ .api }
132
133
### System Property Configuration
134
135
```java
136
// Set compiler mode via system property
137
System.setProperty("spring.expression.compiler.mode", "IMMEDIATE");
138
139
// Parser will use system property if no explicit configuration provided
140
SpelExpressionParser parser = new SpelExpressionParser();
141
// Equivalent to:
142
// SpelExpressionParser parser = new SpelExpressionParser(
143
// new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, classLoader)
144
// );
145
```
146
{ .api }
147
148
### Manual Compilation Control
149
150
```java
151
SpelExpressionParser parser = new SpelExpressionParser();
152
SpelExpression expression = parser.parseRaw("name.length() > 5 ? name.toUpperCase() : name");
153
154
// Check if expression can be compiled
155
boolean compilable = expression.compileExpression();
156
157
if (compilable) {
158
// Expression was successfully compiled
159
String result = expression.getValue(person, String.class); // Uses compiled code
160
} else {
161
// Compilation failed, will use interpreted mode
162
String result = expression.getValue(person, String.class); // Uses interpretation
163
}
164
165
// Revert to interpreted mode
166
expression.revertToInterpreted();
167
String result = expression.getValue(person, String.class); // Back to interpretation
168
```
169
{ .api }
170
171
## Auto-Growth Configuration
172
173
### Null Reference Auto-Growth
174
175
```java
176
public class Container {
177
private NestedObject nested;
178
// getter and setter
179
}
180
181
public class NestedObject {
182
private String value;
183
// getter and setter
184
}
185
186
// Enable null reference auto-growth
187
SpelParserConfiguration config = new SpelParserConfiguration(
188
true, // autoGrowNullReferences
189
false // autoGrowCollections
190
);
191
SpelExpressionParser parser = new SpelExpressionParser(config);
192
193
Container container = new Container(); // nested is null
194
StandardEvaluationContext context = new StandardEvaluationContext(container);
195
196
// Without auto-growth, this would throw NullPointerException
197
// With auto-growth, it creates the nested object automatically
198
Expression exp = parser.parseExpression("nested.value");
199
exp.setValue(context, "Hello World");
200
201
// nested object was created automatically
202
NestedObject created = container.getNested(); // not null
203
String value = created.getValue(); // "Hello World"
204
```
205
{ .api }
206
207
### Collection Auto-Growth
208
209
```java
210
public class ListContainer {
211
private List<String> items = new ArrayList<>();
212
// getter and setter
213
}
214
215
// Enable collection auto-growth
216
SpelParserConfiguration config = new SpelParserConfiguration(
217
false, // autoGrowNullReferences
218
true, // autoGrowCollections
219
10 // maximumAutoGrowSize
220
);
221
SpelExpressionParser parser = new SpelExpressionParser(config);
222
223
ListContainer container = new ListContainer(); // empty list
224
StandardEvaluationContext context = new StandardEvaluationContext(container);
225
226
// Set value at index 5 in empty list
227
Expression exp = parser.parseExpression("items[5]");
228
exp.setValue(context, "Hello");
229
230
// List automatically grows to accommodate index 5
231
List<String> items = container.getItems();
232
// items.size() == 6, items.get(5) == "Hello", others are null
233
```
234
{ .api }
235
236
### Combined Auto-Growth
237
238
```java
239
public class ComplexContainer {
240
private List<NestedObject> objects;
241
// getter and setter
242
}
243
244
// Enable both auto-growth features
245
SpelParserConfiguration config = new SpelParserConfiguration(
246
true, // autoGrowNullReferences
247
true, // autoGrowCollections
248
50 // maximumAutoGrowSize
249
);
250
SpelExpressionParser parser = new SpelExpressionParser(config);
251
252
ComplexContainer container = new ComplexContainer(); // objects is null
253
StandardEvaluationContext context = new StandardEvaluationContext(container);
254
255
// This will:
256
// 1. Create the objects list (null reference auto-growth)
257
// 2. Grow the list to accommodate index 3 (collection auto-growth)
258
// 3. Create NestedObject at index 3 (null reference auto-growth)
259
Expression exp = parser.parseExpression("objects[3].value");
260
exp.setValue(context, "Deep Value");
261
262
NestedObject obj = container.getObjects().get(3);
263
String value = obj.getValue(); // "Deep Value"
264
```
265
{ .api }
266
267
## Expression Length Limits
268
269
### Maximum Expression Length
270
271
```java
272
// Set custom maximum expression length
273
SpelParserConfiguration config = new SpelParserConfiguration(
274
SpelCompilerMode.OFF,
275
null,
276
false, // autoGrowNullReferences
277
false, // autoGrowCollections
278
0, // maximumAutoGrowSize
279
5000 // maximumExpressionLength (default is 10,000)
280
);
281
282
SpelExpressionParser parser = new SpelExpressionParser(config);
283
284
// Expressions longer than 5000 characters will be rejected
285
String longExpression = "very".repeat(2000) + "long expression";
286
try {
287
Expression exp = parser.parseExpression(longExpression);
288
} catch (ParseException e) {
289
// Expression too long
290
}
291
```
292
{ .api }
293
294
## Advanced Configuration Patterns
295
296
### Environment-Based Configuration
297
298
```java
299
public class SpelConfigurationFactory {
300
301
public static SpelParserConfiguration createProductionConfig() {
302
return new SpelParserConfiguration(
303
SpelCompilerMode.IMMEDIATE, // Aggressive compilation for performance
304
Thread.currentThread().getContextClassLoader(),
305
false, // Disable auto-growth for predictable behavior
306
false,
307
0,
308
10000 // Standard expression length limit
309
);
310
}
311
312
public static SpelParserConfiguration createDevelopmentConfig() {
313
return new SpelParserConfiguration(
314
SpelCompilerMode.OFF, // No compilation for easier debugging
315
null,
316
true, // Enable auto-growth for convenience
317
true,
318
100,
319
50000 // Larger expression limit for experimentation
320
);
321
}
322
323
public static SpelParserConfiguration createTestConfig() {
324
return new SpelParserConfiguration(
325
SpelCompilerMode.MIXED, // Mixed mode for testing both paths
326
Thread.currentThread().getContextClassLoader(),
327
true, // Auto-growth for test data setup
328
true,
329
10,
330
10000
331
);
332
}
333
}
334
335
// Usage
336
String environment = System.getProperty("environment", "development");
337
SpelParserConfiguration config = switch (environment) {
338
case "production" -> SpelConfigurationFactory.createProductionConfig();
339
case "test" -> SpelConfigurationFactory.createTestConfig();
340
default -> SpelConfigurationFactory.createDevelopmentConfig();
341
};
342
343
SpelExpressionParser parser = new SpelExpressionParser(config);
344
```
345
{ .api }
346
347
### Configuration with Custom ClassLoader
348
349
```java
350
// Custom class loader for isolation
351
ClassLoader customClassLoader = new URLClassLoader(
352
new URL[]{new URL("file:///path/to/custom/classes/")},
353
Thread.currentThread().getContextClassLoader()
354
);
355
356
SpelParserConfiguration config = new SpelParserConfiguration(
357
SpelCompilerMode.IMMEDIATE,
358
customClassLoader // Use custom class loader for compilation
359
);
360
361
SpelExpressionParser parser = new SpelExpressionParser(config);
362
363
// Compiled expressions will use the custom class loader
364
Expression exp = parser.parseExpression("T(com.custom.MyClass).staticMethod()");
365
```
366
{ .api }
367
368
## Configuration Best Practices
369
370
### Performance-Oriented Configuration
371
372
```java
373
// High-performance configuration for production systems
374
SpelParserConfiguration performanceConfig = new SpelParserConfiguration(
375
SpelCompilerMode.IMMEDIATE, // Immediate compilation
376
Thread.currentThread().getContextClassLoader(), // Appropriate class loader
377
false, // Disable auto-growth (predictable)
378
false, // Disable auto-growth
379
0, // No auto-growth
380
10000 // Standard limit
381
);
382
383
// Use with cached expressions
384
Map<String, Expression> expressionCache = new ConcurrentHashMap<>();
385
SpelExpressionParser parser = new SpelExpressionParser(performanceConfig);
386
387
public Expression getCachedExpression(String expressionString) {
388
return expressionCache.computeIfAbsent(expressionString, parser::parseExpression);
389
}
390
```
391
{ .api }
392
393
### Security-Conscious Configuration
394
395
```java
396
// Security-focused configuration
397
SpelParserConfiguration secureConfig = new SpelParserConfiguration(
398
SpelCompilerMode.OFF, // No compilation to avoid runtime class generation
399
null,
400
false, // No auto-growth to prevent unexpected object creation
401
false,
402
0,
403
1000 // Strict expression length limit
404
);
405
406
// Combine with SimpleEvaluationContext for additional security
407
SpelExpressionParser parser = new SpelExpressionParser(secureConfig);
408
SimpleEvaluationContext context = SimpleEvaluationContext
409
.forReadOnlyDataBinding()
410
.build();
411
```
412
{ .api }
413
414
### Development-Friendly Configuration
415
416
```java
417
// Development configuration with helpful features
418
SpelParserConfiguration devConfig = new SpelParserConfiguration(
419
SpelCompilerMode.MIXED, // Test both compilation modes
420
Thread.currentThread().getContextClassLoader(),
421
true, // Auto-growth for easier prototyping
422
true,
423
1000, // Generous auto-growth limit
424
100000 // Large expression limit for experimentation
425
);
426
427
SpelExpressionParser parser = new SpelExpressionParser(devConfig);
428
429
// Useful for development: detailed error reporting
430
public Object safeEvaluate(String expressionString, Object root) {
431
try {
432
Expression exp = parser.parseExpression(expressionString);
433
return exp.getValue(root);
434
} catch (ParseException e) {
435
System.err.println("Parse error in expression: " + expressionString);
436
System.err.println("Error: " + e.toDetailedString());
437
return null;
438
} catch (EvaluationException e) {
439
System.err.println("Evaluation error in expression: " + expressionString);
440
System.err.println("Error: " + e.toDetailedString());
441
return null;
442
}
443
}
444
```
445
{ .api }
446
447
## Configuration Validation
448
449
### Runtime Configuration Checks
450
451
```java
452
public class ConfigurationValidator {
453
454
public static void validateConfiguration(SpelParserConfiguration config) {
455
SpelCompilerMode mode = config.getCompilerMode();
456
ClassLoader classLoader = config.getCompilerClassLoader();
457
458
if ((mode == SpelCompilerMode.IMMEDIATE || mode == SpelCompilerMode.MIXED)
459
&& classLoader == null) {
460
throw new IllegalArgumentException(
461
"ClassLoader must be provided for compilation modes");
462
}
463
464
if (config.getMaximumAutoGrowSize() < 0) {
465
throw new IllegalArgumentException(
466
"Maximum auto-grow size must be non-negative");
467
}
468
469
if (config.getMaximumExpressionLength() <= 0) {
470
throw new IllegalArgumentException(
471
"Maximum expression length must be positive");
472
}
473
}
474
475
public static SpelExpressionParser createValidatedParser(SpelParserConfiguration config) {
476
validateConfiguration(config);
477
return new SpelExpressionParser(config);
478
}
479
}
480
```
481
{ .api }
482
483
## Migration and Compatibility
484
485
### Upgrading Configuration
486
487
```java
488
// Legacy configuration (pre-6.0)
489
SpelParserConfiguration legacyConfig = new SpelParserConfiguration(
490
true, // autoGrowNullReferences
491
true // autoGrowCollections
492
);
493
494
// Modern equivalent with explicit settings
495
SpelParserConfiguration modernConfig = new SpelParserConfiguration(
496
SpelCompilerMode.OFF, // Explicit compiler mode
497
Thread.currentThread().getContextClassLoader(), // Explicit class loader
498
true, // autoGrowNullReferences
499
true, // autoGrowCollections
500
Integer.MAX_VALUE, // maximumAutoGrowSize
501
SpelParserConfiguration.DEFAULT_MAX_EXPRESSION_LENGTH
502
);
503
```
504
{ .api }
505
506
### Configuration Compatibility Checking
507
508
```java
509
public class CompatibilityChecker {
510
511
public static boolean isCompilationSupported() {
512
try {
513
SpelParserConfiguration config = new SpelParserConfiguration(
514
SpelCompilerMode.IMMEDIATE,
515
Thread.currentThread().getContextClassLoader()
516
);
517
SpelExpressionParser parser = new SpelExpressionParser(config);
518
SpelExpression exp = parser.parseRaw("'test'");
519
return exp.compileExpression();
520
} catch (Exception e) {
521
return false;
522
}
523
}
524
525
public static SpelParserConfiguration createCompatibleConfig() {
526
if (isCompilationSupported()) {
527
return new SpelParserConfiguration(
528
SpelCompilerMode.IMMEDIATE,
529
Thread.currentThread().getContextClassLoader()
530
);
531
} else {
532
return new SpelParserConfiguration();
533
}
534
}
535
}
536
```
537
{ .api }