SPR-5905: support for inner type references in type references 'T(com.foo.A$B)' or in ctor calls 'new com.foo.A$B()'
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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 {
|
||||
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);
|
||||
|
||||
@@ -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 {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user