1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.expression.spel.standard;
18
19 import org.springframework.core.convert.TypeDescriptor;
20 import org.springframework.expression.EvaluationContext;
21 import org.springframework.expression.EvaluationException;
22 import org.springframework.expression.Expression;
23 import org.springframework.expression.TypedValue;
24 import org.springframework.expression.common.ExpressionUtils;
25 import org.springframework.expression.spel.CompiledExpression;
26 import org.springframework.expression.spel.ExpressionState;
27 import org.springframework.expression.spel.SpelCompilerMode;
28 import org.springframework.expression.spel.SpelEvaluationException;
29 import org.springframework.expression.spel.SpelMessage;
30 import org.springframework.expression.spel.SpelNode;
31 import org.springframework.expression.spel.SpelParserConfiguration;
32 import org.springframework.expression.spel.ast.SpelNodeImpl;
33 import org.springframework.expression.spel.support.StandardEvaluationContext;
34 import org.springframework.util.Assert;
35
36
37
38
39
40
41
42
43
44
45 public class SpelExpression implements Expression {
46
47
48 private static final int INTERPRETED_COUNT_THRESHOLD = 100;
49
50
51 private static final int FAILED_ATTEMPTS_THRESHOLD = 100;
52
53
54 private final String expression;
55
56 private final SpelNodeImpl ast;
57
58 private final SpelParserConfiguration configuration;
59
60
61 private EvaluationContext evaluationContext;
62
63
64 private CompiledExpression compiledAst;
65
66
67
68 private volatile int interpretedCount = 0;
69
70
71
72 private volatile int failedAttempts = 0;
73
74
75
76
77
78 public SpelExpression(String expression, SpelNodeImpl ast, SpelParserConfiguration configuration) {
79 this.expression = expression;
80 this.ast = ast;
81 this.configuration = configuration;
82 }
83
84
85
86
87
88
89 public void setEvaluationContext(EvaluationContext evaluationContext) {
90 this.evaluationContext = evaluationContext;
91 }
92
93
94
95
96
97 public EvaluationContext getEvaluationContext() {
98 if (this.evaluationContext == null) {
99 this.evaluationContext = new StandardEvaluationContext();
100 }
101 return this.evaluationContext;
102 }
103
104
105
106
107 @Override
108 public Object getValue() throws EvaluationException {
109 Object result;
110 if (this.compiledAst != null) {
111 try {
112 TypedValue contextRoot = evaluationContext == null ? null : evaluationContext.getRootObject();
113 return this.compiledAst.getValue(contextRoot == null ? null : contextRoot.getValue(), evaluationContext);
114 }
115 catch (Throwable ex) {
116
117 if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
118 this.interpretedCount = 0;
119 this.compiledAst = null;
120 }
121 else {
122
123 throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
124 }
125 }
126 }
127 ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration);
128 result = this.ast.getValue(expressionState);
129 checkCompile(expressionState);
130 return result;
131 }
132
133 @Override
134 public Object getValue(Object rootObject) throws EvaluationException {
135 Object result;
136 if (this.compiledAst != null) {
137 try {
138 return this.compiledAst.getValue(rootObject, evaluationContext);
139 }
140 catch (Throwable ex) {
141
142 if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
143 this.interpretedCount = 0;
144 this.compiledAst = null;
145 }
146 else {
147
148 throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
149 }
150 }
151 }
152 ExpressionState expressionState = new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration);
153 result = this.ast.getValue(expressionState);
154 checkCompile(expressionState);
155 return result;
156 }
157
158 @SuppressWarnings("unchecked")
159 @Override
160 public <T> T getValue(Class<T> expectedResultType) throws EvaluationException {
161 if (this.compiledAst != null) {
162 try {
163 TypedValue contextRoot = evaluationContext == null ? null : evaluationContext.getRootObject();
164 Object result = this.compiledAst.getValue(contextRoot == null ? null : contextRoot.getValue(), evaluationContext);
165 if (expectedResultType == null) {
166 return (T)result;
167 }
168 else {
169 return ExpressionUtils.convertTypedValue(getEvaluationContext(), new TypedValue(result), expectedResultType);
170 }
171 }
172 catch (Throwable ex) {
173
174 if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
175 this.interpretedCount = 0;
176 this.compiledAst = null;
177 }
178 else {
179
180 throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
181 }
182 }
183 }
184 ExpressionState expressionState = new ExpressionState(getEvaluationContext(), this.configuration);
185 TypedValue typedResultValue = this.ast.getTypedValue(expressionState);
186 checkCompile(expressionState);
187 return ExpressionUtils.convertTypedValue(expressionState.getEvaluationContext(), typedResultValue, expectedResultType);
188 }
189
190 @SuppressWarnings("unchecked")
191 @Override
192 public <T> T getValue(Object rootObject, Class<T> expectedResultType) throws EvaluationException {
193 if (this.compiledAst != null) {
194 try {
195 Object result = this.compiledAst.getValue(rootObject, null);
196 if (expectedResultType == null) {
197 return (T)result;
198 }
199 else {
200 return ExpressionUtils.convertTypedValue(getEvaluationContext(), new TypedValue(result), expectedResultType);
201 }
202 }
203 catch (Throwable ex) {
204
205 if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
206 this.interpretedCount = 0;
207 this.compiledAst = null;
208 }
209 else {
210
211 throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
212 }
213 }
214 }
215 ExpressionState expressionState = new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration);
216 TypedValue typedResultValue = this.ast.getTypedValue(expressionState);
217 checkCompile(expressionState);
218 return ExpressionUtils.convertTypedValue(expressionState.getEvaluationContext(), typedResultValue, expectedResultType);
219 }
220
221 @Override
222 public Object getValue(EvaluationContext context) throws EvaluationException {
223 Assert.notNull(context, "EvaluationContext is required");
224 if (compiledAst!= null) {
225 try {
226 TypedValue contextRoot = context == null ? null : context.getRootObject();
227 return this.compiledAst.getValue(contextRoot != null ? contextRoot.getValue() : null, context);
228 }
229 catch (Throwable ex) {
230
231 if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
232 this.interpretedCount = 0;
233 this.compiledAst = null;
234 }
235 else {
236
237 throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
238 }
239 }
240 }
241 ExpressionState expressionState = new ExpressionState(context, this.configuration);
242 Object result = this.ast.getValue(expressionState);
243 checkCompile(expressionState);
244 return result;
245 }
246
247 @Override
248 public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException {
249 Assert.notNull(context, "EvaluationContext is required");
250 if (this.compiledAst != null) {
251 try {
252 return this.compiledAst.getValue(rootObject,context);
253 }
254 catch (Throwable ex) {
255
256 if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
257 this.interpretedCount = 0;
258 this.compiledAst = null;
259 }
260 else {
261
262 throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
263 }
264 }
265 }
266 ExpressionState expressionState = new ExpressionState(context, toTypedValue(rootObject), this.configuration);
267 Object result = this.ast.getValue(expressionState);
268 checkCompile(expressionState);
269 return result;
270 }
271
272 @SuppressWarnings("unchecked")
273 @Override
274 public <T> T getValue(EvaluationContext context, Class<T> expectedResultType) throws EvaluationException {
275 if (this.compiledAst != null) {
276 try {
277 TypedValue contextRoot = context == null ? null : context.getRootObject();
278 Object result = this.compiledAst.getValue(contextRoot==null?null:contextRoot.getValue(),context);
279 if (expectedResultType != null) {
280 return ExpressionUtils.convertTypedValue(context, new TypedValue(result), expectedResultType);
281 }
282 else {
283 return (T) result;
284 }
285 }
286 catch (Throwable ex) {
287
288 if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
289 this.interpretedCount = 0;
290 this.compiledAst = null;
291 }
292 else {
293
294 throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
295 }
296 }
297 }
298 ExpressionState expressionState = new ExpressionState(context, this.configuration);
299 TypedValue typedResultValue = this.ast.getTypedValue(expressionState);
300 checkCompile(expressionState);
301 return ExpressionUtils.convertTypedValue(context, typedResultValue, expectedResultType);
302 }
303
304 @SuppressWarnings("unchecked")
305 @Override
306 public <T> T getValue(EvaluationContext context, Object rootObject, Class<T> expectedResultType) throws EvaluationException {
307 if (this.compiledAst != null) {
308 try {
309 Object result = this.compiledAst.getValue(rootObject,context);
310 if (expectedResultType != null) {
311 return ExpressionUtils.convertTypedValue(context, new TypedValue(result), expectedResultType);
312 }
313 else {
314 return (T) result;
315 }
316 }
317 catch (Throwable ex) {
318
319 if (this.configuration.getCompilerMode() == SpelCompilerMode.MIXED) {
320 this.interpretedCount = 0;
321 this.compiledAst = null;
322 }
323 else {
324
325 throw new SpelEvaluationException(ex, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION);
326 }
327 }
328 }
329 ExpressionState expressionState = new ExpressionState(context, toTypedValue(rootObject), this.configuration);
330 TypedValue typedResultValue = this.ast.getTypedValue(expressionState);
331 checkCompile(expressionState);
332 return ExpressionUtils.convertTypedValue(context, typedResultValue, expectedResultType);
333 }
334
335 @Override
336 public Class<?> getValueType() throws EvaluationException {
337 return getValueType(getEvaluationContext());
338 }
339
340 @Override
341 public Class<?> getValueType(Object rootObject) throws EvaluationException {
342 return getValueType(getEvaluationContext(), rootObject);
343 }
344
345 @Override
346 public Class<?> getValueType(EvaluationContext context) throws EvaluationException {
347 Assert.notNull(context, "EvaluationContext is required");
348 ExpressionState expressionState = new ExpressionState(context, this.configuration);
349 TypeDescriptor typeDescriptor = this.ast.getValueInternal(expressionState).getTypeDescriptor();
350 return (typeDescriptor != null ? typeDescriptor.getType() : null);
351 }
352
353 @Override
354 public Class<?> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException {
355 ExpressionState expressionState = new ExpressionState(context, toTypedValue(rootObject), this.configuration);
356 TypeDescriptor typeDescriptor = this.ast.getValueInternal(expressionState).getTypeDescriptor();
357 return (typeDescriptor != null ? typeDescriptor.getType() : null);
358 }
359
360 @Override
361 public TypeDescriptor getValueTypeDescriptor() throws EvaluationException {
362 return getValueTypeDescriptor(getEvaluationContext());
363 }
364
365 @Override
366 public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException {
367 ExpressionState expressionState =
368 new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration);
369 return this.ast.getValueInternal(expressionState).getTypeDescriptor();
370 }
371
372 @Override
373 public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws EvaluationException {
374 Assert.notNull(context, "EvaluationContext is required");
375 ExpressionState expressionState = new ExpressionState(context, this.configuration);
376 return this.ast.getValueInternal(expressionState).getTypeDescriptor();
377 }
378
379 @Override
380 public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject) throws EvaluationException {
381 Assert.notNull(context, "EvaluationContext is required");
382 ExpressionState expressionState = new ExpressionState(context, toTypedValue(rootObject), this.configuration);
383 return this.ast.getValueInternal(expressionState).getTypeDescriptor();
384 }
385
386 @Override
387 public String getExpressionString() {
388 return this.expression;
389 }
390
391 @Override
392 public boolean isWritable(EvaluationContext context) throws EvaluationException {
393 Assert.notNull(context, "EvaluationContext is required");
394 return this.ast.isWritable(new ExpressionState(context, this.configuration));
395 }
396
397 @Override
398 public boolean isWritable(Object rootObject) throws EvaluationException {
399 return this.ast.isWritable(new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration));
400 }
401
402 @Override
403 public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException {
404 Assert.notNull(context, "EvaluationContext is required");
405 return this.ast.isWritable(new ExpressionState(context, toTypedValue(rootObject), this.configuration));
406 }
407
408 @Override
409 public void setValue(EvaluationContext context, Object value) throws EvaluationException {
410 Assert.notNull(context, "EvaluationContext is required");
411 this.ast.setValue(new ExpressionState(context, this.configuration), value);
412 }
413
414 @Override
415 public void setValue(Object rootObject, Object value) throws EvaluationException {
416 this.ast.setValue(new ExpressionState(getEvaluationContext(), toTypedValue(rootObject), this.configuration), value);
417 }
418
419 @Override
420 public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException {
421 Assert.notNull(context, "EvaluationContext is required");
422 this.ast.setValue(new ExpressionState(context, toTypedValue(rootObject), this.configuration), value);
423 }
424
425
426
427
428
429
430
431 private void checkCompile(ExpressionState expressionState) {
432 this.interpretedCount++;
433 SpelCompilerMode compilerMode = expressionState.getConfiguration().getCompilerMode();
434 if (compilerMode != SpelCompilerMode.OFF) {
435 if (compilerMode == SpelCompilerMode.IMMEDIATE) {
436 if (this.interpretedCount > 1) {
437 compileExpression();
438 }
439 }
440 else {
441
442 if (this.interpretedCount > INTERPRETED_COUNT_THRESHOLD) {
443 compileExpression();
444 }
445 }
446 }
447 }
448
449
450
451
452
453
454
455 public boolean compileExpression() {
456 if (this.failedAttempts > FAILED_ATTEMPTS_THRESHOLD) {
457
458 return false;
459 }
460 if (this.compiledAst == null) {
461 synchronized (this.expression) {
462
463 if (this.compiledAst != null) {
464 return true;
465 }
466 SpelCompiler compiler = SpelCompiler.getCompiler(this.configuration.getCompilerClassLoader());
467 this.compiledAst = compiler.compile(this.ast);
468 if (this.compiledAst == null) {
469 this.failedAttempts++;
470 }
471 }
472 }
473 return (this.compiledAst != null);
474 }
475
476
477
478
479
480
481 public void revertToInterpreted() {
482 this.compiledAst = null;
483 this.interpretedCount = 0;
484 this.failedAttempts = 0;
485 }
486
487
488
489
490 public SpelNode getAST() {
491 return this.ast;
492 }
493
494
495
496
497
498
499
500 public String toStringAST() {
501 return this.ast.toStringAST();
502 }
503
504 private TypedValue toTypedValue(Object object) {
505 if (object == null) {
506 return TypedValue.NULL;
507 }
508 else {
509 return new TypedValue(object);
510 }
511 }
512
513 }