revised TypeDescriptor NULL and element/mapKey/mapValue type semantics

This commit is contained in:
Keith Donald
2011-06-05 04:43:18 +00:00
parent a2a4929c14
commit c84cccf06d
42 changed files with 732 additions and 758 deletions

View File

@@ -16,9 +16,6 @@
package org.springframework.expression;
import java.util.Collection;
import java.util.Map;
import org.springframework.core.convert.TypeDescriptor;
/**
@@ -56,7 +53,7 @@ public class TypedValue {
*/
public TypedValue(Object value, TypeDescriptor typeDescriptor) {
this.value = value;
this.typeDescriptor = initTypeDescriptor(value, typeDescriptor);
this.typeDescriptor = typeDescriptor;
}
public Object getValue() {
@@ -77,20 +74,4 @@ public class TypedValue {
return str.toString();
}
// interal helpers
private static TypeDescriptor initTypeDescriptor(Object value, TypeDescriptor typeDescriptor) {
if (value == null) {
return typeDescriptor;
}
if (typeDescriptor.isCollection() && Object.class.equals(typeDescriptor.getElementType())) {
return typeDescriptor.resolveCollectionElementType((Collection<?>) value);
} else if (typeDescriptor.isMap() && Object.class.equals(typeDescriptor.getMapKeyType())
&& Object.class.equals(typeDescriptor.getMapValueType())){
return typeDescriptor.resolveMapKeyValueTypes((Map<?, ?>) value);
} else {
return typeDescriptor;
}
}
}

View File

@@ -41,7 +41,12 @@ public class FormatHelper {
if (i > 0) {
sb.append(",");
}
sb.append(formatClassNameForMessage(argumentTypes.get(i).getType()));
TypeDescriptor typeDescriptor = argumentTypes.get(i);
if (typeDescriptor != null) {
sb.append(formatClassNameForMessage(typeDescriptor.getClass()));
} else {
sb.append(formatClassNameForMessage(null));
}
}
sb.append(")");
return sb.toString();

View File

@@ -106,7 +106,7 @@ public class FunctionReference extends SpelNodeImpl {
try {
ReflectionUtils.makeAccessible(method);
Object result = method.invoke(method.getClass(), functionArgs);
return new TypedValue(result, new TypeDescriptor(new MethodParameter(method,-1)));
return new TypedValue(result, new TypeDescriptor(new MethodParameter(method,-1)).narrowType(result));
}
catch (Exception ex) {
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.EXCEPTION_DURING_FUNCTION_CALL,

View File

@@ -90,9 +90,12 @@ public class Indexer extends SpelNodeImpl {
// Indexing into a Map
if (targetObject instanceof Map) {
Object possiblyConvertedKey = state.convertValue(index, targetObjectTypeDescriptor.getMapKeyTypeDescriptor());
Object o = ((Map<?, ?>) targetObject).get(possiblyConvertedKey);
return new TypedValue(o, targetObjectTypeDescriptor.getMapValueTypeDescriptor());
Object key = index;
if (targetObjectTypeDescriptor.getMapKeyType() != null) {
key = state.convertValue(key, targetObjectTypeDescriptor.getMapKeyType());
}
Object value = ((Map<?, ?>) targetObject).get(key);
return new TypedValue(value, targetObjectTypeDescriptor.mapValueType(value));
}
if (targetObject == null) {
@@ -100,22 +103,22 @@ public class Indexer extends SpelNodeImpl {
}
// if the object is something that looks indexable by an integer, attempt to treat the index value as a number
if ((targetObject instanceof Collection ) || targetObject.getClass().isArray() || targetObject instanceof String) {
int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
if (targetObject instanceof Collection || targetObject.getClass().isArray() || targetObject instanceof String) {
int idx = (Integer) state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
if (targetObject.getClass().isArray()) {
Object arrayElement = accessArrayElement(targetObject, idx);
return new TypedValue(arrayElement, targetObjectTypeDescriptor.getElementTypeDescriptor());
return new TypedValue(arrayElement, targetObjectTypeDescriptor.elementType(arrayElement));
} else if (targetObject instanceof Collection) {
Collection c = (Collection) targetObject;
if (idx >= c.size()) {
if (!growCollection(state, targetObjectTypeDescriptor.getElementType(), idx, c)) {
if (!growCollection(state, targetObjectTypeDescriptor, idx, c)) {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
}
}
int pos = 0;
for (Object o : c) {
if (pos == idx) {
return new TypedValue(o, targetObjectTypeDescriptor.getElementTypeDescriptor());
return new TypedValue(o, targetObjectTypeDescriptor.elementType(o));
}
pos++;
}
@@ -181,33 +184,38 @@ public class Indexer extends SpelNodeImpl {
throw new SpelEvaluationException(SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE);
}
// Indexing into a Map
if (targetObjectTypeDescriptor.isMap()) {
Map map = (Map)targetObject;
Object possiblyConvertedKey = index;
Object possiblyConvertedValue = newValue;
possiblyConvertedKey = state.convertValue(index.getValue(), targetObjectTypeDescriptor.getMapKeyTypeDescriptor());
possiblyConvertedValue = state.convertValue(newValue, targetObjectTypeDescriptor.getMapValueTypeDescriptor());
map.put(possiblyConvertedKey,possiblyConvertedValue);
if (targetObject instanceof Map) {
Map map = (Map) targetObject;
Object key = index.getValue();
if (targetObjectTypeDescriptor.getMapKeyType() != null) {
key = state.convertValue(index, targetObjectTypeDescriptor.getMapKeyType());
}
if (targetObjectTypeDescriptor.getMapValueType() != null) {
newValue = state.convertValue(newValue, targetObjectTypeDescriptor.getMapValueType());
}
map.put(key, newValue);
return;
}
if (targetObjectTypeDescriptor.isArray()) {
int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
setArrayElement(state, contextObject.getValue(), idx, newValue, targetObjectTypeDescriptor.getElementType());
setArrayElement(state, contextObject.getValue(), idx, newValue, targetObjectTypeDescriptor.getElementType().getType());
return;
}
else if (targetObjectTypeDescriptor.isCollection()) {
int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
else if (targetObject instanceof Collection) {
int idx = (Integer) state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
Collection c = (Collection) targetObject;
if (idx >= c.size()) {
if (!growCollection(state, targetObjectTypeDescriptor.getElementType(), idx, c)) {
if (!growCollection(state, targetObjectTypeDescriptor, idx, c)) {
throw new SpelEvaluationException(getStartPosition(),SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS, c.size(), idx);
}
}
if (targetObject instanceof List) {
List list = (List)targetObject;
Object possiblyConvertedValue = state.convertValue(newValue, targetObjectTypeDescriptor.getElementTypeDescriptor());
list.set(idx,possiblyConvertedValue);
List list = (List) targetObject;
if (targetObjectTypeDescriptor.getElementType() != null) {
newValue = state.convertValue(newValue, targetObjectTypeDescriptor.getElementType());
}
list.set(idx, newValue);
return;
}
else {
@@ -217,7 +225,7 @@ public class Indexer extends SpelNodeImpl {
// Try and treat the index value as a property of the context object
// TODO could call the conversion service to convert the value to a String
if (index.getTypeDescriptor().getType()==String.class) {
if (index.getTypeDescriptor().getType() == String.class) {
Class<?> contextObjectClass = getObjectClass(contextObject.getValue());
String name = (String)index.getValue();
EvaluationContext eContext = state.getEvaluationContext();
@@ -260,20 +268,21 @@ public class Indexer extends SpelNodeImpl {
* @return true if collection growing succeeded, otherwise false
*/
@SuppressWarnings("unchecked")
private boolean growCollection(ExpressionState state, Class<?> elementType, int index,
private boolean growCollection(ExpressionState state, TypeDescriptor targetType, int index,
Collection collection) {
if (state.getConfiguration().isAutoGrowCollections()) {
if (targetType.getElementType() == null) {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);
}
TypeDescriptor elementType = targetType.getElementType();
Object newCollectionElement = null;
try {
int newElements = index-collection.size();
if (elementType == null || elementType == Object.class) {
throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);
}
int newElements = index - collection.size();
while (newElements>0) {
collection.add(elementType.newInstance());
collection.add(elementType.getType().newInstance());
newElements--;
}
newCollectionElement = elementType.newInstance();
newCollectionElement = elementType.getType().newInstance();
}
catch (Exception ex) {
throw new SpelEvaluationException(getStartPosition(), ex, SpelMessage.UNABLE_TO_GROW_COLLECTION);

View File

@@ -142,7 +142,7 @@ public class Selection extends SpelNodeImpl {
return new TypedValue(result);
}
else {
Class<?> elementType = ClassUtils.resolvePrimitiveIfNecessary(op.getTypeDescriptor().getElementType());
Class<?> elementType = ClassUtils.resolvePrimitiveIfNecessary(op.getTypeDescriptor().getElementType().getType());
Object resultArray = Array.newInstance(elementType, result.size());
System.arraycopy(result.toArray(), 0, resultArray, 0, result.size());
return new TypedValue(resultArray);

View File

@@ -103,30 +103,29 @@ public class SpelExpression implements Expression {
return ExpressionUtils.convertTypedValue(context, typedResultValue, expectedResultType);
}
public Class getValueType() throws EvaluationException {
return ast.getValueInternal(new ExpressionState(getEvaluationContext(), configuration)).getTypeDescriptor().getType();
return getValueType(getEvaluationContext());
}
public Class getValueType(Object rootObject) throws EvaluationException {
return getValueType(getEvaluationContext(), rootObject);
}
public Class getValueType(EvaluationContext context) throws EvaluationException {
Assert.notNull(context, "The EvaluationContext is required");
ExpressionState eState = new ExpressionState(context, configuration);
TypeDescriptor typeDescriptor = ast.getValueInternal(eState).getTypeDescriptor();
return typeDescriptor.getType();
return typeDescriptor != null ? typeDescriptor.getType() : null;
}
public Class getValueType(EvaluationContext context, Object rootObject) throws EvaluationException {
ExpressionState eState = new ExpressionState(context, toTypedValue(rootObject), configuration);
TypeDescriptor typeDescriptor = ast.getValueInternal(eState).getTypeDescriptor();
return typeDescriptor.getType();
}
public Class getValueType(Object rootObject) throws EvaluationException {
return ast.getValueInternal(new ExpressionState(getEvaluationContext(), configuration)).getTypeDescriptor().getType();
return typeDescriptor != null ? typeDescriptor.getType() : null;
}
public TypeDescriptor getValueTypeDescriptor() throws EvaluationException {
return ast.getValueInternal(new ExpressionState(getEvaluationContext(), configuration)).getTypeDescriptor();
return getValueTypeDescriptor(getEvaluationContext());
}
public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException {
@@ -177,7 +176,6 @@ public class SpelExpression implements Expression {
Assert.notNull(context, "The EvaluationContext is required");
ast.setValue(new ExpressionState(context, toTypedValue(rootObject), configuration), value);
}
// impl only

View File

@@ -30,6 +30,7 @@ import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.MethodInvoker;
import org.springframework.util.ObjectUtils;
/**
* Utility methods used by the reflection resolver code to discover the appropriate
@@ -63,7 +64,7 @@ public class ReflectionHelper {
TypeDescriptor expectedArg = expectedArgTypes.get(i);
if (!expectedArg.equals(suppliedArg)) {
// The user may supply null - and that will be ok unless a primitive is expected
if (suppliedArg == TypeDescriptor.NULL) {
if (suppliedArg == null) {
if (expectedArg.isPrimitive()) {
match = null;
}
@@ -112,7 +113,7 @@ public class ReflectionHelper {
for (int i = 0,max=paramTypes.size(); i < max; i++) {
TypeDescriptor argType = argTypes.get(i);
TypeDescriptor paramType = paramTypes.get(i);
if (argType==TypeDescriptor.NULL) {
if (argType == null) {
if (paramType.isPrimitive()) {
return Integer.MAX_VALUE;
}
@@ -120,7 +121,7 @@ public class ReflectionHelper {
if (!ClassUtils.isAssignable(paramType.getClass(), argType.getClass())) {
return Integer.MAX_VALUE;
}
if (argType != TypeDescriptor.NULL) {
if (argType != null) {
Class paramTypeClazz = paramType.getType();
if (paramTypeClazz.isPrimitive()) {
paramTypeClazz = Object.class;
@@ -174,7 +175,7 @@ public class ReflectionHelper {
for (int i = 0; i < argCountUpToVarargs && match != null; i++) {
TypeDescriptor suppliedArg = suppliedArgTypes.get(i);
TypeDescriptor expectedArg = expectedArgTypes.get(i);
if (suppliedArg == TypeDescriptor.NULL) {
if (suppliedArg == null) {
if (expectedArg.isPrimitive()) {
match = null;
}
@@ -213,13 +214,13 @@ public class ReflectionHelper {
else {
// Now... we have the final argument in the method we are checking as a match and we have 0 or more other
// arguments left to pass to it.
Class varargsParameterType = expectedArgTypes.get(expectedArgTypes.size() - 1).getElementType();
Class varargsParameterType = expectedArgTypes.get(expectedArgTypes.size() - 1).getElementType().getType();
// All remaining parameters must be of this type or convertable to this type
for (int i = expectedArgTypes.size() - 1; i < suppliedArgTypes.size(); i++) {
TypeDescriptor suppliedArg = suppliedArgTypes.get(i);
if (varargsParameterType != suppliedArg.getType()) {
if (suppliedArg == TypeDescriptor.NULL) {
if (!ObjectUtils.nullSafeEquals(varargsParameterType, suppliedArg)) {
if (suppliedArg == null) {
if (varargsParameterType.isPrimitive()) {
match = null;
}

View File

@@ -66,7 +66,8 @@ class ReflectiveMethodExecutor implements MethodExecutor {
arguments = ReflectionHelper.setupArgumentsForVarargsInvocation(this.method.getParameterTypes(), arguments);
}
ReflectionUtils.makeAccessible(this.method);
return new TypedValue(this.method.invoke(target, arguments), new TypeDescriptor(new MethodParameter(this.method, -1)));
Object value = this.method.invoke(target, arguments);
return new TypedValue(value, new TypeDescriptor(new MethodParameter(this.method, -1)).narrowType(value));
}
catch (Exception ex) {
throw new AccessException("Problem invoking method: " + this.method, ex);

View File

@@ -109,7 +109,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (target instanceof Class) {
throw new AccessException("Cannot access length on array class itself");
}
return new TypedValue(Array.getLength(target),TypeDescriptor.valueOf(Integer.TYPE));
return new TypedValue(Array.getLength(target));
}
CacheKey cacheKey = new CacheKey(type, name);
@@ -508,7 +508,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (needsToBeMadeAccessible) {
ReflectionUtils.makeAccessible((Method) member);
}
return new TypedValue(((Method) member).invoke(target), typeDescriptor);
Object value = ((Method) member).invoke(target);
return new TypedValue(value, typeDescriptor.narrowType(value));
}
catch (Exception ex) {
throw new AccessException("Unable to access property '" + name + "' through getter", ex);
@@ -519,7 +520,8 @@ public class ReflectivePropertyAccessor implements PropertyAccessor {
if (needsToBeMadeAccessible) {
ReflectionUtils.makeAccessible((Field)member);
}
return new TypedValue(((Field)member).get(target),typeDescriptor);
Object value = ((Field)member).get(target);
return new TypedValue(value, typeDescriptor.narrowType(value));
}
catch (Exception ex) {
throw new AccessException("Unable to access field: " + name, ex);

View File

@@ -16,15 +16,17 @@
package org.springframework.expression.spel;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static junit.framework.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
@@ -72,13 +74,13 @@ public class ExpressionTestsUsingCoreConversionService extends ExpressionTestCas
TypeConvertorUsingConversionService tcs = new TypeConvertorUsingConversionService();
// ArrayList containing List<Integer> to List<String>
Class<?> clazz = typeDescriptorForListOfString.getElementType();
Class<?> clazz = typeDescriptorForListOfString.getElementType().getType();
assertEquals(String.class,clazz);
List l = (List) tcs.convertValue(listOfInteger, TypeDescriptor.forObject(listOfInteger), typeDescriptorForListOfString);
assertNotNull(l);
// ArrayList containing List<String> to List<Integer>
clazz = typeDescriptorForListOfInteger.getElementType();
clazz = typeDescriptorForListOfInteger.getElementType().getType();
assertEquals(Integer.class,clazz);
l = (List) tcs.convertValue(listOfString, TypeDescriptor.forObject(listOfString), typeDescriptorForListOfString);

View File

@@ -1,42 +1,304 @@
package org.springframework.expression.spel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
public class IndexingTests {
@Test
@Ignore
public void indexIntoGenericPropertyContainingMap() {
Map<String, String> property = new HashMap<String, String>();
property.put("foo", "bar");
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("property");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.HashMap<?, ?>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
assertEquals(property, expression.getValue(this, Map.class));
expression = parser.parseExpression("property['foo']");
assertEquals("bar", expression.getValue(this));
}
@FieldAnnotation
public Object property;
@Test
public void indexIntoGenericPropertyContainingMapObject() {
Map<String, Map<String, String>> property = new HashMap<String, Map<String, String>>();
Map<String, String> map = new HashMap<String, String>();
map.put("foo", "bar");
property.put("property", map);
SpelExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.addPropertyAccessor(new MapAccessor());
context.setRootObject(property);
Expression expression = parser.parseExpression("property");
assertEquals("java.util.HashMap<?, ?>", expression.getValueTypeDescriptor(context).toString());
assertEquals(map, expression.getValue(context));
assertEquals(map, expression.getValue(context, Map.class));
expression = parser.parseExpression("property['foo']");
assertEquals("bar", expression.getValue(context));
}
public static class MapAccessor implements PropertyAccessor {
public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
return (((Map) target).containsKey(name));
}
public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
return new TypedValue(((Map) target).get(name));
}
public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
return true;
}
@SuppressWarnings("unchecked")
public void write(EvaluationContext context, Object target, String name, Object newValue)
throws AccessException {
((Map) target).put(name, newValue);
}
public Class<?>[] getSpecificTargetClasses() {
return new Class[] { Map.class };
}
}
@Test
public void setGenericPropertyContainingMap() {
Map<String, String> property = new HashMap<String, String>();
property.put("foo", "bar");
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("property");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.HashMap<?, ?>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("property['foo']");
assertEquals("bar", expression.getValue(this));
expression.setValue(this, "baz");
assertEquals("baz", expression.getValue(this));
}
@Test
public void setPropertyContainingMap() {
Map<Integer, Integer> property = new HashMap<Integer, Integer>();
property.put(9, 3);
this.parameterizedMap = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("parameterizedMap");
assertEquals("java.util.HashMap<java.lang.Integer, java.lang.Integer>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("parameterizedMap['9']");
assertEquals(3, expression.getValue(this));
expression.setValue(this, "37");
assertEquals(37, expression.getValue(this));
}
public Map<Integer, Integer> parameterizedMap;
@Test
public void setPropertyContainingMapAutoGrow() {
SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, false));
Expression expression = parser.parseExpression("parameterizedMap");
assertEquals("java.util.Map<java.lang.Integer, java.lang.Integer>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("parameterizedMap['9']");
assertEquals(null, expression.getValue(this));
expression.setValue(this, "37");
assertEquals(37, expression.getValue(this));
}
@Test
public void indexIntoGenericPropertyContainingList() {
List<String> property = new ArrayList<String>();
property.add("bar");
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("property");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.ArrayList<?>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("property[0]");
assertEquals("bar", expression.getValue(this));
}
@Test
public void setGenericPropertyContainingList() {
List<Integer> property = new ArrayList<Integer>();
property.add(3);
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("property");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.ArrayList<?>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("property[0]");
assertEquals(3, expression.getValue(this));
expression.setValue(this, "4");
assertEquals("4", expression.getValue(this));
}
@Test
public void setGenericPropertyContainingListAutogrow() {
List<Integer> property = new ArrayList<Integer>();
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
Expression expression = parser.parseExpression("property");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.ArrayList<?>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("property[0]");
try {
expression.setValue(this, "4");
} catch (EvaluationException e) {
assertTrue(e.getMessage().startsWith("EL1053E"));
}
}
@Test
public void indexIntoPropertyContainingList() {
List<Integer> property = new ArrayList<Integer>();
property.add(3);
this.parameterizedList = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("parameterizedList");
assertEquals("java.util.ArrayList<java.lang.Integer>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("parameterizedList[0]");
assertEquals(3, expression.getValue(this));
}
public List<Integer> parameterizedList;
@Test
public void indexIntoPropertyContainingListOfList() {
List<List<Integer>> property = new ArrayList<List<Integer>>();
property.add(Arrays.asList(3));
this.parameterizedListOfList = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("parameterizedListOfList[0]");
assertEquals("java.util.Arrays$ArrayList<java.lang.Integer>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property.get(0), expression.getValue(this));
expression = parser.parseExpression("parameterizedListOfList[0][0]");
assertEquals(3, expression.getValue(this));
}
public List<List<Integer>> parameterizedListOfList;
@Test
public void setPropertyContainingList() {
List<Integer> property = new ArrayList<Integer>();
property.add(3);
this.parameterizedList = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("parameterizedList");
assertEquals("java.util.ArrayList<java.lang.Integer>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("parameterizedList[0]");
assertEquals(3, expression.getValue(this));
expression.setValue(this, "4");
assertEquals(4, expression.getValue(this));
}
@Test
public void indexIntoGenericPropertyContainingNullList() {
SpelParserConfiguration configuration = new SpelParserConfiguration(true, true);
SpelExpressionParser parser = new SpelExpressionParser(configuration);
Expression expression = parser.parseExpression("property");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.lang.Object", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("property[0]");
try {
assertEquals("bar", expression.getValue(this));
} catch (EvaluationException e) {
assertTrue(e.getMessage().startsWith("EL1027E"));
}
}
@Test
public void indexIntoGenericPropertyContainingGrowingList() {
List<String> property = new ArrayList<String>();
this.property = property;
SpelParserConfiguration configuration = new SpelParserConfiguration(true, true);
SpelExpressionParser parser = new SpelExpressionParser(configuration);
Expression expression = parser.parseExpression("property");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.ArrayList<?>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("property[0]");
try {
assertEquals("bar", expression.getValue(this));
} catch (EvaluationException e) {
assertTrue(e.getMessage().startsWith("EL1053E"));
}
}
@Test
public void indexIntoGenericPropertyContainingGrowingList2() {
List<String> property2 = new ArrayList<String>();
this.property2 = property2;
SpelParserConfiguration configuration = new SpelParserConfiguration(true, true);
SpelExpressionParser parser = new SpelExpressionParser(configuration);
Expression expression = parser.parseExpression("property2");
assertEquals("java.util.ArrayList<?>", expression.getValueTypeDescriptor(this).toString());
assertEquals(property2, expression.getValue(this));
expression = parser.parseExpression("property2[0]");
try {
assertEquals("bar", expression.getValue(this));
} catch (EvaluationException e) {
assertTrue(e.getMessage().startsWith("EL1053E"));
}
}
public List property2;
@Test
public void indexIntoGenericPropertyContainingArray() {
String[] property = new String[] { "bar" };
this.property = property;
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("property");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.lang.String[]", expression.getValueTypeDescriptor(this).toString());
assertEquals(property, expression.getValue(this));
expression = parser.parseExpression("property[0]");
assertEquals("bar", expression.getValue(this));
}
@Test
public void emptyList() {
listOfScalarNotGeneric = new ArrayList();
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("listOfScalarNotGeneric");
assertEquals("java.util.List<java.lang.Object>", expression.getValueTypeDescriptor(this).toString());
assertEquals("java.util.ArrayList<?>", expression.getValueTypeDescriptor(this).toString());
assertEquals("", expression.getValue(this, String.class));
}
@Test
@Ignore
public void resolveCollectionElementType() {
listNotGeneric = new ArrayList();
listNotGeneric.add(5);
listNotGeneric.add(6);
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("listNotGeneric");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.List<@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.lang.Integer>", expression.getValueTypeDescriptor(this).toString());
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.ArrayList<?>", expression.getValueTypeDescriptor(this).toString());
assertEquals("5,6", expression.getValue(this, String.class));
}
@@ -44,7 +306,7 @@ public class IndexingTests {
public void resolveCollectionElementTypeNull() {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("listNotGeneric");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.List<@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.lang.Object>", expression.getValueTypeDescriptor(this).toString());
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.List<?>", expression.getValueTypeDescriptor(this).toString());
}
@FieldAnnotation
@@ -63,7 +325,7 @@ public class IndexingTests {
mapNotGeneric.put("bonusAmount", 7.17);
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("mapNotGeneric");
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.Map<java.lang.String, java.lang.Double>", expression.getValueTypeDescriptor(this).toString());
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.HashMap<?, ?>", expression.getValueTypeDescriptor(this).toString());
}
@FieldAnnotation

View File

@@ -16,6 +16,9 @@
package org.springframework.expression.spel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
@@ -23,9 +26,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
@@ -112,7 +113,7 @@ public class SelectionAndProjectionTests {
Object value = expression.getValue(context);
assertTrue(value.getClass().isArray());
TypedValue typedValue = new TypedValue(value);
assertEquals(Integer.class, typedValue.getTypeDescriptor().getElementType());
assertEquals(Integer.class, typedValue.getTypeDescriptor().getElementType().getType());
Integer[] array = (Integer[]) value;
assertEquals(5, array.length);
assertEquals(new Integer(0), array[0]);
@@ -147,7 +148,7 @@ public class SelectionAndProjectionTests {
Object value = expression.getValue(context);
assertTrue(value.getClass().isArray());
TypedValue typedValue = new TypedValue(value);
assertEquals(Integer.class, typedValue.getTypeDescriptor().getElementType());
assertEquals(Integer.class, typedValue.getTypeDescriptor().getElementType().getType());
Integer[] array = (Integer[]) value;
assertEquals(5, array.length);
assertEquals(new Integer(0), array[0]);
@@ -249,7 +250,7 @@ public class SelectionAndProjectionTests {
Object value = expression.getValue(context);
assertTrue(value.getClass().isArray());
TypedValue typedValue = new TypedValue(value);
assertEquals(Number.class, typedValue.getTypeDescriptor().getElementType());
assertEquals(Number.class, typedValue.getTypeDescriptor().getElementType().getType());
Number[] array = (Number[]) value;
assertEquals(3, array.length);
assertEquals(new Integer(5), array[0]);

View File

@@ -26,7 +26,6 @@ import java.util.Map;
import junit.framework.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
@@ -206,7 +205,6 @@ public class SpelDocumentationTests extends ExpressionTestCase {
@Test
@Ignore
public void testDictionaryAccess() throws Exception {
StandardEvaluationContext societyContext = new StandardEvaluationContext();
societyContext.setRootObject(new IEEE());

View File

@@ -698,7 +698,6 @@ public class SpringEL300Tests extends ExpressionTestCase {
}
@Test
@Ignore
@SuppressWarnings("unchecked")
public void testMapOfMap_SPR7244() throws Exception {
Map<String,Object> map = new LinkedHashMap();
@@ -727,10 +726,11 @@ public class SpringEL300Tests extends ExpressionTestCase {
String el1 = "ls.![#this.equals('abc')]";
SpelExpression exp = parser.parseRaw(el1);
List value = (List)exp.getValue(ctx);
System.out.println(value);
// value is list containing [true,false]
Assert.assertEquals(Boolean.class,value.get(0).getClass());
TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
Assert.assertEquals(Boolean.class,evaluated.getElementType());
Assert.assertEquals(null, evaluated.getElementType());
}
@Test
@@ -743,7 +743,7 @@ public class SpringEL300Tests extends ExpressionTestCase {
// value is array containing [true,false]
Assert.assertEquals(Boolean.class,value[0].getClass());
TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
Assert.assertEquals(Boolean.class,evaluated.getElementType());
Assert.assertEquals(Boolean.class, evaluated.getElementType().getType());
}
@Test
@@ -756,7 +756,7 @@ public class SpringEL300Tests extends ExpressionTestCase {
// value is list containing [true,false]
Assert.assertEquals(Boolean.class,value.get(0).getClass());
TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
Assert.assertEquals(Boolean.class,evaluated.getElementType());
Assert.assertEquals(null, evaluated.getElementType());
}
static class C {