Skip to content

Commit 1a626ab

Browse files
committed
SpelExpression consistently exposes EvaluationContext to compiled AST
Operator includes explicit support for Boolean comparisons now. Issue: SPR-17229 (cherry picked from commit 51cee65)
1 parent 56194a1 commit 1a626ab

File tree

2 files changed

+29
-30
lines changed

2 files changed

+29
-30
lines changed

Diff for: spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java

+19-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@
4040
public abstract class Operator extends SpelNodeImpl {
4141

4242
private final String operatorName;
43-
43+
4444
// The descriptors of the runtime operand values are used if the discovered declared
4545
// descriptors are not providing enough information (for example a generic type
4646
// whose accessors seem to only be returning 'Object' - the actual descriptors may
@@ -70,7 +70,8 @@ public final String getOperatorName() {
7070
}
7171

7272
/**
73-
* String format for all operators is the same '(' [operand] [operator] [operand] ')'
73+
* String format for all operators is the same
74+
* {@code '(' [operand] [operator] [operand] ')'}.
7475
*/
7576
@Override
7677
public String toStringAST() {
@@ -100,8 +101,8 @@ protected boolean isCompilableOperatorUsingNumerics() {
100101
return (dc.areNumbers && dc.areCompatible);
101102
}
102103

103-
/**
104-
* Numeric comparison operators share very similar generated code, only differing in
104+
/**
105+
* Numeric comparison operators share very similar generated code, only differing in
105106
* two comparison instructions.
106107
*/
107108
protected void generateComparisonCode(MethodVisitor mv, CodeFlow cf, int compInstruction1, int compInstruction2) {
@@ -113,14 +114,14 @@ protected void generateComparisonCode(MethodVisitor mv, CodeFlow cf, int compIns
113114
DescriptorComparison dc = DescriptorComparison.checkNumericCompatibility(
114115
leftDesc, rightDesc, this.leftActualDescriptor, this.rightActualDescriptor);
115116
char targetType = dc.compatibleType; // CodeFlow.toPrimitiveTargetDesc(leftDesc);
116-
117+
117118
cf.enterCompilationScope();
118119
getLeftOperand().generateCode(mv, cf);
119120
cf.exitCompilationScope();
120121
if (unboxLeft) {
121122
CodeFlow.insertUnboxInsns(mv, targetType, leftDesc);
122123
}
123-
124+
124125
cf.enterCompilationScope();
125126
getRightOperand().generateCode(mv, cf);
126127
cf.exitCompilationScope();
@@ -136,11 +137,11 @@ protected void generateComparisonCode(MethodVisitor mv, CodeFlow cf, int compIns
136137
mv.visitJumpInsn(compInstruction1, elseTarget);
137138
}
138139
else if (targetType == 'F') {
139-
mv.visitInsn(FCMPG);
140+
mv.visitInsn(FCMPG);
140141
mv.visitJumpInsn(compInstruction1, elseTarget);
141142
}
142143
else if (targetType == 'J') {
143-
mv.visitInsn(LCMP);
144+
mv.visitInsn(LCMP);
144145
mv.visitJumpInsn(compInstruction1, elseTarget);
145146
}
146147
else if (targetType == 'I') {
@@ -212,6 +213,10 @@ else if (leftNumber instanceof Byte || rightNumber instanceof Byte) {
212213
return left.toString().equals(right.toString());
213214
}
214215

216+
if (left instanceof Boolean && right instanceof Boolean) {
217+
return left.equals(right);
218+
}
219+
215220
if (ObjectUtils.nullSafeEquals(left, right)) {
216221
return true;
217222
}
@@ -225,7 +230,7 @@ else if (leftNumber instanceof Byte || rightNumber instanceof Byte) {
225230

226231
return false;
227232
}
228-
233+
229234

230235
/**
231236
* A descriptor comparison encapsulates the result of comparing descriptor
@@ -248,7 +253,7 @@ private DescriptorComparison(boolean areNumbers, boolean areCompatible, char com
248253
this.areCompatible = areCompatible;
249254
this.compatibleType = compatibleType;
250255
}
251-
256+
252257
/**
253258
* Return an object that indicates whether the input descriptors are compatible.
254259
* <p>A declared descriptor is what could statically be determined (e.g. from looking
@@ -271,7 +276,7 @@ public static DescriptorComparison checkNumericCompatibility(String leftDeclared
271276

272277
boolean leftNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(ld);
273278
boolean rightNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(rd);
274-
279+
275280
// If the declared descriptors aren't providing the information, try the actual descriptors
276281
if (!leftNumeric && !ObjectUtils.nullSafeEquals(ld, leftActualDescriptor)) {
277282
ld = leftActualDescriptor;
@@ -281,7 +286,7 @@ public static DescriptorComparison checkNumericCompatibility(String leftDeclared
281286
rd = rightActualDescriptor;
282287
rightNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(rd);
283288
}
284-
289+
285290
if (leftNumeric && rightNumeric) {
286291
if (CodeFlow.areBoxingCompatible(ld, rd)) {
287292
return new DescriptorComparison(true, true, CodeFlow.toPrimitiveTargetDesc(ld));
@@ -292,7 +297,7 @@ public static DescriptorComparison checkNumericCompatibility(String leftDeclared
292297
}
293298
else {
294299
return DescriptorComparison.NOT_NUMBERS;
295-
}
300+
}
296301
}
297302
}
298303

Diff for: spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java

+10-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -114,10 +114,8 @@ public String getExpressionString() {
114114
public Object getValue() throws EvaluationException {
115115
if (this.compiledAst != null) {
116116
try {
117-
TypedValue contextRoot =
118-
(this.evaluationContext != null ? this.evaluationContext.getRootObject() : null);
119-
return this.compiledAst.getValue(
120-
(contextRoot != null ? contextRoot.getValue() : null), this.evaluationContext);
117+
EvaluationContext context = getEvaluationContext();
118+
return this.compiledAst.getValue(context.getRootObject().getValue(), context);
121119
}
122120
catch (Throwable ex) {
123121
// If running in mixed mode, revert to interpreted
@@ -143,10 +141,8 @@ public Object getValue() throws EvaluationException {
143141
public <T> T getValue(Class<T> expectedResultType) throws EvaluationException {
144142
if (this.compiledAst != null) {
145143
try {
146-
TypedValue contextRoot =
147-
(this.evaluationContext != null ? this.evaluationContext.getRootObject() : null);
148-
Object result = this.compiledAst.getValue(
149-
(contextRoot != null ? contextRoot.getValue() : null), this.evaluationContext);
144+
EvaluationContext context = getEvaluationContext();
145+
Object result = this.compiledAst.getValue(context.getRootObject().getValue(), context);
150146
if (expectedResultType == null) {
151147
return (T) result;
152148
}
@@ -179,7 +175,7 @@ public <T> T getValue(Class<T> expectedResultType) throws EvaluationException {
179175
public Object getValue(Object rootObject) throws EvaluationException {
180176
if (this.compiledAst != null) {
181177
try {
182-
return this.compiledAst.getValue(rootObject, evaluationContext);
178+
return this.compiledAst.getValue(rootObject, getEvaluationContext());
183179
}
184180
catch (Throwable ex) {
185181
// If running in mixed mode, revert to interpreted
@@ -206,7 +202,7 @@ public Object getValue(Object rootObject) throws EvaluationException {
206202
public <T> T getValue(Object rootObject, Class<T> expectedResultType) throws EvaluationException {
207203
if (this.compiledAst != null) {
208204
try {
209-
Object result = this.compiledAst.getValue(rootObject, null);
205+
Object result = this.compiledAst.getValue(rootObject, getEvaluationContext());
210206
if (expectedResultType == null) {
211207
return (T)result;
212208
}
@@ -242,8 +238,7 @@ public Object getValue(EvaluationContext context) throws EvaluationException {
242238

243239
if (this.compiledAst != null) {
244240
try {
245-
TypedValue contextRoot = context.getRootObject();
246-
return this.compiledAst.getValue(contextRoot.getValue(), context);
241+
return this.compiledAst.getValue(context.getRootObject().getValue(), context);
247242
}
248243
catch (Throwable ex) {
249244
// If running in mixed mode, revert to interpreted
@@ -271,8 +266,7 @@ public <T> T getValue(EvaluationContext context, Class<T> expectedResultType) th
271266

272267
if (this.compiledAst != null) {
273268
try {
274-
TypedValue contextRoot = context.getRootObject();
275-
Object result = this.compiledAst.getValue(contextRoot.getValue(), context);
269+
Object result = this.compiledAst.getValue(context.getRootObject().getValue(), context);
276270
if (expectedResultType != null) {
277271
return ExpressionUtils.convertTypedValue(context, new TypedValue(result), expectedResultType);
278272
}
@@ -305,7 +299,7 @@ public Object getValue(EvaluationContext context, Object rootObject) throws Eval
305299

306300
if (this.compiledAst != null) {
307301
try {
308-
return this.compiledAst.getValue(rootObject,context);
302+
return this.compiledAst.getValue(rootObject, context);
309303
}
310304
catch (Throwable ex) {
311305
// If running in mixed mode, revert to interpreted

0 commit comments

Comments
 (0)