Comprehensive revision of SpEL's bytecode generation and number handling (BigInteger support, doubleValue fallback)

Issue: SPR-9913
This commit is contained in:
Juergen Hoeller
2014-10-06 23:29:43 +02:00
parent e58b33a593
commit d8160b3c09
66 changed files with 1458 additions and 1352 deletions

View File

@@ -17,6 +17,7 @@
package org.springframework.expression.spel;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.junit.Test;
@@ -414,7 +415,6 @@ public class OperatorTests extends AbstractExpressionTests {
// string concatenation
evaluate("'abc'+'def'","abcdef",String.class);
//
evaluate("5 + new Integer('37')",42,Integer.class);
}
@@ -423,17 +423,17 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("'c' - 2", "a", String.class);
evaluate("3.0f - 5.0f", -2.0f, Float.class);
evaluateAndCheckError("'ab' - 2", SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
evaluateAndCheckError("2-'ab'",SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
evaluateAndCheckError("2-'ab'", SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
SpelExpression expr = (SpelExpression)parser.parseExpression("-3");
assertEquals("-3",expr.toStringAST());
assertEquals("-3", expr.toStringAST());
expr = (SpelExpression)parser.parseExpression("2-3");
assertEquals("(2 - 3)",expr.toStringAST());
assertEquals("(2 - 3)", expr.toStringAST());
evaluate("-5d",-5d,Double.class);
evaluate("-5L",-5L,Long.class);
evaluate("-5",-5,Integer.class);
evaluate("-5", -5, Integer.class);
evaluate("-new java.math.BigDecimal('5')", new BigDecimal("-5"),BigDecimal.class);
evaluateAndCheckError("-'abc'",SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
evaluateAndCheckError("-'abc'", SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
}
@Test
@@ -483,7 +483,6 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("6.0d % 3.5d", 2.5d, Double.class);
}
@Test
public void testBigDecimals() {
evaluate("3 + new java.math.BigDecimal('5')", new BigDecimal("8"), BigDecimal.class);
@@ -545,7 +544,7 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("3^2",9,Integer.class);
evaluate("3.0d^2.0d",9.0d,Double.class);
evaluate("3L^2L",9L,Long.class);
evaluate("(2^32)^2",9223372036854775807L,Long.class);
evaluate("(2^32)^2", 9223372036854775807L, Long.class);
evaluate("new java.math.BigDecimal('5') ^ 3", new BigDecimal("125"), BigDecimal.class);
}
@@ -588,6 +587,17 @@ public class OperatorTests extends AbstractExpressionTests {
evaluate("3L - 50L", -47L, Long.class);
}
@Test
public void testBigIntegers() {
evaluate("3 + new java.math.BigInteger('5')", new BigInteger("8"), BigInteger.class);
evaluate("3 - new java.math.BigInteger('5')", new BigInteger("-2"), BigInteger.class);
evaluate("3 * new java.math.BigInteger('5')", new BigInteger("15"), BigInteger.class);
evaluate("3 / new java.math.BigInteger('5')", new BigInteger("0"), BigInteger.class);
evaluate("5 % new java.math.BigInteger('3')", new BigInteger("2"), BigInteger.class);
evaluate("new java.math.BigInteger('5') % 3", new BigInteger("2"), BigInteger.class);
evaluate("new java.math.BigInteger('5') ^ 3", new BigInteger("125"), BigInteger.class);
}
private Operator getOperatorNode(SpelExpression expr) {
SpelNode node = expr.getAST();

View File

@@ -256,6 +256,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
Object resultC = expression.getValue(new TestClass1(),Object.class);
assertEquals(null,resultI);
assertEquals(null,resultC);
assertEquals(null,resultC);
}
@Test
@@ -2616,7 +2617,7 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
}
@Override
public void generateCode(String propertyName, MethodVisitor mv,CodeFlow codeflow) {
public void generateCode(String propertyName, MethodVisitor mv,CodeFlow cf) {
if (method == null) {
try {
method = Payload2.class.getDeclaredMethod("getField", String.class);
@@ -2624,10 +2625,10 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
catch (Exception e) {
}
}
String descriptor = codeflow.lastDescriptor();
String descriptor = cf.lastDescriptor();
String memberDeclaringClassSlashedDescriptor = method.getDeclaringClass().getName().replace('.','/');
if (descriptor == null) {
codeflow.loadTarget(mv);
cf.loadTarget(mv);
}
if (descriptor == null || !memberDeclaringClassSlashedDescriptor.equals(descriptor.substring(1))) {
mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor);
@@ -2684,10 +2685,10 @@ public class SpelCompilationCoverageTests extends AbstractExpressionTests {
}
@Override
public void generateCode(String propertyName, MethodVisitor mv, CodeFlow codeflow) {
String descriptor = codeflow.lastDescriptor();
public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) {
String descriptor = cf.lastDescriptor();
if (descriptor == null) {
codeflow.loadTarget(mv);
cf.loadTarget(mv);
}
mv.visitLdcInsn(propertyName);
mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get","(Ljava/lang/Object;)Ljava/lang/Object;",true);

View File

@@ -328,14 +328,14 @@ public class SpelParserTests {
public void token() {
Token token = new Token(TokenKind.NOT, 0, 3);
assertEquals(TokenKind.NOT, token.kind);
assertEquals(0, token.startpos);
assertEquals(3, token.endpos);
assertEquals(0, token.startPos);
assertEquals(3, token.endPos);
assertEquals("[NOT(!)](0,3)", token.toString());
token = new Token(TokenKind.LITERAL_STRING, "abc".toCharArray(), 0, 3);
assertEquals(TokenKind.LITERAL_STRING, token.kind);
assertEquals(0, token.startpos);
assertEquals(3, token.endpos);
assertEquals(0, token.startPos);
assertEquals(3, token.endPos);
assertEquals("[LITERAL_STRING:abc](0,3)", token.toString());
}