Support [] array ref syntax in SpEL T() construct
Prior to this change, SpEL would not allow the use of '[]' in
expressions like the following:
T(foo.Bar[])
This commit updates TypeReference and InternalSpelExpressionParser to
support this syntax, avoiding the need for workarounds like:
new foo.bar[0].class
Issue: SPR-9203
This commit is contained in:
parent
0e8f5d877a
commit
916e9d6efa
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.expression.spel.ast;
|
package org.springframework.expression.spel.ast;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
|
||||||
import org.springframework.expression.EvaluationException;
|
import org.springframework.expression.EvaluationException;
|
||||||
import org.springframework.expression.TypedValue;
|
import org.springframework.expression.TypedValue;
|
||||||
import org.springframework.expression.spel.ExpressionState;
|
import org.springframework.expression.spel.ExpressionState;
|
||||||
|
|
@ -27,8 +29,15 @@ import org.springframework.expression.spel.ExpressionState;
|
||||||
*/
|
*/
|
||||||
public class TypeReference extends SpelNodeImpl {
|
public class TypeReference extends SpelNodeImpl {
|
||||||
|
|
||||||
|
private int dimensions;
|
||||||
|
|
||||||
public TypeReference(int pos,SpelNodeImpl qualifiedId) {
|
public TypeReference(int pos,SpelNodeImpl qualifiedId) {
|
||||||
|
this(pos,qualifiedId,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeReference(int pos,SpelNodeImpl qualifiedId,int dims) {
|
||||||
super(pos,qualifiedId);
|
super(pos,qualifiedId);
|
||||||
|
this.dimensions = dims;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -39,10 +48,24 @@ public class TypeReference extends SpelNodeImpl {
|
||||||
TypeCode tc = TypeCode.valueOf(typename.toUpperCase());
|
TypeCode tc = TypeCode.valueOf(typename.toUpperCase());
|
||||||
if (tc != TypeCode.OBJECT) {
|
if (tc != TypeCode.OBJECT) {
|
||||||
// it is a primitive type
|
// it is a primitive type
|
||||||
return new TypedValue(tc.getType());
|
Class<?> clazz = tc.getType();
|
||||||
|
clazz = makeArrayIfNecessary(clazz);
|
||||||
|
return new TypedValue(clazz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new TypedValue(state.findType(typename));
|
Class<?> clazz = state.findType(typename);
|
||||||
|
clazz = makeArrayIfNecessary(clazz);
|
||||||
|
return new TypedValue(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class makeArrayIfNecessary(Class clazz) {
|
||||||
|
if (dimensions!=0) {
|
||||||
|
for (int i=0;i<dimensions;i++) {
|
||||||
|
Object o = Array.newInstance(clazz, 0);
|
||||||
|
clazz = o.getClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return clazz;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -50,6 +73,9 @@ public class TypeReference extends SpelNodeImpl {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("T(");
|
sb.append("T(");
|
||||||
sb.append(getChild(0).toStringAST());
|
sb.append(getChild(0).toStringAST());
|
||||||
|
for (int d=0;d<dimensions;d++) {
|
||||||
|
sb.append("[]");
|
||||||
|
}
|
||||||
sb.append(")");
|
sb.append(")");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -497,8 +497,14 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
||||||
eatToken(TokenKind.LPAREN);
|
eatToken(TokenKind.LPAREN);
|
||||||
SpelNodeImpl node = eatPossiblyQualifiedId();
|
SpelNodeImpl node = eatPossiblyQualifiedId();
|
||||||
// dotted qualified id
|
// dotted qualified id
|
||||||
|
// Are there array dimensions?
|
||||||
|
int dims = 0;
|
||||||
|
while (peekToken(TokenKind.LSQUARE,true)) {
|
||||||
|
eatToken(TokenKind.RSQUARE);
|
||||||
|
dims++;
|
||||||
|
}
|
||||||
eatToken(TokenKind.RPAREN);
|
eatToken(TokenKind.RPAREN);
|
||||||
constructedNodes.push(new TypeReference(toPos(typeName),node));
|
constructedNodes.push(new TypeReference(toPos(typeName),node,dims));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -1175,6 +1175,35 @@ public class SpringEL300Tests extends ExpressionTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArray() {
|
||||||
|
ExpressionParser parser = new SpelExpressionParser();
|
||||||
|
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||||
|
Expression expression = null;
|
||||||
|
Object result = null;
|
||||||
|
|
||||||
|
expression = parser.parseExpression("new java.lang.Long[0].class");
|
||||||
|
result = expression.getValue(context, "");
|
||||||
|
assertEquals("Equal assertion failed: ", "class [Ljava.lang.Long;", result.toString());
|
||||||
|
|
||||||
|
expression = parser.parseExpression("T(java.lang.Long[])");
|
||||||
|
result = expression.getValue(context, "");
|
||||||
|
assertEquals("Equal assertion failed: ", "class [Ljava.lang.Long;", result.toString());
|
||||||
|
|
||||||
|
expression = parser.parseExpression("T(java.lang.String[][][])");
|
||||||
|
result = expression.getValue(context, "");
|
||||||
|
assertEquals("Equal assertion failed: ", "class [[[Ljava.lang.String;", result.toString());
|
||||||
|
assertEquals("T(java.lang.String[][][])",((SpelExpression)expression).toStringAST());
|
||||||
|
|
||||||
|
expression = parser.parseExpression("new int[0].class");
|
||||||
|
result = expression.getValue(context, "");
|
||||||
|
assertEquals("Equal assertion failed: ", "class [I", result.toString());
|
||||||
|
|
||||||
|
expression = parser.parseExpression("T(int[][])");
|
||||||
|
result = expression.getValue(context, "");
|
||||||
|
assertEquals("Equal assertion failed: ", "class [[I", result.toString());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue