revised TypeDescriptor NULL and element/mapKey/mapValue type semantics
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user