Browse Source

Merge pull request #163 from philwebb/SPR-9862

# By Phillip Webb
* SPR-9862:
  Allow SpEL reserved words in type package names
pull/99/merge
Chris Beams 14 years ago
parent
commit
99b2f6a081
  1. 42
      spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java
  2. 6
      spring-expression/src/test/java/org/springframework/expression/spel/ParserErrorMessagesTests.java
  3. 50
      spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java
  4. 29
      spring-expression/src/test/java/org/springframework/expression/spel/testresources/le/div/mod/reserved/Reserver.java

42
spring-expression/src/main/java/org/springframework/expression/spel/standard/InternalSpelExpressionParser.java

@ -17,8 +17,10 @@ @@ -17,8 +17,10 @@
package org.springframework.expression.spel.standard;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import java.util.regex.Pattern;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
@ -29,6 +31,7 @@ import org.springframework.expression.spel.SpelParseException; @@ -29,6 +31,7 @@ import org.springframework.expression.spel.SpelParseException;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.ast.*;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Hand written SpEL parser. Instances are reusable but are not thread safe.
@ -38,6 +41,8 @@ import org.springframework.util.Assert; @@ -38,6 +41,8 @@ import org.springframework.util.Assert;
*/
class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
private static final Pattern VALID_QUALIFIED_ID_PATTERN = Pattern.compile("[\\p{L}\\p{N}_$]+");
// The expression being parsed
private String expressionString;
@ -567,14 +572,35 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser { @@ -567,14 +572,35 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
* TODO AndyC Could create complete identifiers (a.b.c) here rather than a sequence of them? (a, b, c)
*/
private SpelNodeImpl eatPossiblyQualifiedId() {
List<SpelNodeImpl> qualifiedIdPieces = new ArrayList<SpelNodeImpl>();
Token startnode = eatToken(TokenKind.IDENTIFIER);
qualifiedIdPieces.add(new Identifier(startnode.stringValue(),toPos(startnode)));
while (peekToken(TokenKind.DOT,true)) {
Token node = eatToken(TokenKind.IDENTIFIER);
qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node)));
}
return new QualifiedIdentifier(toPos(startnode.startpos,qualifiedIdPieces.get(qualifiedIdPieces.size()-1).getEndPosition()),qualifiedIdPieces.toArray(new SpelNodeImpl[qualifiedIdPieces.size()]));
LinkedList<SpelNodeImpl> qualifiedIdPieces = new LinkedList<SpelNodeImpl>();
Token node = peekToken();
while (isValidQualifiedId(node)) {
nextToken();
if(node.kind != TokenKind.DOT) {
qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node)));
}
node = peekToken();
}
if(qualifiedIdPieces.isEmpty()) {
if(node == null) {
raiseInternalException( expressionString.length(), SpelMessage.OOD);
}
raiseInternalException(node.startpos, SpelMessage.NOT_EXPECTED_TOKEN,
"qualified ID", node.getKind().toString().toLowerCase());
}
int pos = toPos(qualifiedIdPieces.getFirst().getStartPosition(), qualifiedIdPieces.getLast().getEndPosition());
return new QualifiedIdentifier(pos, qualifiedIdPieces.toArray(new SpelNodeImpl[qualifiedIdPieces.size()]));
}
private boolean isValidQualifiedId(Token node) {
if(node == null || node.kind == TokenKind.LITERAL_STRING) {
return false;
}
if(node.kind == TokenKind.DOT || node.kind == TokenKind.IDENTIFIER) {
return true;
}
String value = node.stringValue();
return StringUtils.hasLength(value) && VALID_QUALIFIED_ID_PATTERN.matcher(value).matches();
}
// This is complicated due to the support for dollars in identifiers. Dollars are normally separate tokens but

6
spring-expression/src/test/java/org/springframework/expression/spel/ParserErrorMessagesTests.java

@ -1,5 +1,5 @@ @@ -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.
@ -20,7 +20,7 @@ import org.junit.Test; @@ -20,7 +20,7 @@ import org.junit.Test;
/**
* Tests the messages and exceptions that come out for badly formed expressions
*
*
* @author Andy Clement
*/
public class ParserErrorMessagesTests extends ExpressionTestCase {
@ -56,7 +56,7 @@ public class ParserErrorMessagesTests extends ExpressionTestCase { @@ -56,7 +56,7 @@ public class ParserErrorMessagesTests extends ExpressionTestCase {
// T() can only take an identifier (possibly qualified), not a literal
// message ought to say identifier rather than ID
parseAndCheckError("null instanceof T('a')", SpelMessage.NOT_EXPECTED_TOKEN, 18,
"identifier","literal_string");
"qualified ID","literal_string");
}
}

50
spring-expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java → spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java

@ -16,32 +16,49 @@ @@ -16,32 +16,49 @@
package org.springframework.expression.spel;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import junit.framework.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.*;
import org.springframework.expression.AccessException;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.MethodExecutor;
import org.springframework.expression.MethodResolver;
import org.springframework.expression.ParserContext;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.ReflectiveMethodResolver;
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeLocator;
import org.springframework.expression.spel.testresources.le.div.mod.reserved.Reserver;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;
/**
* Tests based on Jiras up to the release of Spring 3.0.0
* Reproduction tests cornering various SpEL JIRA issues.
*
* @author Andy Clement
* @author Clark Duplichien
*/
public class SpringEL300Tests extends ExpressionTestCase {
public class SpelReproTests extends ExpressionTestCase {
@Test
public void testNPE_SPR5661() {
@ -147,12 +164,12 @@ public class SpringEL300Tests extends ExpressionTestCase { @@ -147,12 +164,12 @@ public class SpringEL300Tests extends ExpressionTestCase {
Expression expr = new SpelExpressionParser().parseRaw("T(java.util.Map$Entry)");
Assert.assertEquals(Map.Entry.class,expr.getValue(eContext));
expr = new SpelExpressionParser().parseRaw("T(org.springframework.expression.spel.SpringEL300Tests$Outer$Inner).run()");
expr = new SpelExpressionParser().parseRaw("T(org.springframework.expression.spel.SpelReproTests$Outer$Inner).run()");
Assert.assertEquals(12,expr.getValue(eContext));
expr = new SpelExpressionParser().parseRaw("new org.springframework.expression.spel.SpringEL300Tests$Outer$Inner().run2()");
expr = new SpelExpressionParser().parseRaw("new org.springframework.expression.spel.SpelReproTests$Outer$Inner().run2()");
Assert.assertEquals(13,expr.getValue(eContext));
}
}
static class Outer {
static class Inner {
@ -1034,6 +1051,15 @@ public class SpringEL300Tests extends ExpressionTestCase { @@ -1034,6 +1051,15 @@ public class SpringEL300Tests extends ExpressionTestCase {
Assert.assertEquals("abc",exp.getValue(ctx));
}
@Test
public void testReservedWordProperties_9862() throws Exception {
StandardEvaluationContext ctx = new StandardEvaluationContext();
SpelExpressionParser parser = new SpelExpressionParser();
SpelExpression expression = parser.parseRaw("T(org.springframework.expression.spel.testresources.le.div.mod.reserved.Reserver).CONST");
Object value = expression.getValue(ctx);
assertEquals(value, Reserver.CONST);
}
/**
* We add property accessors in the order:
* First, Second, Third, Fourth.

29
spring-expression/src/test/java/org/springframework/expression/spel/testresources/le/div/mod/reserved/Reserver.java

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.expression.spel.testresources.le.div.mod.reserved;
/**
* For use when testing that the SpEL expression parser can accommodate SpEL's own
* reserved words being used in package names.
*
* @author Phillip Webb
*/
public class Reserver {
public static final String CONST = "Const";
}
Loading…
Cancel
Save