From e332e32a88e0a5356dbf212290ea6f49cf47c589 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 31 Aug 2018 12:41:22 +0200 Subject: [PATCH] SpelExpression consistently exposes EvaluationContext to compiled AST Operator includes explicit support for Boolean comparisons now. Issue: SPR-17229 (cherry picked from commit 51cee658d5da9de2f0749129d7f0904fd0e2af91) --- .../expression/spel/ast/Operator.java | 35 +++++++++++-------- .../spel/standard/SpelExpression.java | 26 ++++++-------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java index 9bbadb372c..820258dabd 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Operator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,7 +41,7 @@ import org.springframework.util.ObjectUtils; public abstract class Operator extends SpelNodeImpl { private final String operatorName; - + // The descriptors of the runtime operand values are used if the discovered declared // descriptors are not providing enough information (for example a generic type // whose accessors seem to only be returning 'Object' - the actual descriptors may @@ -73,7 +73,8 @@ public abstract class Operator extends SpelNodeImpl { } /** - * String format for all operators is the same '(' [operand] [operator] [operand] ')' + * String format for all operators is the same + * {@code '(' [operand] [operator] [operand] ')'}. */ @Override public String toStringAST() { @@ -103,8 +104,8 @@ public abstract class Operator extends SpelNodeImpl { return (dc.areNumbers && dc.areCompatible); } - /** - * Numeric comparison operators share very similar generated code, only differing in + /** + * Numeric comparison operators share very similar generated code, only differing in * two comparison instructions. */ protected void generateComparisonCode(MethodVisitor mv, CodeFlow cf, int compInstruction1, int compInstruction2) { @@ -112,20 +113,20 @@ public abstract class Operator extends SpelNodeImpl { SpelNodeImpl right = getRightOperand(); String leftDesc = left.exitTypeDescriptor; String rightDesc = right.exitTypeDescriptor; - + boolean unboxLeft = !CodeFlow.isPrimitive(leftDesc); boolean unboxRight = !CodeFlow.isPrimitive(rightDesc); DescriptorComparison dc = DescriptorComparison.checkNumericCompatibility( leftDesc, rightDesc, this.leftActualDescriptor, this.rightActualDescriptor); char targetType = dc.compatibleType; // CodeFlow.toPrimitiveTargetDesc(leftDesc); - + cf.enterCompilationScope(); left.generateCode(mv, cf); cf.exitCompilationScope(); if (unboxLeft) { CodeFlow.insertUnboxInsns(mv, targetType, leftDesc); } - + cf.enterCompilationScope(); right.generateCode(mv, cf); cf.exitCompilationScope(); @@ -141,11 +142,11 @@ public abstract class Operator extends SpelNodeImpl { mv.visitJumpInsn(compInstruction1, elseTarget); } else if (targetType == 'F') { - mv.visitInsn(FCMPG); + mv.visitInsn(FCMPG); mv.visitJumpInsn(compInstruction1, elseTarget); } else if (targetType == 'J') { - mv.visitInsn(LCMP); + mv.visitInsn(LCMP); mv.visitJumpInsn(compInstruction1, elseTarget); } else if (targetType == 'I') { @@ -217,6 +218,10 @@ public abstract class Operator extends SpelNodeImpl { return left.toString().equals(right.toString()); } + if (left instanceof Boolean && right instanceof Boolean) { + return left.equals(right); + } + if (ObjectUtils.nullSafeEquals(left, right)) { return true; } @@ -230,7 +235,7 @@ public abstract class Operator extends SpelNodeImpl { return false; } - + /** * A descriptor comparison encapsulates the result of comparing descriptor @@ -253,7 +258,7 @@ public abstract class Operator extends SpelNodeImpl { this.areCompatible = areCompatible; this.compatibleType = compatibleType; } - + /** * Return an object that indicates whether the input descriptors are compatible. *

A declared descriptor is what could statically be determined (e.g. from looking @@ -277,7 +282,7 @@ public abstract class Operator extends SpelNodeImpl { boolean leftNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(ld); boolean rightNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(rd); - + // If the declared descriptors aren't providing the information, try the actual descriptors if (!leftNumeric && !ObjectUtils.nullSafeEquals(ld, leftActualDescriptor)) { ld = leftActualDescriptor; @@ -287,7 +292,7 @@ public abstract class Operator extends SpelNodeImpl { rd = rightActualDescriptor; rightNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(rd); } - + if (leftNumeric && rightNumeric) { if (CodeFlow.areBoxingCompatible(ld, rd)) { return new DescriptorComparison(true, true, CodeFlow.toPrimitiveTargetDesc(ld)); @@ -298,7 +303,7 @@ public abstract class Operator extends SpelNodeImpl { } else { return DescriptorComparison.NOT_NUMBERS; - } + } } } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java index fbb6fb7697..b8420a98e3 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpression.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -118,10 +118,8 @@ public class SpelExpression implements Expression { public Object getValue() throws EvaluationException { if (this.compiledAst != null) { try { - TypedValue contextRoot = - (this.evaluationContext != null ? this.evaluationContext.getRootObject() : null); - return this.compiledAst.getValue( - (contextRoot != null ? contextRoot.getValue() : null), this.evaluationContext); + EvaluationContext context = getEvaluationContext(); + return this.compiledAst.getValue(context.getRootObject().getValue(), context); } catch (Throwable ex) { // If running in mixed mode, revert to interpreted @@ -148,10 +146,8 @@ public class SpelExpression implements Expression { public T getValue(@Nullable Class expectedResultType) throws EvaluationException { if (this.compiledAst != null) { try { - TypedValue contextRoot = - (this.evaluationContext != null ? this.evaluationContext.getRootObject() : null); - Object result = this.compiledAst.getValue( - (contextRoot != null ? contextRoot.getValue() : null), this.evaluationContext); + EvaluationContext context = getEvaluationContext(); + Object result = this.compiledAst.getValue(context.getRootObject().getValue(), context); if (expectedResultType == null) { return (T) result; } @@ -185,7 +181,7 @@ public class SpelExpression implements Expression { public Object getValue(Object rootObject) throws EvaluationException { if (this.compiledAst != null) { try { - return this.compiledAst.getValue(rootObject, evaluationContext); + return this.compiledAst.getValue(rootObject, getEvaluationContext()); } catch (Throwable ex) { // If running in mixed mode, revert to interpreted @@ -213,7 +209,7 @@ public class SpelExpression implements Expression { public T getValue(Object rootObject, @Nullable Class expectedResultType) throws EvaluationException { if (this.compiledAst != null) { try { - Object result = this.compiledAst.getValue(rootObject, null); + Object result = this.compiledAst.getValue(rootObject, getEvaluationContext()); if (expectedResultType == null) { return (T)result; } @@ -250,8 +246,7 @@ public class SpelExpression implements Expression { if (this.compiledAst != null) { try { - TypedValue contextRoot = context.getRootObject(); - return this.compiledAst.getValue(contextRoot.getValue(), context); + return this.compiledAst.getValue(context.getRootObject().getValue(), context); } catch (Throwable ex) { // If running in mixed mode, revert to interpreted @@ -280,8 +275,7 @@ public class SpelExpression implements Expression { if (this.compiledAst != null) { try { - TypedValue contextRoot = context.getRootObject(); - Object result = this.compiledAst.getValue(contextRoot.getValue(), context); + Object result = this.compiledAst.getValue(context.getRootObject().getValue(), context); if (expectedResultType != null) { return ExpressionUtils.convertTypedValue(context, new TypedValue(result), expectedResultType); } @@ -315,7 +309,7 @@ public class SpelExpression implements Expression { if (this.compiledAst != null) { try { - return this.compiledAst.getValue(rootObject,context); + return this.compiledAst.getValue(rootObject, context); } catch (Throwable ex) { // If running in mixed mode, revert to interpreted