diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java index 28c74aba2e..10ec6b2bb4 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/Elvis.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. @@ -79,10 +79,12 @@ public class Elvis extends SpelNodeImpl { public void generateCode(MethodVisitor mv, CodeFlow cf) { // exit type descriptor can be null if both components are literal expressions computeExitTypeDescriptor(); + cf.enterCompilationScope(); this.children[0].generateCode(mv, cf); String lastDesc = cf.lastDescriptor(); Assert.state(lastDesc != null, "No last descriptor"); CodeFlow.insertBoxIfNecessary(mv, lastDesc.charAt(0)); + cf.exitCompilationScope(); Label elseTarget = new Label(); Label endOfIf = new Label(); mv.visitInsn(DUP); @@ -95,12 +97,14 @@ public class Elvis extends SpelNodeImpl { mv.visitJumpInsn(IFEQ, endOfIf); // if not empty, drop through to elseTarget mv.visitLabel(elseTarget); mv.visitInsn(POP); + cf.enterCompilationScope(); this.children[1].generateCode(mv, cf); if (!CodeFlow.isPrimitive(this.exitTypeDescriptor)) { lastDesc = cf.lastDescriptor(); Assert.state(lastDesc != null, "No last descriptor"); CodeFlow.insertBoxIfNecessary(mv, lastDesc.charAt(0)); } + cf.exitCompilationScope(); mv.visitLabel(endOfIf); cf.pushDescriptor(this.exitTypeDescriptor); } 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 9efc685753..5d4888852f 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 @@ -4898,6 +4898,71 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests { assertIsCompiled(exp); } + + @Test + public void elvisOperator_SPR17214() throws Exception { + SpelParserConfiguration spc = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null); + SpelExpressionParser sep = new SpelExpressionParser(spc); + + RecordHolder rh = null; + + expression = sep.parseExpression("record.get('abc')?:record.put('abc',expression.someLong?.longValue())"); + rh = new RecordHolder(); + assertNull(expression.getValue(rh)); + assertEquals(3L,expression.getValue(rh)); + assertCanCompile(expression); + rh = new RecordHolder(); + assertNull(expression.getValue(rh)); + assertEquals(3L,expression.getValue(rh)); + + expression = sep.parseExpression("record.get('abc')?:record.put('abc',3L.longValue())"); + rh = new RecordHolder(); + assertNull(expression.getValue(rh)); + assertEquals(3L,expression.getValue(rh)); + assertCanCompile(expression); + rh = new RecordHolder(); + assertNull(expression.getValue(rh)); + assertEquals(3L,expression.getValue(rh)); + + expression = sep.parseExpression("record.get('abc')?:record.put('abc',3L.longValue())"); + rh = new RecordHolder(); + assertNull(expression.getValue(rh)); + assertEquals(3L,expression.getValue(rh)); + assertCanCompile(expression); + rh = new RecordHolder(); + assertNull(expression.getValue(rh)); + assertEquals(3L,expression.getValue(rh)); + + expression = sep.parseExpression("record.get('abc')==null?record.put('abc',expression.someLong?.longValue()):null"); + rh = new RecordHolder(); + rh.expression.someLong=6L; + assertNull(expression.getValue(rh)); + assertEquals(6L,rh.get("abc")); + assertNull(expression.getValue(rh)); + assertCanCompile(expression); + rh = new RecordHolder(); + rh.expression.someLong=6L; + assertNull(expression.getValue(rh)); + assertEquals(6L,rh.get("abc")); + assertNull(expression.getValue(rh)); + } + + public static class RecordHolder { + public void add(String key, Long value) { + record.put(key, value); + } + public long get(String key) { + return record.get(key); + } + public Map record = new HashMap<>(); + public LongHolder expression = new LongHolder(); + + } + + public static class LongHolder { + public Long someLong = 3L; + } + @Test public void ternaryOperator_SPR15192() { SpelParserConfiguration configuration = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null);