Browse Source

SPR-5905: support for inner type references in type references 'T(com.foo.A$B)' or in ctor calls 'new com.foo.A$B()'

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1484 50f2f4bb-b051-0410-bef5-90022cba6387
pull/1/head
Andy Clement 17 years ago
parent
commit
38327100d6
  1. 5
      org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java
  2. 23
      org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java
  3. 28
      org.springframework.expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java

5
org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/QualifiedIdentifier.java

@ -43,10 +43,11 @@ public class QualifiedIdentifier extends SpelNodeImpl { @@ -43,10 +43,11 @@ public class QualifiedIdentifier extends SpelNodeImpl {
if (this.value == null) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < getChildCount(); i++) {
if (i > 0) {
Object value = children[i].getValueInternal(state).getValue();
if (i > 0 && !value.toString().startsWith("$")) {
sb.append(".");
}
sb.append(children[i].getValueInternal(state).getValue());
sb.append(value);
}
this.value = new TypedValue(sb.toString(),STRING_TYPE_DESCRIPTOR);
}

23
org.springframework.expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java

@ -452,7 +452,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { @@ -452,7 +452,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
}
nextToken();
eatToken(TokenKind.LPAREN);
SpelNodeImpl node = eatPossiblyQualifiedId();
SpelNodeImpl node = eatPossiblyQualifiedId(true);
// dotted qualified id
eatToken(TokenKind.RPAREN);
constructedNodes.push(new TypeReference(toPos(typeName),node));
@ -515,13 +515,26 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { @@ -515,13 +515,26 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
return true;
}
private SpelNodeImpl eatPossiblyQualifiedId() {
/**
* Eat an identifier, possibly qualified (meaning that it is dotted). If the dollarAllowed parameter is true then
* it will process any dollar characters found between names, and this allows it to support inner type references
* correctly. For example 'com.foo.bar.Outer$Inner' will produce the identifier sequence com, foo, bar, Outer, $Inner,
* note that the $ has been prefixed onto the Inner identifier. The code in TypeReference which reforms this into
* a typename copes with the $ prefixed identifiers.
* TODO AndyC Could create complete identifiers (a.b.c) here rather than a sequence of them? (a, b, c)
*/
private SpelNodeImpl eatPossiblyQualifiedId(boolean dollarAllowed) {
List<SpelNodeImpl> qualifiedIdPieces = new ArrayList<SpelNodeImpl>();
Token startnode = eatToken(TokenKind.IDENTIFIER);
qualifiedIdPieces.add(new Identifier(startnode.stringValue(),toPos(startnode)));
while (peekToken(TokenKind.DOT,true)) {
boolean dollar = false;
while (peekToken(TokenKind.DOT,true) || (dollarAllowed && (dollar = peekToken(TokenKind.DOLLAR,true)))) {
Token node = eatToken(TokenKind.IDENTIFIER);
qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node)));
if (dollar) {
qualifiedIdPieces.add(new Identifier("$"+node.stringValue(),((node.startpos-1)<<16)+node.endpos));
} else {
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()]));
}
@ -549,7 +562,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser { @@ -549,7 +562,7 @@ public class SpelExpressionParser extends TemplateAwareExpressionParser {
private boolean maybeEatConstructorReference() {
if (peekIdentifierToken("new")) {
Token newToken = nextToken();
SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId();
SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId(true);
List<SpelNodeImpl> nodes = new ArrayList<SpelNodeImpl>();
nodes.add(possiblyQualifiedConstructorName);
eatConstructorArgs(nodes);

28
org.springframework.expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java

@ -99,6 +99,9 @@ public class SpringEL300Tests extends ExpressionTestCase { @@ -99,6 +99,9 @@ public class SpringEL300Tests extends ExpressionTestCase {
if (typename.equals("Spr5899Class")) {
return Spr5899Class.class;
}
if (typename.equals("Outer")) {
return Outer.class;
}
return super.findType(typename);
}
}
@ -126,6 +129,31 @@ public class SpringEL300Tests extends ExpressionTestCase { @@ -126,6 +129,31 @@ public class SpringEL300Tests extends ExpressionTestCase {
return "instance";
}
}
@Test
public void testSPR5905_InnerTypeReferences() throws Exception {
StandardEvaluationContext eContext = new StandardEvaluationContext(new Spr5899Class());
Expression expr = new SpelExpressionParser().parse("T(java.util.Map$Entry)");
Assert.assertEquals(Map.Entry.class,expr.getValue(eContext));
expr = new SpelExpressionParser().parse("T(org.springframework.expression.spel.SpringEL300Tests$Outer$Inner).run()");
Assert.assertEquals(12,expr.getValue(eContext));
expr = new SpelExpressionParser().parse("new org.springframework.expression.spel.SpringEL300Tests$Outer$Inner().run2()");
Assert.assertEquals(13,expr.getValue(eContext));
}
static class Outer {
static class Inner {
public Inner() {}
public static int run() {
return 12;
}
public int run2() {
return 13;
}
}
}
@SuppressWarnings("unchecked")
@Test

Loading…
Cancel
Save