Fix compilation of SpEL elvis/ternary expressions

Without this fix the compiled version of elvis
actual behaved differently to the interpreted version
if the value being queried was an empty string. This
is now fixed. It also now correctly handles the
query value being a primitive and addresses the
findings of SPR-15192 where some type inferencing
logic was trying to be too clever, that code has
been deleted.

Issue: SPR-15192
(cherry picked from commit d41d28f)
This commit is contained in:
Andy Clement
2017-02-06 18:43:10 +01:00
committed by Juergen Hoeller
parent dfa8a7c358
commit 7879bdfc1d
3 changed files with 200 additions and 19 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2017 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.
@@ -35,7 +35,7 @@ import org.springframework.util.StringUtils;
public class Elvis extends SpelNodeImpl {
public Elvis(int pos, SpelNodeImpl... args) {
super(pos,args);
super(pos, args);
}
@@ -49,6 +49,7 @@ public class Elvis extends SpelNodeImpl {
@Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
TypedValue value = this.children[0].getValueInternal(state);
// If this check is changed, the generateCode method will need changing too
if (!StringUtils.isEmpty(value.getValue())) {
return value;
}
@@ -77,11 +78,17 @@ public class Elvis extends SpelNodeImpl {
// exit type descriptor can be null if both components are literal expressions
computeExitTypeDescriptor();
this.children[0].generateCode(mv, cf);
CodeFlow.insertBoxIfNecessary(mv, cf.lastDescriptor().charAt(0));
Label elseTarget = new Label();
Label endOfIf = new Label();
mv.visitInsn(DUP);
mv.visitJumpInsn(IFNULL, elseTarget);
mv.visitJumpInsn(GOTO, endOfIf);
// Also check if empty string, as per the code in the interpreted version
mv.visitInsn(DUP);
mv.visitLdcInsn("");
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z",false);
mv.visitJumpInsn(IFEQ, endOfIf); // if not empty, drop through to elseTarget
mv.visitLabel(elseTarget);
mv.visitInsn(POP);
this.children[1].generateCode(mv, cf);
@@ -100,12 +107,6 @@ public class Elvis extends SpelNodeImpl {
if (conditionDescriptor.equals(ifNullValueDescriptor)) {
this.exitTypeDescriptor = conditionDescriptor;
}
else if (conditionDescriptor.equals("Ljava/lang/Object") && !CodeFlow.isPrimitive(ifNullValueDescriptor)) {
this.exitTypeDescriptor = ifNullValueDescriptor;
}
else if (ifNullValueDescriptor.equals("Ljava/lang/Object") && !CodeFlow.isPrimitive(conditionDescriptor)) {
this.exitTypeDescriptor = conditionDescriptor;
}
else {
// Use the easiest to compute common super type
this.exitTypeDescriptor = "Ljava/lang/Object";

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2017 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.
@@ -35,7 +35,7 @@ import org.springframework.expression.spel.SpelMessage;
public class Ternary extends SpelNodeImpl {
public Ternary(int pos, SpelNodeImpl... args) {
super(pos,args);
super(pos, args);
}
@@ -71,12 +71,6 @@ public class Ternary extends SpelNodeImpl {
if (leftDescriptor.equals(rightDescriptor)) {
this.exitTypeDescriptor = leftDescriptor;
}
else if (leftDescriptor.equals("Ljava/lang/Object") && !CodeFlow.isPrimitive(rightDescriptor)) {
this.exitTypeDescriptor = rightDescriptor;
}
else if (rightDescriptor.equals("Ljava/lang/Object") && !CodeFlow.isPrimitive(leftDescriptor)) {
this.exitTypeDescriptor = leftDescriptor;
}
else {
// Use the easiest to compute common super type
this.exitTypeDescriptor = "Ljava/lang/Object";