From 58756b023cdd28683d82c8358ef8e202d6fa5022 Mon Sep 17 00:00:00 2001 From: Andy Clement Date: Tue, 24 Nov 2015 13:37:53 -0800 Subject: [PATCH] Ensure cast correctly included for OpPlus compilation When the plus operator is used between strings in a SpEL expression and that expression is compiled, it is important to include a cast if computation of any of the operands isn't obviously leaving strings on the stack. Likewise if the stack contents are known to be strings, a cast should not be included. Issue: SPR-12426 --- .../expression/spel/ast/OpPlus.java | 2 +- .../spel/SpelCompilationCoverageTests.java | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java index 6eef879f66..d94f080426 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/OpPlus.java @@ -198,7 +198,7 @@ public class OpPlus extends Operator { else { cf.enterCompilationScope(); operand.generateCode(mv,cf); - if (cf.lastDescriptor() != "Ljava/lang/String") { + if (!"Ljava/lang/String".equals(cf.lastDescriptor())) { mv.visitTypeInsn(CHECKCAST, "java/lang/String"); } cf.exitCompilationScope(); diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java index c69ccae456..84bf8d7ea3 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelCompilationCoverageTests.java @@ -4194,6 +4194,29 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { assertEquals("value1",stringify(expression.getValue(mapArray))); assertEquals("Ljava/lang/Object",getAst().getExitDescriptor()); } + + @Test + public void plusNeedingCheckcast_SPR12426() { + expression = parser.parseExpression("object + ' world'"); + Object v = expression.getValue(new FooObject()); + assertEquals("hello world",v); + assertCanCompile(expression); + assertEquals("hello world",v); + + expression = parser.parseExpression("object + ' world'"); + v = expression.getValue(new FooString()); + assertEquals("hello world",v); + assertCanCompile(expression); + assertEquals("hello world",v); + } + + public static class FooObject { + public Object getObject() { return "hello"; } + } + + public static class FooString { + public String getObject() { return "hello"; } + } @Test public void mixingItUp_propertyAccessIndexerOpLtTernaryRootNull() throws Exception {