Support symbolic boolean operators for OR and AND
SpEL typically supports logical operators for boolean expressions consistent with standard Java language syntax. However, the operators for logical AND and logical OR are currently only supported as textual operators. In other words, SpEL does not support the use of && and || as logical operators. The SpEL tokenizer has now been modified to recognize && and || as symbolic boolean operators. The parser has been modified to allow the use of either the textual or symbolic operators. Issue: SPR-9614
This commit is contained in:
parent
6249539426
commit
58e6214b7b
|
|
@ -169,7 +169,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
//logicalOrExpression : logicalAndExpression (OR^ logicalAndExpression)*;
|
||||
private SpelNodeImpl eatLogicalOrExpression() {
|
||||
SpelNodeImpl expr = eatLogicalAndExpression();
|
||||
while (peekIdentifierToken("or")) {
|
||||
while (peekIdentifierToken("or") || peekToken(TokenKind.SYMBOLIC_OR)) {
|
||||
Token t = nextToken(); //consume OR
|
||||
SpelNodeImpl rhExpr = eatLogicalAndExpression();
|
||||
checkRightOperand(t,rhExpr);
|
||||
|
|
@ -181,7 +181,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
// logicalAndExpression : relationalExpression (AND^ relationalExpression)*;
|
||||
private SpelNodeImpl eatLogicalAndExpression() {
|
||||
SpelNodeImpl expr = eatRelationalExpression();
|
||||
while (peekIdentifierToken("and")) {
|
||||
while (peekIdentifierToken("and") || peekToken(TokenKind.SYMBOLIC_AND)) {
|
||||
Token t = nextToken();// consume 'AND'
|
||||
SpelNodeImpl rhExpr = eatRelationalExpression();
|
||||
checkRightOperand(t,rhExpr);
|
||||
|
|
@ -432,7 +432,6 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//startNode
|
||||
// : parenExpr | literal
|
||||
// | type
|
||||
|
|
@ -513,7 +512,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
private boolean maybeEatNullReference() {
|
||||
if (peekToken(TokenKind.IDENTIFIER)) {
|
||||
Token nullToken = peekToken();
|
||||
if (!nullToken.stringValue().toLowerCase().equals("null")) {
|
||||
if (!nullToken.stringValue().equalsIgnoreCase("null")) {
|
||||
return false;
|
||||
}
|
||||
nextToken();
|
||||
|
|
@ -805,7 +804,6 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
return t.kind==TokenKind.SELECT || t.kind==TokenKind.SELECT_FIRST || t.kind==TokenKind.SELECT_LAST;
|
||||
}
|
||||
|
||||
|
||||
private boolean moreTokens() {
|
||||
return tokenStreamPointer<tokenStream.size();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -29,7 +29,7 @@ enum TokenKind {
|
|||
DIV("/"), GE(">="), GT(">"), LE("<="), LT("<"), EQ("=="), NE("!="),
|
||||
MOD("%"), NOT("!"), ASSIGN("="), INSTANCEOF("instanceof"), MATCHES("matches"), BETWEEN("between"),
|
||||
SELECT("?["), POWER("^"),
|
||||
ELVIS("?:"), SAFE_NAVI("?."), BEAN_REF("@")
|
||||
ELVIS("?:"), SAFE_NAVI("?."), BEAN_REF("@"), SYMBOLIC_OR("||"), SYMBOLIC_AND("&&")
|
||||
;
|
||||
|
||||
char[] tokenChars;
|
||||
|
|
|
|||
|
|
@ -128,6 +128,16 @@ class Tokenizer {
|
|||
pushCharToken(TokenKind.ASSIGN);
|
||||
}
|
||||
break;
|
||||
case '&':
|
||||
if (isTwoCharToken(TokenKind.SYMBOLIC_AND)) {
|
||||
pushPairToken(TokenKind.SYMBOLIC_AND);
|
||||
}
|
||||
break;
|
||||
case '|':
|
||||
if (isTwoCharToken(TokenKind.SYMBOLIC_OR)) {
|
||||
pushPairToken(TokenKind.SYMBOLIC_OR);
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
if (isTwoCharToken(TokenKind.SELECT)) {
|
||||
pushPairToken(TokenKind.SELECT);
|
||||
|
|
@ -200,7 +210,6 @@ class Tokenizer {
|
|||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
// STRING_LITERAL: '\''! (APOS|~'\'')* '\''!;
|
||||
private void lexQuotedStringLiteral() {
|
||||
int start = pos;
|
||||
|
|
@ -242,7 +251,6 @@ class Tokenizer {
|
|||
tokens.add(new Token(TokenKind.LITERAL_STRING, subarray(start,pos), start, pos));
|
||||
}
|
||||
|
||||
|
||||
// REAL_LITERAL :
|
||||
// ('.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
|
||||
// ((DECIMAL_DIGIT)+ '.' (DECIMAL_DIGIT)+ (EXPONENT_PART)? (REAL_TYPE_SUFFIX)?) |
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ public class SpelParserTests {
|
|||
assertEquals(5, expr.getValue());
|
||||
expr = parser.parseRaw("2 + 3");
|
||||
assertEquals(5, expr.getValue());
|
||||
expr = parser.parseRaw("2\n+ 3");
|
||||
expr = parser.parseRaw("2\n+\t3");
|
||||
assertEquals(5, expr.getValue());
|
||||
expr = parser.parseRaw("2\r\n+\t3");
|
||||
assertEquals(5, expr.getValue());
|
||||
|
|
@ -229,6 +229,24 @@ public class SpelParserTests {
|
|||
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void booleanOperators_symbolic_spr9614() throws EvaluationException, ParseException {
|
||||
SpelExpression expr = new SpelExpressionParser().parseRaw("true");
|
||||
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
|
||||
expr = new SpelExpressionParser().parseRaw("false");
|
||||
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
|
||||
expr = new SpelExpressionParser().parseRaw("false && false");
|
||||
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
|
||||
expr = new SpelExpressionParser().parseRaw("true && (true || false)");
|
||||
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
|
||||
expr = new SpelExpressionParser().parseRaw("true && true || false");
|
||||
assertEquals(Boolean.TRUE, expr.getValue(Boolean.class));
|
||||
expr = new SpelExpressionParser().parseRaw("!true");
|
||||
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
|
||||
expr = new SpelExpressionParser().parseRaw("!(false || true)");
|
||||
assertEquals(Boolean.FALSE, expr.getValue(Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stringLiterals() throws EvaluationException, ParseException {
|
||||
SpelExpression expr = new SpelExpressionParser().parseRaw("'howdy'");
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ Changes in version 3.2 M2 (2012-08-xx)
|
|||
|
||||
* spring-test module now depends on junit:junit-dep (SPR-6966)
|
||||
* now inferring return type of generic factory methods (SPR-9493)
|
||||
* SpEL Tokenizer now supports methods on integers (SPR-9612)
|
||||
* SpEL now supports method invocations on integers (SPR-9612)
|
||||
* SpEL now supports symbolic boolean operators for OR and AND (SPR-9614)
|
||||
* introduced support for case-insensitive null literals in SpEL expressions (SPR-9613)
|
||||
* now using BufferedInputStream in SimpleMetaDataReader to double performance (SPR-9528)
|
||||
* introduced "repeatCount" property in Quartz SimpleTriggerFactoryBean (SPR-9521)
|
||||
|
|
|
|||
Loading…
Reference in New Issue