Skip to content

Commit

Permalink
SpelExpression consistently exposes EvaluationContext to compiled AST
Browse files Browse the repository at this point in the history
Operator includes explicit support for Boolean comparisons now.

Issue: SPR-17229

(cherry picked from commit 51cee65)
  • Loading branch information
jhoeller committed Aug 31, 2018
1 parent 56194a1 commit 1a626ab
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 30 deletions.
@@ -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.
Expand Down Expand Up @@ -40,7 +40,7 @@
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
Expand Down Expand Up @@ -70,7 +70,8 @@ public final String getOperatorName() {
}

/**
* 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() {
Expand Down Expand Up @@ -100,8 +101,8 @@ protected boolean isCompilableOperatorUsingNumerics() {
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) {
Expand All @@ -113,14 +114,14 @@ protected void generateComparisonCode(MethodVisitor mv, CodeFlow cf, int compIns
DescriptorComparison dc = DescriptorComparison.checkNumericCompatibility(
leftDesc, rightDesc, this.leftActualDescriptor, this.rightActualDescriptor);
char targetType = dc.compatibleType; // CodeFlow.toPrimitiveTargetDesc(leftDesc);

cf.enterCompilationScope();
getLeftOperand().generateCode(mv, cf);
cf.exitCompilationScope();
if (unboxLeft) {
CodeFlow.insertUnboxInsns(mv, targetType, leftDesc);
}

cf.enterCompilationScope();
getRightOperand().generateCode(mv, cf);
cf.exitCompilationScope();
Expand All @@ -136,11 +137,11 @@ protected void generateComparisonCode(MethodVisitor mv, CodeFlow cf, int compIns
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') {
Expand Down Expand Up @@ -212,6 +213,10 @@ else if (leftNumber instanceof Byte || rightNumber instanceof Byte) {
return left.toString().equals(right.toString());
}

if (left instanceof Boolean && right instanceof Boolean) {
return left.equals(right);
}

if (ObjectUtils.nullSafeEquals(left, right)) {
return true;
}
Expand All @@ -225,7 +230,7 @@ else if (leftNumber instanceof Byte || rightNumber instanceof Byte) {

return false;
}


/**
* A descriptor comparison encapsulates the result of comparing descriptor
Expand All @@ -248,7 +253,7 @@ private DescriptorComparison(boolean areNumbers, boolean areCompatible, char com
this.areCompatible = areCompatible;
this.compatibleType = compatibleType;
}

/**
* Return an object that indicates whether the input descriptors are compatible.
* <p>A declared descriptor is what could statically be determined (e.g. from looking
Expand All @@ -271,7 +276,7 @@ public static DescriptorComparison checkNumericCompatibility(String leftDeclared

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;
Expand All @@ -281,7 +286,7 @@ public static DescriptorComparison checkNumericCompatibility(String leftDeclared
rd = rightActualDescriptor;
rightNumeric = CodeFlow.isPrimitiveOrUnboxableSupportedNumberOrBoolean(rd);
}

if (leftNumeric && rightNumeric) {
if (CodeFlow.areBoxingCompatible(ld, rd)) {
return new DescriptorComparison(true, true, CodeFlow.toPrimitiveTargetDesc(ld));
Expand All @@ -292,7 +297,7 @@ public static DescriptorComparison checkNumericCompatibility(String leftDeclared
}
else {
return DescriptorComparison.NOT_NUMBERS;
}
}
}
}

Expand Down
@@ -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.
Expand Down Expand Up @@ -114,10 +114,8 @@ public String getExpressionString() {
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
Expand All @@ -143,10 +141,8 @@ public Object getValue() throws EvaluationException {
public <T> T getValue(Class<T> 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;
}
Expand Down Expand Up @@ -179,7 +175,7 @@ public <T> T getValue(Class<T> expectedResultType) throws EvaluationException {
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
Expand All @@ -206,7 +202,7 @@ public Object getValue(Object rootObject) throws EvaluationException {
public <T> T getValue(Object rootObject, Class<T> 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;
}
Expand Down Expand Up @@ -242,8 +238,7 @@ public Object getValue(EvaluationContext context) throws EvaluationException {

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
Expand Down Expand Up @@ -271,8 +266,7 @@ public <T> T getValue(EvaluationContext context, Class<T> expectedResultType) th

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);
}
Expand Down Expand Up @@ -305,7 +299,7 @@ public Object getValue(EvaluationContext context, Object rootObject) throws Eval

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
Expand Down

0 comments on commit 1a626ab

Please sign in to comment.