revised TypeDescriptor NULL and element/mapKey/mapValue type semantics
This commit is contained in:
parent
a2a4929c14
commit
c84cccf06d
|
@ -141,8 +141,8 @@ class TypeConverterDelegate {
|
|||
// Value not of required type?
|
||||
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
|
||||
if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {
|
||||
Class elemType = typeDescriptor.getElementType();
|
||||
if (elemType != null && Enum.class.isAssignableFrom(elemType)) {
|
||||
TypeDescriptor elementType = typeDescriptor.getElementType();
|
||||
if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {
|
||||
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
|
||||
}
|
||||
}
|
||||
|
@ -459,8 +459,8 @@ class TypeConverterDelegate {
|
|||
return original;
|
||||
}
|
||||
|
||||
Class elementType = typeDescriptor.getElementType();
|
||||
if (elementType == Object.class && originalAllowed &&
|
||||
TypeDescriptor elementType = typeDescriptor.getElementType();
|
||||
if (elementType == null && originalAllowed &&
|
||||
!this.propertyEditorRegistry.hasCustomEditorForElement(null, propertyName)) {
|
||||
return original;
|
||||
}
|
||||
|
@ -506,7 +506,7 @@ class TypeConverterDelegate {
|
|||
Object element = it.next();
|
||||
String indexedPropertyName = buildIndexedPropertyName(propertyName, i);
|
||||
Object convertedElement = convertIfNecessary(
|
||||
indexedPropertyName, null, element, elementType, typeDescriptor.getElementTypeDescriptor());
|
||||
indexedPropertyName, null, element, elementType != null ? elementType.getType() : null , typeDescriptor.getElementType());
|
||||
try {
|
||||
convertedCopy.add(convertedElement);
|
||||
}
|
||||
|
@ -531,9 +531,9 @@ class TypeConverterDelegate {
|
|||
return original;
|
||||
}
|
||||
|
||||
Class keyType = typeDescriptor.getMapKeyType();
|
||||
Class valueType = typeDescriptor.getMapValueType();
|
||||
if (keyType == Object.class && valueType == Object.class && originalAllowed &&
|
||||
TypeDescriptor keyType = typeDescriptor.getMapKeyType();
|
||||
TypeDescriptor valueType = typeDescriptor.getMapValueType();
|
||||
if (keyType == null && valueType == null && originalAllowed &&
|
||||
!this.propertyEditorRegistry.hasCustomEditorForElement(null, propertyName)) {
|
||||
return original;
|
||||
}
|
||||
|
@ -579,8 +579,8 @@ class TypeConverterDelegate {
|
|||
Object key = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
String keyedPropertyName = buildKeyedPropertyName(propertyName, key);
|
||||
Object convertedKey = convertIfNecessary(keyedPropertyName, null, key, keyType, typeDescriptor.getMapKeyTypeDescriptor());
|
||||
Object convertedValue = convertIfNecessary(keyedPropertyName, null, value, valueType, typeDescriptor.getMapValueTypeDescriptor());
|
||||
Object convertedKey = convertIfNecessary(keyedPropertyName, null, key, keyType != null ? keyType.getType() : null, typeDescriptor.getMapKeyType());
|
||||
Object convertedValue = convertIfNecessary(keyedPropertyName, null, value, valueType!= null ? valueType.getType() : null, typeDescriptor.getMapValueType());
|
||||
try {
|
||||
convertedCopy.put(convertedKey, convertedValue);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,9 @@ abstract class AbstractDescriptor {
|
|||
private final Class<?> type;
|
||||
|
||||
public AbstractDescriptor(Class<?> type) {
|
||||
//if (type == null) {
|
||||
// throw new IllegalArgumentException("type cannot be null");
|
||||
//}
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
@ -33,31 +36,31 @@ abstract class AbstractDescriptor {
|
|||
|
||||
public TypeDescriptor getElementType() {
|
||||
if (isCollection()) {
|
||||
Class<?> elementType = wildcard(getCollectionElementClass());
|
||||
return new TypeDescriptor(nested(elementType, 0));
|
||||
Class<?> elementType = resolveCollectionElementType();
|
||||
return elementType != null ? new TypeDescriptor(nested(elementType, 0)) : null;
|
||||
} else if (isArray()) {
|
||||
Class<?> elementType = getType().getComponentType();
|
||||
return new TypeDescriptor(nested(elementType, 0));
|
||||
} else {
|
||||
return TypeDescriptor.NULL;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public TypeDescriptor getMapKeyType() {
|
||||
if (isMap()) {
|
||||
Class<?> keyType = wildcard(getMapKeyClass());
|
||||
return new TypeDescriptor(nested(keyType, 0));
|
||||
Class<?> keyType = resolveMapKeyType();
|
||||
return keyType != null ? new TypeDescriptor(nested(keyType, 0)) : null;
|
||||
} else {
|
||||
return TypeDescriptor.NULL;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public TypeDescriptor getMapValueType() {
|
||||
if (isMap()) {
|
||||
Class<?> valueType = wildcard(getMapValueClass());
|
||||
return new TypeDescriptor(nested(valueType, 1));
|
||||
Class<?> valueType = resolveMapValueType();
|
||||
return valueType != null ? new TypeDescriptor(nested(valueType, 1)) : null;
|
||||
} else {
|
||||
return TypeDescriptor.NULL;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,11 +68,11 @@ abstract class AbstractDescriptor {
|
|||
|
||||
public AbstractDescriptor nested() {
|
||||
if (isCollection()) {
|
||||
return nested(wildcard(getCollectionElementClass()), 0);
|
||||
return nested(resolveCollectionElementType(), 0);
|
||||
} else if (isArray()) {
|
||||
return nested(getType().getComponentType(), 0);
|
||||
} else if (isMap()) {
|
||||
return nested(wildcard(getMapValueClass()), 1);
|
||||
return nested(resolveMapValueType(), 1);
|
||||
} else {
|
||||
throw new IllegalStateException("Not a collection, array, or map: cannot resolve nested value types");
|
||||
}
|
||||
|
@ -77,30 +80,26 @@ abstract class AbstractDescriptor {
|
|||
|
||||
// subclassing hooks
|
||||
|
||||
protected abstract Class<?> getCollectionElementClass();
|
||||
protected abstract Class<?> resolveCollectionElementType();
|
||||
|
||||
protected abstract Class<?> getMapKeyClass();
|
||||
protected abstract Class<?> resolveMapKeyType();
|
||||
|
||||
protected abstract Class<?> getMapValueClass();
|
||||
protected abstract Class<?> resolveMapValueType();
|
||||
|
||||
protected abstract AbstractDescriptor nested(Class<?> type, int typeIndex);
|
||||
|
||||
// internal helpers
|
||||
|
||||
private boolean isCollection() {
|
||||
return Collection.class.isAssignableFrom(getType());
|
||||
return getType() != null && Collection.class.isAssignableFrom(getType());
|
||||
}
|
||||
|
||||
private boolean isArray() {
|
||||
return getType().isArray();
|
||||
return getType() != null && getType().isArray();
|
||||
}
|
||||
|
||||
private boolean isMap() {
|
||||
return Map.class.isAssignableFrom(getType());
|
||||
}
|
||||
|
||||
private Class<?> wildcard(Class<?> type) {
|
||||
return type != null ? type : Object.class;
|
||||
return getType() != null && Map.class.isAssignableFrom(getType());
|
||||
}
|
||||
|
||||
}
|
|
@ -52,17 +52,17 @@ class BeanPropertyDescriptor extends AbstractDescriptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getCollectionElementClass() {
|
||||
protected Class<?> resolveCollectionElementType() {
|
||||
return GenericCollectionTypeResolver.getCollectionParameterType(methodParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getMapKeyClass() {
|
||||
protected Class<?> resolveMapKeyType() {
|
||||
return GenericCollectionTypeResolver.getMapKeyParameterType(methodParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getMapValueClass() {
|
||||
protected Class<?> resolveMapValueType() {
|
||||
return GenericCollectionTypeResolver.getMapValueParameterType(methodParameter);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,18 +29,18 @@ class ClassDescriptor extends AbstractDescriptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getCollectionElementClass() {
|
||||
return Object.class;
|
||||
protected Class<?> resolveCollectionElementType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getMapKeyClass() {
|
||||
return Object.class;
|
||||
protected Class<?> resolveMapKeyType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getMapValueClass() {
|
||||
return Object.class;
|
||||
protected Class<?> resolveMapValueType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.core.convert;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
class CommonElement {
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
private final Object value;
|
||||
|
||||
public CommonElement(Class<?> type, Object value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public TypeDescriptor toTypeDescriptor() {
|
||||
if (type == null) {
|
||||
return TypeDescriptor.NULL;
|
||||
} else if (value instanceof Collection<?>) {
|
||||
Collection<?> collection = (Collection<?>) value;
|
||||
return new TypeDescriptor(type, typeDescriptor(collection));
|
||||
}
|
||||
else if (value instanceof Map<?, ?>) {
|
||||
Map<?, ?> map = (Map<?, ?>) value;
|
||||
return new TypeDescriptor(type, typeDescriptor(map.keySet()), typeDescriptor(map.values()));
|
||||
}
|
||||
else {
|
||||
return TypeDescriptor.valueOf(type);
|
||||
}
|
||||
}
|
||||
|
||||
public static TypeDescriptor typeDescriptor(Collection<?> collection) {
|
||||
return findCommonElement(collection).toTypeDescriptor();
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private static CommonElement findCommonElement(Collection<?> values) {
|
||||
Class<?> commonType = null;
|
||||
Object candidate = null;
|
||||
for (Object value : values) {
|
||||
if (value != null) {
|
||||
if (candidate == null) {
|
||||
commonType = value.getClass();
|
||||
candidate = value;
|
||||
} else {
|
||||
commonType = commonType(commonType, value.getClass());
|
||||
if (commonType == Object.class) {
|
||||
return new CommonElement(Object.class, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new CommonElement(commonType, candidate);
|
||||
}
|
||||
|
||||
private static Class<?> commonType(Class<?> commonType, Class<?> valueClass) {
|
||||
Set<Class<?>> interfaces = new LinkedHashSet<Class<?>>();
|
||||
LinkedList<Class<?>> classQueue = new LinkedList<Class<?>>();
|
||||
classQueue.addFirst(commonType);
|
||||
while (!classQueue.isEmpty()) {
|
||||
Class<?> currentClass = classQueue.removeLast();
|
||||
if (currentClass.isAssignableFrom(valueClass)) {
|
||||
return currentClass;
|
||||
}
|
||||
Class<?> superClass = currentClass.getSuperclass();
|
||||
if (superClass != null && superClass != Object.class) {
|
||||
classQueue.addFirst(currentClass.getSuperclass());
|
||||
}
|
||||
for (Class<?> interfaceType : currentClass.getInterfaces()) {
|
||||
addInterfaceHierarchy(interfaceType, interfaces);
|
||||
}
|
||||
}
|
||||
for (Class<?> interfaceType : interfaces) {
|
||||
if (interfaceType.isAssignableFrom(valueClass)) {
|
||||
return interfaceType;
|
||||
}
|
||||
}
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
private static void addInterfaceHierarchy(Class<?> interfaceType, Set<Class<?>> interfaces) {
|
||||
interfaces.add(interfaceType);
|
||||
for (Class<?> inheritedInterface : interfaceType.getInterfaces()) {
|
||||
addInterfaceHierarchy(inheritedInterface, interfaces);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -41,7 +41,7 @@ public interface ConversionService {
|
|||
* @throws ConversionException if an exception occurred
|
||||
*/
|
||||
<T> T convert(Object source, Class<T> targetType);
|
||||
|
||||
|
||||
/**
|
||||
* Returns true if objects of sourceType can be converted to the targetType.
|
||||
* The TypeDescriptors provide additional context about the field locations where conversion would occur, often object property locations.
|
||||
|
|
|
@ -36,17 +36,17 @@ class FieldDescriptor extends AbstractDescriptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getCollectionElementClass() {
|
||||
protected Class<?> resolveCollectionElementType() {
|
||||
return GenericCollectionTypeResolver.getCollectionFieldType(this.field, this.nestingLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getMapKeyClass() {
|
||||
protected Class<?> resolveMapKeyType() {
|
||||
return GenericCollectionTypeResolver.getMapKeyFieldType(this.field, this.nestingLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getMapValueClass() {
|
||||
protected Class<?> resolveMapValueType() {
|
||||
return GenericCollectionTypeResolver.getMapValueFieldType(this.field, this.nestingLevel);
|
||||
}
|
||||
|
||||
|
|
|
@ -43,17 +43,17 @@ class ParameterDescriptor extends AbstractDescriptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getCollectionElementClass() {
|
||||
protected Class<?> resolveCollectionElementType() {
|
||||
return GenericCollectionTypeResolver.getCollectionParameterType(methodParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getMapKeyClass() {
|
||||
protected Class<?> resolveMapKeyType() {
|
||||
return GenericCollectionTypeResolver.getMapKeyParameterType(methodParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> getMapValueClass() {
|
||||
protected Class<?> resolveMapValueType() {
|
||||
return GenericCollectionTypeResolver.getMapValueParameterType(methodParameter);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,9 +38,6 @@ public class TypeDescriptor {
|
|||
|
||||
static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
|
||||
|
||||
/** Constant defining a TypeDescriptor for a <code>null</code> value */
|
||||
public static final TypeDescriptor NULL = new TypeDescriptor();
|
||||
|
||||
private static final Map<Class<?>, TypeDescriptor> typeDescriptorCache = new HashMap<Class<?>, TypeDescriptor>();
|
||||
|
||||
static {
|
||||
|
@ -63,7 +60,6 @@ public class TypeDescriptor {
|
|||
typeDescriptorCache.put(String.class, new TypeDescriptor(String.class));
|
||||
}
|
||||
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
private final TypeDescriptor elementType;
|
||||
|
@ -110,9 +106,6 @@ public class TypeDescriptor {
|
|||
* @return the type descriptor
|
||||
*/
|
||||
public static TypeDescriptor valueOf(Class<?> type) {
|
||||
if (type == null) {
|
||||
return NULL;
|
||||
}
|
||||
TypeDescriptor desc = typeDescriptorCache.get(type);
|
||||
return (desc != null ? desc : new TypeDescriptor(type));
|
||||
}
|
||||
|
@ -148,37 +141,6 @@ public class TypeDescriptor {
|
|||
return new TypeDescriptor(mapType, keyType, valueType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new type descriptor for an object.
|
||||
* Use this factory method to introspect a source object's type before asking the conversion system to convert it to some another type.
|
||||
* Populates nested type descriptors for collection and map objects through object introspection.
|
||||
* If the provided object is null, returns {@link TypeDescriptor#NULL}.
|
||||
* If the object is not a collection or map, simply calls {@link #valueOf(Class)}.
|
||||
* If the object is a collection or map, this factory method will derive nested element or key/value types by introspecting the collection or map.
|
||||
* The introspection algorithm derives nested element or key/value types by resolving the "common element type" across the collection or map.
|
||||
* For example, if a Collection contained all java.lang.Integer elements, its element type would be java.lang.Integer.
|
||||
* If a Collection contained several distinct number types all extending from java.lang.Number, its element type would be java.lang.Number.
|
||||
* If a Collection contained a String and a java.util.Map element, its element type would be java.io.Serializable.
|
||||
* @param object the source object
|
||||
* @return the type descriptor
|
||||
* @see ConversionService#convert(Object, Class)
|
||||
*/
|
||||
public static TypeDescriptor forObject(Object object) {
|
||||
if (object == null) {
|
||||
return NULL;
|
||||
}
|
||||
if (object instanceof Collection<?>) {
|
||||
return new TypeDescriptor(object.getClass(), CommonElement.typeDescriptor((Collection<?>) object));
|
||||
}
|
||||
else if (object instanceof Map<?, ?>) {
|
||||
Map<?, ?> map = (Map<?, ?>) object;
|
||||
return new TypeDescriptor(map.getClass(), CommonElement.typeDescriptor(map.keySet()), CommonElement.typeDescriptor(map.values()));
|
||||
}
|
||||
else {
|
||||
return valueOf(object.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a type descriptor for a nested type declared within the method parameter.
|
||||
* For example, if the methodParameter is a List<String> and the nestingLevel is 1, the nested type descriptor will be String.class.
|
||||
|
@ -224,6 +186,10 @@ public class TypeDescriptor {
|
|||
return nested(new BeanPropertyDescriptor(beanClass, property), nestingLevel);
|
||||
}
|
||||
|
||||
public static TypeDescriptor forObject(Object source) {
|
||||
return source != null ? valueOf(source.getClass()) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the declared (non-generic) type of the wrapped parameter/field.
|
||||
* @return the declared type, or <code>null</code> if this is {@link TypeDescriptor#NULL}
|
||||
|
@ -237,21 +203,27 @@ public class TypeDescriptor {
|
|||
* Returns the Object wrapper type if the underlying type is a primitive.
|
||||
*/
|
||||
public Class<?> getObjectType() {
|
||||
return getType() != null ? ClassUtils.resolvePrimitiveIfNecessary(getType()) : null;
|
||||
return ClassUtils.resolvePrimitiveIfNecessary(getType());
|
||||
}
|
||||
|
||||
public TypeDescriptor narrowType(Object value) {
|
||||
if (value == null) {
|
||||
return this;
|
||||
}
|
||||
return new TypeDescriptor(value.getClass(), elementType, mapKeyType, mapValueType, annotations);
|
||||
}
|
||||
/**
|
||||
* Returns the name of this type: the fully qualified class name.
|
||||
*/
|
||||
public String getName() {
|
||||
return getType() != null ? ClassUtils.getQualifiedName(getType()) : null;
|
||||
return ClassUtils.getQualifiedName(getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this type a primitive type?
|
||||
*/
|
||||
public boolean isPrimitive() {
|
||||
return getType() != null && getType().isPrimitive();
|
||||
return getType().isPrimitive();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -281,21 +253,19 @@ public class TypeDescriptor {
|
|||
* @return true if this type is assignable to the target
|
||||
*/
|
||||
public boolean isAssignableTo(TypeDescriptor targetType) {
|
||||
if (this == TypeDescriptor.NULL || targetType == TypeDescriptor.NULL) {
|
||||
return true;
|
||||
boolean typesAssignable = targetType.getObjectType().isAssignableFrom(getObjectType());
|
||||
if (!typesAssignable) {
|
||||
return false;
|
||||
}
|
||||
if (isCollection() && targetType.isCollection() || isArray() && targetType.isArray()) {
|
||||
return targetType.getType().isAssignableFrom(getType()) &&
|
||||
getElementTypeDescriptor().isAssignableTo(targetType.getElementTypeDescriptor());
|
||||
if (isArray() && targetType.isArray()) {
|
||||
return getElementType().isAssignableTo(targetType.getElementType());
|
||||
}
|
||||
else if (isMap() && targetType.isMap()) {
|
||||
return targetType.getType().isAssignableFrom(getType()) &&
|
||||
getMapKeyTypeDescriptor().isAssignableTo(targetType.getMapKeyTypeDescriptor()) &&
|
||||
getMapValueTypeDescriptor().isAssignableTo(targetType.getMapValueTypeDescriptor());
|
||||
}
|
||||
else {
|
||||
return targetType.getObjectType().isAssignableFrom(getObjectType());
|
||||
if (isCollection() && targetType.isCollection()) {
|
||||
return collectionElementsAssignable(targetType.getElementType());
|
||||
} else if (isMap() && targetType.isMap()) {
|
||||
return mapKeysAssignable(targetType.getMapKeyType()) && mapValuesAssignable(targetType.getMapValueType());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// indexable type descriptor operations
|
||||
|
@ -304,53 +274,36 @@ public class TypeDescriptor {
|
|||
* Is this type a {@link Collection} type?
|
||||
*/
|
||||
public boolean isCollection() {
|
||||
return getType() != null && Collection.class.isAssignableFrom(getType());
|
||||
return Collection.class.isAssignableFrom(getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this type an array type?
|
||||
*/
|
||||
public boolean isArray() {
|
||||
return getType() != null && getType().isArray();
|
||||
return getType().isArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* If this type is a {@link Collection} or array, returns the underlying element type.
|
||||
* Returns Object.class if this type is a collection and the element type was not explicitly declared.
|
||||
* @return the map element type, or <code>null</code> if not a collection or array.
|
||||
* @throws IllegalStateException if this descriptor is not for a java.util.Collection or Array
|
||||
* If this type is an array, returns the array's component type.
|
||||
* If this type is a {@link Collection} and it is parameterized, returns the Collection's element type.
|
||||
* If the Collection is not parameterized, returns null indicating the element type is not declared.
|
||||
* @return the array component type or Collection element type, or <code>null</code> if this type is a Collection but its element type is not parameterized.
|
||||
* @throws IllegalStateException if this type is not a java.util.Collection or Array type
|
||||
*/
|
||||
public Class<?> getElementType() {
|
||||
return getElementTypeDescriptor().getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* The collection or array element type as a type descriptor.
|
||||
* Returns TypeDescriptor.valueOf(Object.class) if this type is a collection and the element type is not explicitly declared.
|
||||
* @throws IllegalStateException if this descriptor is not for a java.util.Collection or Array
|
||||
*/
|
||||
public TypeDescriptor getElementTypeDescriptor() {
|
||||
public TypeDescriptor getElementType() {
|
||||
if (!isCollection() && !isArray()) {
|
||||
throw new IllegalStateException("Not a java.util.Collection or Array");
|
||||
}
|
||||
return this.elementType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this type descriptor that has its elementType populated from the specified Collection.
|
||||
* This property will be set by calculating the "common element type" of the specified Collection.
|
||||
* For example, if the collection contains String elements, the returned TypeDescriptor will have its elementType set to String.
|
||||
* This method is designed to be used when converting values read from Collection fields or method return values that are not parameterized e.g. Collection vs. Collection<String>
|
||||
* In this scenario the elementType will be Object.class before invoking this method.
|
||||
* @param colection the collection to derive the elementType from
|
||||
* @return a new TypeDescriptor with the resolved elementType property
|
||||
* @throws IllegalArgumentException if this is not a type descriptor for a java.util.Collection.
|
||||
*/
|
||||
public TypeDescriptor resolveCollectionElementType(Collection<?> collection) {
|
||||
if (!isCollection()) {
|
||||
throw new IllegalStateException("Not a java.util.Collection");
|
||||
}
|
||||
return new TypeDescriptor(type, CommonElement.typeDescriptor(collection), mapKeyType, mapValueType, annotations);
|
||||
public TypeDescriptor elementType(Object element) {
|
||||
if (elementType != null) {
|
||||
return elementType.narrowType(element);
|
||||
} else {
|
||||
return element != null ? new TypeDescriptor(element.getClass(), null, null, null, annotations) : null;
|
||||
}
|
||||
}
|
||||
|
||||
// map type descriptor operations
|
||||
|
@ -359,71 +312,51 @@ public class TypeDescriptor {
|
|||
* Is this type a {@link Map} type?
|
||||
*/
|
||||
public boolean isMap() {
|
||||
return getType() != null && Map.class.isAssignableFrom(getType());
|
||||
return Map.class.isAssignableFrom(getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* If this type is a {@link Map}, returns the underlying key type.
|
||||
* Returns Object.class if this type is a map and its key type was not explicitly declared.
|
||||
* @return the map key type, or <code>null</code> if not a map.
|
||||
* @throws IllegalStateException if this descriptor is not for a java.util.Map
|
||||
* If this type is a {@link Map} and its key type is parameterized, returns the map's key type.
|
||||
* If the Map's key type is not parameterized, returns null indicating the key type is not declared.
|
||||
* @return the Map key type, or <code>null</code> if this type is a Map but its key type is not parameterized.
|
||||
* @throws IllegalStateException if this type is not a java.util.Map.
|
||||
*/
|
||||
public Class<?> getMapKeyType() {
|
||||
return getMapKeyTypeDescriptor().getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* The map key type as a type descriptor.
|
||||
* Returns TypeDescriptor.valueOf(Object.class) if this type is a map and the key type is not explicitly declared.
|
||||
* @throws IllegalStateException if this descriptor is not for a java.util.Map
|
||||
*/
|
||||
public TypeDescriptor getMapKeyTypeDescriptor() {
|
||||
public TypeDescriptor getMapKeyType() {
|
||||
if (!isMap()) {
|
||||
throw new IllegalStateException("Not a map");
|
||||
}
|
||||
return this.mapKeyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this type is a {@link Map}, returns the underlying value type.
|
||||
* Returns <code>null</code> if this type is not map.
|
||||
* Returns Object.class if this type is a map and its value type was not explicitly declared.
|
||||
* @return the map value type, or <code>null</code> if not a map.
|
||||
* @throws IllegalStateException if this descriptor is not for a java.util.Map
|
||||
*/
|
||||
public Class<?> getMapValueType() {
|
||||
return getMapValueTypeDescriptor().getType();
|
||||
public TypeDescriptor mapKeyType(Object mapKey) {
|
||||
if (mapKeyType != null) {
|
||||
return mapKeyType.narrowType(mapKey);
|
||||
} else {
|
||||
return mapKey != null ? new TypeDescriptor(mapKey.getClass(), null, null, null, annotations) : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The map value type as a type descriptor.
|
||||
* Returns TypeDescriptor.valueOf(Object.class) if this type is a map and the value type is not explicitly declared.
|
||||
* @throws IllegalStateException if this descriptor is not for a java.util.Map
|
||||
* If this type is a {@link Map} and its value type is parameterized, returns the map's value type.
|
||||
* If the Map's value type is not parameterized, returns null indicating the value type is not declared.
|
||||
* @return the Map value type, or <code>null</code> if this type is a Map but its value type is not parameterized.
|
||||
* @throws IllegalStateException if this type is not a java.util.Map.
|
||||
*/
|
||||
public TypeDescriptor getMapValueTypeDescriptor() {
|
||||
public TypeDescriptor getMapValueType() {
|
||||
if (!isMap()) {
|
||||
throw new IllegalStateException("Not a map");
|
||||
}
|
||||
return this.mapValueType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this type descriptor that has its mapKeyType and mapValueType properties populated from the specified Map.
|
||||
* These properties will be set by calculating the "common element type" of the specified Map's keySet and values collection.
|
||||
* For example, if the Map contains String keys and Integer values, the returned TypeDescriptor will have its mapKeyType set to String and its mapValueType to Integer.
|
||||
* This method is designed to be used when converting values read from Map fields or method return values that are not parameterized e.g. Map vs. Map<String, Integer>.
|
||||
* In this scenario the key and value types will be Object.class before invoking this method.
|
||||
* @param map the map to derive key and value types from
|
||||
* @return a new TypeDescriptor with the resolved mapKeyType and mapValueType properties
|
||||
* @throws IllegalArgumentException if this is not a type descriptor for a java.util.Map.
|
||||
*/
|
||||
public TypeDescriptor resolveMapKeyValueTypes(Map<?, ?> map) {
|
||||
if (!isMap()) {
|
||||
throw new IllegalStateException("Not a java.util.Map");
|
||||
public TypeDescriptor mapValueType(Object mapValue) {
|
||||
if (mapValueType != null) {
|
||||
return mapValueType.narrowType(mapValue);
|
||||
} else {
|
||||
return mapValue != null ? new TypeDescriptor(mapValue.getClass(), null, null, null, annotations) : null;
|
||||
}
|
||||
return new TypeDescriptor(type, elementType, CommonElement.typeDescriptor(map.keySet()), CommonElement.typeDescriptor(map.values()), annotations);
|
||||
}
|
||||
|
||||
|
||||
// extending Object
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
|
@ -450,29 +383,24 @@ public class TypeDescriptor {
|
|||
}
|
||||
|
||||
public int hashCode() {
|
||||
return (this == TypeDescriptor.NULL ? 0 : getType().hashCode());
|
||||
return getType().hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (this == TypeDescriptor.NULL) {
|
||||
return "null";
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Annotation[] anns = getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
builder.append("@").append(ann.annotationType().getName()).append(' ');
|
||||
}
|
||||
else {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Annotation[] anns = getAnnotations();
|
||||
for (Annotation ann : anns) {
|
||||
builder.append("@").append(ann.annotationType().getName()).append(' ');
|
||||
}
|
||||
builder.append(ClassUtils.getQualifiedName(getType()));
|
||||
if (isMap()) {
|
||||
builder.append("<").append(getMapKeyTypeDescriptor());
|
||||
builder.append(", ").append(getMapValueTypeDescriptor()).append(">");
|
||||
}
|
||||
else if (isCollection()) {
|
||||
builder.append("<").append(getElementTypeDescriptor()).append(">");
|
||||
}
|
||||
return builder.toString();
|
||||
builder.append(ClassUtils.getQualifiedName(getType()));
|
||||
if (isMap()) {
|
||||
builder.append("<").append(wildcard(getMapKeyType()));
|
||||
builder.append(", ").append(wildcard(getMapValueType())).append(">");
|
||||
}
|
||||
else if (isCollection()) {
|
||||
builder.append("<").append(wildcard(getElementType())).append(">");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
// package private
|
||||
|
@ -485,14 +413,6 @@ public class TypeDescriptor {
|
|||
this.annotations = descriptor.getAnnotations();
|
||||
}
|
||||
|
||||
TypeDescriptor(Class<?> collectionType, TypeDescriptor elementType) {
|
||||
this(collectionType, elementType, TypeDescriptor.NULL, TypeDescriptor.NULL, EMPTY_ANNOTATION_ARRAY);
|
||||
}
|
||||
|
||||
TypeDescriptor(Class<?> mapType, TypeDescriptor keyType, TypeDescriptor valueType) {
|
||||
this(mapType, TypeDescriptor.NULL, keyType, valueType, EMPTY_ANNOTATION_ARRAY);
|
||||
}
|
||||
|
||||
static Annotation[] nullSafeAnnotations(Annotation[] annotations) {
|
||||
return annotations != null ? annotations : EMPTY_ANNOTATION_ARRAY;
|
||||
}
|
||||
|
@ -503,8 +423,12 @@ public class TypeDescriptor {
|
|||
this(new ClassDescriptor(type));
|
||||
}
|
||||
|
||||
private TypeDescriptor() {
|
||||
this(null, TypeDescriptor.NULL, TypeDescriptor.NULL, TypeDescriptor.NULL, EMPTY_ANNOTATION_ARRAY);
|
||||
private TypeDescriptor(Class<?> collectionType, TypeDescriptor elementType) {
|
||||
this(collectionType, elementType, null, null, EMPTY_ANNOTATION_ARRAY);
|
||||
}
|
||||
|
||||
private TypeDescriptor(Class<?> mapType, TypeDescriptor keyType, TypeDescriptor valueType) {
|
||||
this(mapType, null, keyType, valueType, EMPTY_ANNOTATION_ARRAY);
|
||||
}
|
||||
|
||||
private TypeDescriptor(Class<?> type, TypeDescriptor elementType, TypeDescriptor mapKeyType, TypeDescriptor mapValueType, Annotation[] annotations) {
|
||||
|
@ -515,8 +439,6 @@ public class TypeDescriptor {
|
|||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private static TypeDescriptor nested(AbstractDescriptor descriptor, int nestingLevel) {
|
||||
for (int i = 0; i < nestingLevel; i++) {
|
||||
descriptor = descriptor.nested();
|
||||
|
@ -524,4 +446,43 @@ public class TypeDescriptor {
|
|||
return new TypeDescriptor(descriptor);
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private boolean mapKeysAssignable(TypeDescriptor targetKeyType) {
|
||||
TypeDescriptor keyType = getMapKeyType();
|
||||
if (targetKeyType == null) {
|
||||
return true;
|
||||
}
|
||||
if (keyType == null) {
|
||||
return false;
|
||||
}
|
||||
return keyType.isAssignableTo(targetKeyType);
|
||||
}
|
||||
|
||||
private boolean collectionElementsAssignable(TypeDescriptor targetElementType) {
|
||||
TypeDescriptor elementType = getElementType();
|
||||
if (targetElementType == null) {
|
||||
return true;
|
||||
}
|
||||
if (elementType == null) {
|
||||
return false;
|
||||
}
|
||||
return elementType.isAssignableTo(targetElementType);
|
||||
}
|
||||
|
||||
private boolean mapValuesAssignable(TypeDescriptor targetValueType) {
|
||||
TypeDescriptor valueType = getMapValueType();
|
||||
if (targetValueType == null) {
|
||||
return true;
|
||||
}
|
||||
if (valueType == null) {
|
||||
return false;
|
||||
}
|
||||
return valueType.isAssignableTo(targetValueType);
|
||||
}
|
||||
|
||||
private String wildcard(TypeDescriptor nestedType) {
|
||||
return nestedType != null ? nestedType.toString() : "?";
|
||||
}
|
||||
|
||||
}
|
|
@ -44,10 +44,6 @@ final class ArrayToArrayConverter implements GenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(Object[].class, Object[].class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.helperConverter.matches(sourceType, targetType);
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.helperConverter.convert(Arrays.asList(ObjectUtils.toObjectArray(source)), sourceType, targetType);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.util.Set;
|
|||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
|
||||
/**
|
||||
* Converts an Array to a Collection.
|
||||
|
@ -36,7 +36,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
|||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class ArrayToCollectionConverter implements ConditionalGenericConverter {
|
||||
final class ArrayToCollectionConverter implements GenericConverter {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
|
@ -48,10 +48,6 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(Object[].class, Collection.class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (source == null) {
|
||||
|
@ -59,9 +55,7 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter {
|
|||
}
|
||||
int length = Array.getLength(source);
|
||||
Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), length);
|
||||
TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor();
|
||||
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
|
||||
if (Object.class.equals(targetElementType.getType())) {
|
||||
if (targetType.getElementType() == null) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object sourceElement = Array.get(source, i);
|
||||
target.add(sourceElement);
|
||||
|
@ -69,7 +63,7 @@ final class ArrayToCollectionConverter implements ConditionalGenericConverter {
|
|||
} else {
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object sourceElement = Array.get(source, i);
|
||||
Object targetElement = this.conversionService.convert(sourceElement, sourceElementType, targetElementType);
|
||||
Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType.getElementType());
|
||||
target.add(targetElement);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.util.Set;
|
|||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
|
@ -32,7 +32,7 @@ import org.springframework.util.ObjectUtils;
|
|||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class ArrayToObjectConverter implements ConditionalGenericConverter {
|
||||
final class ArrayToObjectConverter implements GenericConverter {
|
||||
|
||||
private final CollectionToObjectConverter helperConverter;
|
||||
|
||||
|
@ -44,10 +44,6 @@ final class ArrayToObjectConverter implements ConditionalGenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(Object[].class, Object.class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.helperConverter.matches(sourceType, targetType);
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.helperConverter.convert(Arrays.asList(ObjectUtils.toObjectArray(source)), sourceType, targetType);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.util.Set;
|
|||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
|
@ -32,7 +32,7 @@ import org.springframework.util.ObjectUtils;
|
|||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class ArrayToStringConverter implements ConditionalGenericConverter {
|
||||
final class ArrayToStringConverter implements GenericConverter {
|
||||
|
||||
private final CollectionToStringConverter helperConverter;
|
||||
|
||||
|
@ -44,10 +44,6 @@ final class ArrayToStringConverter implements ConditionalGenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(Object[].class, String.class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.helperConverter.matches(sourceType, targetType);
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.helperConverter.convert(Arrays.asList(ObjectUtils.toObjectArray(source)), sourceType, targetType);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import java.util.Set;
|
|||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
|
||||
/**
|
||||
* Converts a Collection to an array.
|
||||
|
@ -36,7 +36,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
|||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class CollectionToArrayConverter implements ConditionalGenericConverter {
|
||||
final class CollectionToArrayConverter implements GenericConverter {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
|
@ -48,20 +48,15 @@ final class CollectionToArrayConverter implements ConditionalGenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(Collection.class, Object[].class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor());
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
Collection<?> sourceCollection = (Collection<?>) source;
|
||||
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
|
||||
Object array = Array.newInstance(targetElementType.getType(), sourceCollection.size());
|
||||
Object array = Array.newInstance(targetType.getElementType().getType(), sourceCollection.size());
|
||||
int i = 0;
|
||||
for (Object sourceElement : sourceCollection) {
|
||||
Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetElementType);
|
||||
Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType.getElementType());
|
||||
Array.set(array, i++, targetElement);
|
||||
}
|
||||
return array;
|
||||
|
|
|
@ -23,7 +23,7 @@ import java.util.Set;
|
|||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
|
||||
/**
|
||||
* Converts from a Collection to another Collection.
|
||||
|
@ -36,7 +36,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
|||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class CollectionToCollectionConverter implements ConditionalGenericConverter {
|
||||
final class CollectionToCollectionConverter implements GenericConverter {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
|
@ -48,12 +48,6 @@ final class CollectionToCollectionConverter implements ConditionalGenericConvert
|
|||
return Collections.singleton(new ConvertiblePair(Collection.class, Collection.class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor();
|
||||
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
|
||||
return this.conversionService.canConvert(sourceElementType, targetElementType);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (source == null) {
|
||||
|
@ -61,17 +55,15 @@ final class CollectionToCollectionConverter implements ConditionalGenericConvert
|
|||
}
|
||||
Collection<?> sourceCollection = (Collection<?>) source;
|
||||
Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size());
|
||||
TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor();
|
||||
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
|
||||
if (Object.class.equals(targetElementType.getType())) {
|
||||
for (Object sourceElement : sourceCollection) {
|
||||
target.add(sourceElement);
|
||||
}
|
||||
if (targetType.getElementType() == null) {
|
||||
for (Object element : sourceCollection) {
|
||||
target.add(element);
|
||||
}
|
||||
} else {
|
||||
for (Object sourceElement : sourceCollection) {
|
||||
Object targetElement = this.conversionService.convert(sourceElement, sourceElementType, targetElementType);
|
||||
Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType.getElementType());
|
||||
target.add(targetElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.util.Set;
|
|||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
|
||||
/**
|
||||
* Converts a Collection to an Object by returning the first collection element after converting it to the desired targetType.
|
||||
|
@ -30,7 +30,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
|||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class CollectionToObjectConverter implements ConditionalGenericConverter {
|
||||
final class CollectionToObjectConverter implements GenericConverter {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
|
@ -42,10 +42,6 @@ final class CollectionToObjectConverter implements ConditionalGenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(Collection.class, Object.class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType);
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
|
@ -55,7 +51,7 @@ final class CollectionToObjectConverter implements ConditionalGenericConverter {
|
|||
return null;
|
||||
}
|
||||
Object firstElement = sourceCollection.iterator().next();
|
||||
return this.conversionService.convert(firstElement, sourceType.getElementTypeDescriptor(), targetType);
|
||||
return this.conversionService.convert(firstElement, sourceType.elementType(firstElement), targetType);
|
||||
}
|
||||
|
||||
}
|
|
@ -22,7 +22,7 @@ import java.util.Set;
|
|||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
|
||||
/**
|
||||
* Converts a Collection to a comma-delimited String.
|
||||
|
@ -30,7 +30,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
|||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class CollectionToStringConverter implements ConditionalGenericConverter {
|
||||
final class CollectionToStringConverter implements GenericConverter {
|
||||
|
||||
private static final String DELIMITER = ",";
|
||||
|
||||
|
@ -44,10 +44,6 @@ final class CollectionToStringConverter implements ConditionalGenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(Collection.class, String.class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.canConvert(sourceType.getElementTypeDescriptor(), targetType);
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
|
@ -56,17 +52,17 @@ final class CollectionToStringConverter implements ConditionalGenericConverter {
|
|||
if (sourceCollection.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder string = new StringBuilder();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i = 0;
|
||||
for (Object sourceElement : sourceCollection) {
|
||||
if (i > 0) {
|
||||
string.append(DELIMITER);
|
||||
sb.append(DELIMITER);
|
||||
}
|
||||
Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType);
|
||||
string.append(targetElement);
|
||||
Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType);
|
||||
sb.append(targetElement);
|
||||
i++;
|
||||
}
|
||||
return string.toString();
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -138,18 +138,16 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T convert(Object source, Class<T> targetType) {
|
||||
if (targetType == null) {
|
||||
throw new IllegalArgumentException("The targetType to convert to cannot be null");
|
||||
}
|
||||
return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
|
||||
}
|
||||
|
||||
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
assertNotNull(sourceType, targetType);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Checking if I can convert " + sourceType + " to " + targetType);
|
||||
}
|
||||
if (sourceType == TypeDescriptor.NULL || targetType == TypeDescriptor.NULL) {
|
||||
logger.trace("Yes, I can convert");
|
||||
return true;
|
||||
}
|
||||
GenericConverter converter = getConverter(sourceType, targetType);
|
||||
if (converter != null) {
|
||||
logger.trace("Yes, I can convert");
|
||||
|
@ -162,21 +160,19 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
assertNotNull(sourceType, targetType);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converting value " + StylerUtils.style(source) + " of " + sourceType + " to " + targetType);
|
||||
if (targetType == null) {
|
||||
throw new IllegalArgumentException("The targetType to convert to cannot be null");
|
||||
}
|
||||
if (sourceType == TypeDescriptor.NULL) {
|
||||
if (sourceType == null) {
|
||||
Assert.isTrue(source == null, "The source must be [null] if sourceType == [null]");
|
||||
return handleResult(sourceType, targetType, convertNullSource(sourceType, targetType));
|
||||
}
|
||||
if (targetType == TypeDescriptor.NULL) {
|
||||
logger.debug("Converted to null");
|
||||
return null;
|
||||
}
|
||||
if (source != null && !sourceType.getObjectType().isInstance(source)) {
|
||||
throw new IllegalArgumentException("The source to convert from must be an instance of " + sourceType + "; instead it was a " + source.getClass().getName());
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Converting value " + StylerUtils.style(source) + " of " + sourceType + " to " + targetType);
|
||||
}
|
||||
GenericConverter converter = getConverter(sourceType, targetType);
|
||||
if (converter != null) {
|
||||
return handleResult(sourceType, targetType, ConversionUtils.invokeConverter(converter, source, sourceType, targetType));
|
||||
|
@ -236,30 +232,26 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Matched cached converter " + converter);
|
||||
}
|
||||
return (converter != NO_MATCH ? converter : null);
|
||||
return converter != NO_MATCH ? converter : null;
|
||||
}
|
||||
else {
|
||||
converter = findConverterForClassPair(sourceType, targetType);
|
||||
if (converter == null) {
|
||||
converter = getDefaultConverter(sourceType, targetType);
|
||||
}
|
||||
if (converter != null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Caching under " + key);
|
||||
logger.trace("Caching matched Converter under key " + key);
|
||||
}
|
||||
this.converterCache.put(key, converter);
|
||||
return converter;
|
||||
}
|
||||
converter = getDefaultConverter(sourceType, targetType);
|
||||
if (converter != null) {
|
||||
} else {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Caching under " + key);
|
||||
logger.trace("Caching Converter [NO_MATCH] result under key " + key);
|
||||
}
|
||||
this.converterCache.put(key, converter);
|
||||
return converter;
|
||||
this.converterCache.put(key, NO_MATCH);
|
||||
return null;
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Caching NO_MATCH under " + key);
|
||||
}
|
||||
this.converterCache.put(key, NO_MATCH);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,11 +304,6 @@ public class GenericConversionService implements ConfigurableConversionService {
|
|||
return sourceMap;
|
||||
}
|
||||
|
||||
private void assertNotNull(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
Assert.notNull(sourceType, "The sourceType to convert from is required");
|
||||
Assert.notNull(targetType, "The targetType to convert to is required");
|
||||
}
|
||||
|
||||
private GenericConverter findConverterForClassPair(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
Class<?> sourceObjectType = sourceType.getObjectType();
|
||||
if (sourceObjectType.isInterface()) {
|
||||
|
|
|
@ -23,7 +23,7 @@ import java.util.Set;
|
|||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
|
||||
/**
|
||||
* Converts a Map to another Map.
|
||||
|
@ -36,7 +36,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
|||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class MapToMapConverter implements ConditionalGenericConverter {
|
||||
final class MapToMapConverter implements GenericConverter {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
|
@ -48,11 +48,6 @@ final class MapToMapConverter implements ConditionalGenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(Map.class, Map.class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.canConvert(sourceType.getMapKeyTypeDescriptor(), targetType.getMapKeyTypeDescriptor()) &&
|
||||
this.conversionService.canConvert(sourceType.getMapValueTypeDescriptor(), targetType.getMapValueTypeDescriptor());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (source == null) {
|
||||
|
@ -60,24 +55,30 @@ final class MapToMapConverter implements ConditionalGenericConverter {
|
|||
}
|
||||
Map<Object, Object> sourceMap = (Map<Object, Object>) source;
|
||||
Map<Object, Object> targetMap = CollectionFactory.createMap(targetType.getType(), sourceMap.size());
|
||||
TypeDescriptor sourceKeyType = sourceType.getMapKeyTypeDescriptor();
|
||||
TypeDescriptor targetKeyType = targetType.getMapKeyTypeDescriptor();
|
||||
TypeDescriptor sourceValueType = sourceType.getMapValueTypeDescriptor();
|
||||
TypeDescriptor targetValueType = targetType.getMapValueTypeDescriptor();
|
||||
if (Object.class.equals(targetKeyType.getType()) && Object.class.equals(targetValueType.getType())) {
|
||||
for (Map.Entry<Object, Object> entry : sourceMap.entrySet()) {
|
||||
targetMap.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
} else {
|
||||
for (Map.Entry<Object, Object> entry : sourceMap.entrySet()) {
|
||||
Object sourceKey = entry.getKey();
|
||||
Object sourceValue = entry.getValue();
|
||||
Object targetKey = this.conversionService.convert(sourceKey, sourceKeyType, targetKeyType);
|
||||
Object targetValue = this.conversionService.convert(sourceValue, sourceValueType, targetValueType);
|
||||
targetMap.put(targetKey, targetValue);
|
||||
}
|
||||
for (Map.Entry<Object, Object> entry : sourceMap.entrySet()) {
|
||||
Object sourceKey = entry.getKey();
|
||||
Object sourceValue = entry.getValue();
|
||||
Object targetKey = convertKey(sourceKey, sourceType, targetType.getMapKeyType());
|
||||
Object targetValue = convertValue(sourceValue, sourceType, targetType.getMapValueType());
|
||||
targetMap.put(targetKey, targetValue);
|
||||
}
|
||||
return targetMap;
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private Object convertKey(Object sourceKey, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (targetType == null) {
|
||||
return sourceKey;
|
||||
}
|
||||
return this.conversionService.convert(sourceKey, sourceType.mapKeyType(sourceKey), targetType);
|
||||
}
|
||||
|
||||
private Object convertValue(Object sourceValue, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (targetType == null) {
|
||||
return sourceValue;
|
||||
}
|
||||
return this.conversionService.convert(sourceValue, sourceType.mapValueType(sourceValue), targetType);
|
||||
}
|
||||
|
||||
}
|
|
@ -22,7 +22,7 @@ import java.util.Set;
|
|||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
|
||||
/**
|
||||
* Converts an Object to a single-element Array containing the Object.
|
||||
|
@ -31,7 +31,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
|||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class ObjectToArrayConverter implements ConditionalGenericConverter {
|
||||
final class ObjectToArrayConverter implements GenericConverter {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
|
@ -43,16 +43,12 @@ final class ObjectToArrayConverter implements ConditionalGenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(Object.class, Object[].class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
Object target = Array.newInstance(targetType.getElementType(), 1);
|
||||
Object targetElement = this.conversionService.convert(source, sourceType, targetType.getElementTypeDescriptor());
|
||||
Object target = Array.newInstance(targetType.getElementType().getType(), 1);
|
||||
Object targetElement = this.conversionService.convert(source, sourceType, targetType.getElementType());
|
||||
Array.set(target, 0, targetElement);
|
||||
return target;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import java.util.Set;
|
|||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
|
||||
/**
|
||||
* Converts an Object to a single-element Collection containing the Object.
|
||||
|
@ -33,7 +33,7 @@ import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
|||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
final class ObjectToCollectionConverter implements ConditionalGenericConverter {
|
||||
final class ObjectToCollectionConverter implements GenericConverter {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
|
@ -45,22 +45,17 @@ final class ObjectToCollectionConverter implements ConditionalGenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(Object.class, Collection.class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), 1);
|
||||
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
|
||||
// Avoid potential recursion....
|
||||
if (targetElementType.isCollection()) {
|
||||
if (targetType.getElementType() == null || targetType.getElementType().isCollection()) {
|
||||
target.add(source);
|
||||
} else {
|
||||
target.add(this.conversionService.convert(source, sourceType, targetElementType));
|
||||
Object singleElement = this.conversionService.convert(source, sourceType, targetType.getElementType());
|
||||
target.add(singleElement);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
|
|
@ -48,9 +48,7 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
|
|||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
Class<?> source = sourceType.getType();
|
||||
Class<?> target = targetType.getType();
|
||||
return !source.equals(target) && hasValueOfMethodOrConstructor(target, source);
|
||||
return !sourceType.equals(targetType) && hasValueOfMethodOrConstructor(targetType.getType(), sourceType.getType());
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
|
@ -79,16 +77,16 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
|
|||
") method or Constructor(" + sourceClass.getName() + ") exists on " + targetClass.getName());
|
||||
}
|
||||
|
||||
public static boolean hasValueOfMethodOrConstructor(Class<?> targetClass, Class<?> sourceClass) {
|
||||
return getValueOfMethodOn(targetClass, sourceClass) != null || getConstructor(targetClass, sourceClass) != null;
|
||||
static boolean hasValueOfMethodOrConstructor(Class<?> clazz, Class<?> sourceParameterType) {
|
||||
return getValueOfMethodOn(clazz, sourceParameterType) != null || getConstructor(clazz, sourceParameterType) != null;
|
||||
}
|
||||
|
||||
private static Method getValueOfMethodOn(Class<?> targetClass, Class<?> sourceClass) {
|
||||
return ClassUtils.getStaticMethod(targetClass, "valueOf", sourceClass);
|
||||
private static Method getValueOfMethodOn(Class<?> clazz, Class<?> sourceParameterType) {
|
||||
return ClassUtils.getStaticMethod(clazz, "valueOf", sourceParameterType);
|
||||
}
|
||||
|
||||
private static Constructor<?> getConstructor(Class<?> targetClass, Class<?> sourceClass) {
|
||||
return ClassUtils.getConstructorIfAvailable(targetClass, sourceClass);
|
||||
private static Constructor<?> getConstructor(Class<?> clazz, Class<?> sourceParameterType) {
|
||||
return ClassUtils.getConstructorIfAvailable(clazz, sourceParameterType);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.util.Set;
|
|||
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.converter.ConditionalGenericConverter;
|
||||
import org.springframework.core.convert.converter.GenericConverter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -31,7 +31,7 @@ import org.springframework.util.StringUtils;
|
|||
* @author Keith Donald
|
||||
* @since 3.0
|
||||
*/
|
||||
final class StringToArrayConverter implements ConditionalGenericConverter {
|
||||
final class StringToArrayConverter implements GenericConverter {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
|
||||
|
@ -43,20 +43,16 @@ final class StringToArrayConverter implements ConditionalGenericConverter {
|
|||
return Collections.singleton(new ConvertiblePair(String.class, Object[].class));
|
||||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
|
||||
}
|
||||
|
||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
String string = (String) source;
|
||||
String[] fields = StringUtils.commaDelimitedListToStringArray(string);
|
||||
Object target = Array.newInstance(targetType.getElementType(), fields.length);
|
||||
Object target = Array.newInstance(targetType.getElementType().getType(), fields.length);
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
String sourceElement = fields[i];
|
||||
Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementTypeDescriptor());
|
||||
Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementType());
|
||||
Array.set(target, i, targetElement);
|
||||
}
|
||||
return target;
|
||||
|
|
|
@ -45,7 +45,10 @@ final class StringToCollectionConverter implements ConditionalGenericConverter {
|
|||
}
|
||||
|
||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||
return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
|
||||
if (targetType.getElementType() == null) {
|
||||
return true;
|
||||
}
|
||||
return this.conversionService.canConvert(sourceType, targetType.getElementType());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -56,11 +59,17 @@ final class StringToCollectionConverter implements ConditionalGenericConverter {
|
|||
String string = (String) source;
|
||||
String[] fields = StringUtils.commaDelimitedListToStringArray(string);
|
||||
Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), fields.length);
|
||||
for (String sourceElement : fields) {
|
||||
Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementTypeDescriptor());
|
||||
target.add(targetElement);
|
||||
if (targetType.getElementType() == null) {
|
||||
for (String field : fields) {
|
||||
target.add(field.trim());
|
||||
}
|
||||
} else {
|
||||
for (String field : fields) {
|
||||
Object targetElement = this.conversionService.convert(field.trim(), sourceType, targetType.getElementType());
|
||||
target.add(targetElement);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@ 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.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
@ -37,7 +36,6 @@ import java.util.Map;
|
|||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
|
||||
/**
|
||||
|
@ -62,18 +60,6 @@ public class TypeDescriptorTests {
|
|||
|
||||
public Map<String, List<Integer>> nestedMapField = new HashMap<String, List<Integer>>();
|
||||
|
||||
@Test
|
||||
public void nullTypeDescriptor() {
|
||||
TypeDescriptor desc = TypeDescriptor.NULL;
|
||||
assertEquals(false, desc.isMap());
|
||||
assertEquals(false, desc.isCollection());
|
||||
assertEquals(false, desc.isArray());
|
||||
assertEquals(null, desc.getType());
|
||||
assertEquals(null, desc.getObjectType());
|
||||
assertEquals(null, desc.getName());
|
||||
assertEquals(0, desc.getAnnotations().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parameterPrimitive() throws Exception {
|
||||
TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterPrimitive", int.class), 0));
|
||||
|
@ -121,12 +107,12 @@ public class TypeDescriptorTests {
|
|||
assertEquals(0, desc.getAnnotations().length);
|
||||
assertTrue(desc.isCollection());
|
||||
assertFalse(desc.isArray());
|
||||
assertEquals(List.class, desc.getElementType());
|
||||
assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getElementTypeDescriptor());
|
||||
assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getElementTypeDescriptor().getElementTypeDescriptor());
|
||||
assertEquals(TypeDescriptor.nested(methodParameter, 3), desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor());
|
||||
assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapKeyTypeDescriptor().getType());
|
||||
assertEquals(Enum.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor().getType());
|
||||
assertEquals(List.class, desc.getElementType().getType());
|
||||
assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getElementType());
|
||||
assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getElementType().getElementType());
|
||||
assertEquals(TypeDescriptor.nested(methodParameter, 3), desc.getElementType().getElementType().getMapValueType());
|
||||
assertEquals(Integer.class, desc.getElementType().getElementType().getMapKeyType().getType());
|
||||
assertEquals(Enum.class, desc.getElementType().getElementType().getMapValueType().getType());
|
||||
assertFalse(desc.isMap());
|
||||
}
|
||||
|
||||
|
@ -141,13 +127,12 @@ public class TypeDescriptorTests {
|
|||
assertEquals(List.class, desc.getType());
|
||||
assertEquals(List.class, desc.getObjectType());
|
||||
assertEquals("java.util.List", desc.getName());
|
||||
assertEquals("java.util.List<java.lang.Object>", desc.toString());
|
||||
assertEquals("java.util.List<?>", desc.toString());
|
||||
assertTrue(!desc.isPrimitive());
|
||||
assertEquals(0, desc.getAnnotations().length);
|
||||
assertTrue(desc.isCollection());
|
||||
assertFalse(desc.isArray());
|
||||
assertEquals(Object.class, desc.getElementType());
|
||||
assertEquals(TypeDescriptor.valueOf(Object.class), desc.getElementTypeDescriptor());
|
||||
assertNull(desc.getElementType());
|
||||
assertFalse(desc.isMap());
|
||||
}
|
||||
|
||||
|
@ -167,8 +152,8 @@ public class TypeDescriptorTests {
|
|||
assertEquals(0, desc.getAnnotations().length);
|
||||
assertFalse(desc.isCollection());
|
||||
assertTrue(desc.isArray());
|
||||
assertEquals(Integer.class, desc.getElementType());
|
||||
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor());
|
||||
assertEquals(Integer.class, desc.getElementType().getType());
|
||||
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementType());
|
||||
assertFalse(desc.isMap());
|
||||
}
|
||||
|
||||
|
@ -189,11 +174,11 @@ public class TypeDescriptorTests {
|
|||
assertFalse(desc.isCollection());
|
||||
assertFalse(desc.isArray());
|
||||
assertTrue(desc.isMap());
|
||||
assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueTypeDescriptor());
|
||||
assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueTypeDescriptor().getElementTypeDescriptor());
|
||||
assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getType());
|
||||
assertEquals(List.class, desc.getMapValueTypeDescriptor().getType());
|
||||
assertEquals(String.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType());
|
||||
assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueType());
|
||||
assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueType().getElementType());
|
||||
assertEquals(Integer.class, desc.getMapKeyType().getType());
|
||||
assertEquals(List.class, desc.getMapValueType().getType());
|
||||
assertEquals(String.class, desc.getMapValueType().getElementType().getType());
|
||||
}
|
||||
|
||||
public void testParameterMap(Map<Integer, List<String>> map) {
|
||||
|
@ -222,8 +207,8 @@ public class TypeDescriptorTests {
|
|||
public void propertyComplex() throws Exception {
|
||||
PropertyDescriptor property = new PropertyDescriptor("complexProperty", getClass().getMethod("getComplexProperty", null), getClass().getMethod("setComplexProperty", Map.class));
|
||||
TypeDescriptor desc = new TypeDescriptor(getClass(), property);
|
||||
//assertEquals(String.class, desc.getMapKeyType());
|
||||
assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getElementType());
|
||||
assertEquals(String.class, desc.getMapKeyType().getType());
|
||||
assertEquals(Integer.class, desc.getMapValueType().getElementType().getElementType().getType());
|
||||
}
|
||||
|
||||
public Map<String, List<List<Integer>>> getComplexProperty() {
|
||||
|
@ -248,7 +233,7 @@ public class TypeDescriptorTests {
|
|||
PropertyDescriptor property = new PropertyDescriptor("listProperty", genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
|
||||
TypeDescriptor desc = new TypeDescriptor(genericBean.getClass(), property);
|
||||
assertEquals(List.class, desc.getType());
|
||||
assertEquals(Integer.class, desc.getElementType());
|
||||
assertEquals(Integer.class, desc.getElementType().getType());
|
||||
}
|
||||
|
||||
public interface GenericType<T> {
|
||||
|
@ -292,7 +277,7 @@ public class TypeDescriptorTests {
|
|||
PropertyDescriptor property = new PropertyDescriptor("listProperty", genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));
|
||||
TypeDescriptor desc = new TypeDescriptor(genericBean.getClass(), property);
|
||||
assertEquals(List.class, desc.getType());
|
||||
assertEquals(Integer.class, desc.getElementType());
|
||||
assertEquals(Integer.class, desc.getElementType().getType());
|
||||
assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
|
||||
}
|
||||
|
||||
|
@ -323,8 +308,8 @@ public class TypeDescriptorTests {
|
|||
public void property() throws Exception {
|
||||
PropertyDescriptor property = new PropertyDescriptor("property", getClass().getMethod("getProperty", null), getClass().getMethod("setProperty", Map.class));
|
||||
TypeDescriptor desc = new TypeDescriptor(getClass(), property);
|
||||
assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementType());
|
||||
assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementType());
|
||||
assertEquals(Integer.class, desc.getMapKeyType().getElementType().getType());
|
||||
assertEquals(Long.class, desc.getMapValueType().getElementType().getType());
|
||||
assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
|
||||
assertNotNull(desc.getAnnotation(MethodAnnotation2.class));
|
||||
assertNotNull(desc.getAnnotation(MethodAnnotation3.class));
|
||||
|
@ -379,8 +364,7 @@ public class TypeDescriptorTests {
|
|||
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfString"));
|
||||
assertFalse(typeDescriptor.isArray());
|
||||
assertEquals(List.class, typeDescriptor.getType());
|
||||
assertEquals(String.class, typeDescriptor.getElementType());
|
||||
// TODO caught shorten these names but it is OK that they are fully qualified for now
|
||||
assertEquals(String.class, typeDescriptor.getElementType().getType());
|
||||
assertEquals("java.util.List<java.lang.String>", typeDescriptor.toString());
|
||||
}
|
||||
|
||||
|
@ -389,8 +373,8 @@ public class TypeDescriptorTests {
|
|||
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfString"));
|
||||
assertFalse(typeDescriptor.isArray());
|
||||
assertEquals(List.class, typeDescriptor.getType());
|
||||
assertEquals(List.class, typeDescriptor.getElementType());
|
||||
assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementType());
|
||||
assertEquals(List.class, typeDescriptor.getElementType().getType());
|
||||
assertEquals(String.class, typeDescriptor.getElementType().getElementType().getType());
|
||||
assertEquals("java.util.List<java.util.List<java.lang.String>>", typeDescriptor.toString());
|
||||
}
|
||||
|
||||
|
@ -399,16 +383,16 @@ public class TypeDescriptorTests {
|
|||
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfUnknown"));
|
||||
assertFalse(typeDescriptor.isArray());
|
||||
assertEquals(List.class, typeDescriptor.getType());
|
||||
assertEquals(List.class, typeDescriptor.getElementType());
|
||||
assertEquals(Object.class, typeDescriptor.getElementTypeDescriptor().getElementType());
|
||||
assertEquals("java.util.List<java.util.List<java.lang.Object>>", typeDescriptor.toString());
|
||||
assertEquals(List.class, typeDescriptor.getElementType().getType());
|
||||
assertNull(typeDescriptor.getElementType().getElementType());
|
||||
assertEquals("java.util.List<java.util.List<?>>", typeDescriptor.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fieldArray() throws Exception {
|
||||
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("intArray"));
|
||||
assertTrue(typeDescriptor.isArray());
|
||||
assertEquals(Integer.TYPE,typeDescriptor.getElementType());
|
||||
assertEquals(Integer.TYPE,typeDescriptor.getElementType().getType());
|
||||
assertEquals("int[]",typeDescriptor.toString());
|
||||
}
|
||||
|
||||
|
@ -418,7 +402,7 @@ public class TypeDescriptorTests {
|
|||
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("arrayOfListOfString"));
|
||||
assertTrue(typeDescriptor.isArray());
|
||||
assertEquals(List.class,typeDescriptor.getElementType());
|
||||
assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementType());
|
||||
assertEquals(String.class, typeDescriptor.getElementType().getElementType());
|
||||
assertEquals("java.util.List[]",typeDescriptor.toString());
|
||||
}
|
||||
|
||||
|
@ -426,9 +410,9 @@ public class TypeDescriptorTests {
|
|||
public void fieldComplexTypeDescriptor2() throws Exception {
|
||||
TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("nestedMapField"));
|
||||
assertTrue(typeDescriptor.isMap());
|
||||
assertEquals(String.class,typeDescriptor.getMapKeyType());
|
||||
assertEquals(List.class, typeDescriptor.getMapValueType());
|
||||
assertEquals(Integer.class, typeDescriptor.getMapValueTypeDescriptor().getElementType());
|
||||
assertEquals(String.class,typeDescriptor.getMapKeyType().getType());
|
||||
assertEquals(List.class, typeDescriptor.getMapValueType().getType());
|
||||
assertEquals(Integer.class, typeDescriptor.getMapValueType().getElementType().getType());
|
||||
assertEquals("java.util.Map<java.lang.String, java.util.List<java.lang.Integer>>", typeDescriptor.toString());
|
||||
}
|
||||
|
||||
|
@ -438,8 +422,8 @@ public class TypeDescriptorTests {
|
|||
// TODO: SPR-8394: typeIndex handling not currently supported by fields
|
||||
TypeDescriptor desc = new TypeDescriptor(getClass().getField("fieldMap"));
|
||||
assertTrue(desc.isMap());
|
||||
assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementType());
|
||||
assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementType());
|
||||
assertEquals(Integer.class, desc.getMapKeyType().getElementType());
|
||||
assertEquals(Long.class, desc.getMapValueType().getElementType());
|
||||
}
|
||||
|
||||
public Map<List<Integer>, List<Long>> fieldMap;
|
||||
|
@ -488,7 +472,7 @@ public class TypeDescriptorTests {
|
|||
assertTrue(typeDescriptor.isArray());
|
||||
assertFalse(typeDescriptor.isCollection());
|
||||
assertFalse(typeDescriptor.isMap());
|
||||
assertEquals(Integer.TYPE, typeDescriptor.getElementType());
|
||||
assertEquals(Integer.TYPE, typeDescriptor.getElementType().getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -497,117 +481,19 @@ public class TypeDescriptorTests {
|
|||
assertTrue(typeDescriptor.isCollection());
|
||||
assertFalse(typeDescriptor.isArray());
|
||||
assertFalse(typeDescriptor.isMap());
|
||||
assertEquals(Object.class, typeDescriptor.getElementType());
|
||||
assertNull(typeDescriptor.getElementType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forObjectCollection() {
|
||||
List<String> list = new ArrayList<String>();
|
||||
list.add("1");
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(list);
|
||||
assertEquals(String.class, desc.getElementType());
|
||||
public void forObject() {
|
||||
TypeDescriptor desc = TypeDescriptor.forObject("3");
|
||||
assertEquals(String.class, desc.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forObjectCollectionEmpty() {
|
||||
List<String> list = new ArrayList<String>();
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(list);
|
||||
assertNull(desc.getElementType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forObjectCollectionSuperClassCommonType() throws SecurityException, NoSuchFieldException {
|
||||
List<Number> list = new ArrayList<Number>();
|
||||
list.add(1);
|
||||
list.add(2L);
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(list);
|
||||
assertEquals(Number.class, desc.getElementType());
|
||||
}
|
||||
|
||||
public List<Long> longs;
|
||||
|
||||
@Test
|
||||
public void forObjectCollectionNoObviousCommonType() {
|
||||
List<Object> collection = new ArrayList<Object>();
|
||||
List<String> list = new ArrayList<String>();
|
||||
list.add("1");
|
||||
collection.add(list);
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
collection.add(map);
|
||||
map.put("1", "2");
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(collection);
|
||||
assertEquals(Cloneable.class, desc.getElementType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forObjectCollectionNoCommonType() {
|
||||
List<Object> collection = new ArrayList<Object>();
|
||||
collection.add(new Object());
|
||||
collection.add("1");
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(collection);
|
||||
assertEquals(Object.class, desc.getElementType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forObjectCollectionNested() {
|
||||
List<Object> collection = new ArrayList<Object>();
|
||||
collection.add(Arrays.asList("1", "2"));
|
||||
collection.add(Arrays.asList("3", "4"));
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(collection);
|
||||
assertEquals(Arrays.asList("foo").getClass(), desc.getElementType());
|
||||
assertEquals(String.class, desc.getElementTypeDescriptor().getElementType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forObjectMap() {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
map.put("1", "2");
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(map);
|
||||
assertEquals(String.class, desc.getMapKeyType());
|
||||
assertEquals(String.class, desc.getMapValueType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forObjectMapEmpty() {
|
||||
Map<String, String> map = new HashMap<String, String>();
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(map);
|
||||
assertNull(desc.getMapKeyType());
|
||||
assertNull(desc.getMapValueType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forObjectMapCommonSuperClass() {
|
||||
Map<Number, Number> map = new HashMap<Number, Number>();
|
||||
map.put(1, 2);
|
||||
map.put(2L, 3L);
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(map);
|
||||
assertEquals(Number.class, desc.getMapKeyType());
|
||||
assertEquals(Number.class, desc.getMapValueType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forObjectMapNoObviousCommonType() {
|
||||
Map<Object, Object> map = new HashMap<Object, Object>();
|
||||
map.put("1", "2");
|
||||
map.put(2, 2);
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(map);
|
||||
assertEquals(Comparable.class, desc.getMapKeyType());
|
||||
assertEquals(Comparable.class, desc.getMapValueType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forObjectMapNested() {
|
||||
Map<Integer, List<String>> map = new HashMap<Integer, List<String>>();
|
||||
map.put(1, Arrays.asList("1, 2"));
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(map);
|
||||
assertEquals(Integer.class, desc.getMapKeyType());
|
||||
assertEquals(String.class, desc.getMapValueTypeDescriptor().getElementType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nestedMethodParameterType() throws Exception {
|
||||
TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test1", List.class), 0), 1);
|
||||
assertEquals(String.class, t1.getType());
|
||||
public void forObjectNullTypeDescriptor() {
|
||||
TypeDescriptor desc = TypeDescriptor.forObject(null);
|
||||
assertNull(desc);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -692,8 +578,8 @@ public class TypeDescriptorTests {
|
|||
assertEquals(0, desc.getAnnotations().length);
|
||||
assertTrue(desc.isCollection());
|
||||
assertFalse(desc.isArray());
|
||||
assertEquals(Integer.class, desc.getElementType());
|
||||
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor());
|
||||
assertEquals(Integer.class, desc.getElementType().getType());
|
||||
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementType());
|
||||
assertFalse(desc.isMap());
|
||||
}
|
||||
|
||||
|
@ -708,8 +594,8 @@ public class TypeDescriptorTests {
|
|||
assertEquals(0, desc.getAnnotations().length);
|
||||
assertTrue(desc.isCollection());
|
||||
assertFalse(desc.isArray());
|
||||
assertEquals(List.class, desc.getElementType());
|
||||
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor().getElementTypeDescriptor());
|
||||
assertEquals(List.class, desc.getElementType().getType());
|
||||
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementType().getElementType());
|
||||
assertFalse(desc.isMap());
|
||||
}
|
||||
|
||||
|
@ -725,8 +611,8 @@ public class TypeDescriptorTests {
|
|||
assertFalse(desc.isCollection());
|
||||
assertFalse(desc.isArray());
|
||||
assertTrue(desc.isMap());
|
||||
assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
|
||||
assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getType());
|
||||
assertEquals(String.class, desc.getMapKeyType().getType());
|
||||
assertEquals(Integer.class, desc.getMapValueType().getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -742,9 +628,9 @@ public class TypeDescriptorTests {
|
|||
assertFalse(desc.isCollection());
|
||||
assertFalse(desc.isArray());
|
||||
assertTrue(desc.isMap());
|
||||
assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
|
||||
assertEquals(String.class, desc.getMapValueTypeDescriptor().getMapKeyTypeDescriptor().getType());
|
||||
assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getMapValueTypeDescriptor().getType());
|
||||
assertEquals(String.class, desc.getMapKeyType().getType());
|
||||
assertEquals(String.class, desc.getMapValueType().getMapKeyType().getType());
|
||||
assertEquals(Integer.class, desc.getMapValueType().getMapValueType().getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.List;
|
|||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
@ -38,7 +39,12 @@ public class CollectionToCollectionConverterTests {
|
|||
list.add("37");
|
||||
TypeDescriptor sourceType = TypeDescriptor.forObject(list);
|
||||
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarListTarget"));
|
||||
assertFalse(conversionService.canConvert(sourceType, targetType));
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
try {
|
||||
conversionService.convert(list, sourceType, targetType);
|
||||
} catch (ConversionFailedException e) {
|
||||
assertTrue(e.getCause() instanceof ConverterNotFoundException);
|
||||
}
|
||||
conversionService.addConverterFactory(new StringToNumberConverterFactory());
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -169,7 +175,7 @@ public class CollectionToCollectionConverterTests {
|
|||
assertEquals(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources"))));
|
||||
}
|
||||
|
||||
@Test(expected=ConverterNotFoundException.class)
|
||||
@Test
|
||||
public void allNullsNotConvertible() throws Exception {
|
||||
List<Resource> resources = new ArrayList<Resource>();
|
||||
resources.add(null);
|
||||
|
@ -180,7 +186,7 @@ public class CollectionToCollectionConverterTests {
|
|||
|
||||
public List<String> allNullsNotConvertible;
|
||||
|
||||
@Test(expected=ConverterNotFoundException.class)
|
||||
@Test(expected=ConversionFailedException.class)
|
||||
public void nothingInCommon() throws Exception {
|
||||
List<Object> resources = new ArrayList<Object>();
|
||||
resources.add(new ClassPathResource("test"));
|
||||
|
|
|
@ -73,7 +73,7 @@ public class GenericConversionServiceTests {
|
|||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void convertNotNullSourceNullSourceTypeDescriptor() {
|
||||
conversionService.convert("3", TypeDescriptor.NULL, TypeDescriptor.valueOf(int.class));
|
||||
conversionService.convert("3", null, TypeDescriptor.valueOf(int.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -124,14 +124,15 @@ public class GenericConversionServiceTests {
|
|||
assertNull(conversionService.convert(null, Integer.class));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void convertNullTargetClass() {
|
||||
assertNull(conversionService.convert("3", (Class<?>) null));
|
||||
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), TypeDescriptor.NULL));
|
||||
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void convertNullTypeDescriptor() {
|
||||
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), TypeDescriptor.NULL));
|
||||
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), null));
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
|
@ -186,7 +187,12 @@ public class GenericConversionServiceTests {
|
|||
@Test
|
||||
public void genericConverterDelegatingBackToConversionServiceConverterNotFound() {
|
||||
conversionService.addConverter(new ObjectToArrayConverter(conversionService));
|
||||
assertFalse(conversionService.canConvert(String.class, Integer[].class));
|
||||
assertTrue(conversionService.canConvert(String.class, Integer[].class));
|
||||
try {
|
||||
conversionService.convert("3,4,5", Integer[].class);
|
||||
} catch (ConversionFailedException e) {
|
||||
assertTrue(e.getCause() instanceof ConverterNotFoundException);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -12,6 +12,8 @@ import java.util.Map;
|
|||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.convert.ConversionFailedException;
|
||||
import org.springframework.core.convert.ConverterNotFoundException;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
|
||||
public class MapToMapConverterTests {
|
||||
|
@ -30,7 +32,12 @@ public class MapToMapConverterTests {
|
|||
map.put("2", "37");
|
||||
TypeDescriptor sourceType = TypeDescriptor.forObject(map);
|
||||
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarMapTarget"));
|
||||
assertFalse(conversionService.canConvert(sourceType, targetType));
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
try {
|
||||
conversionService.convert(map, sourceType, targetType);
|
||||
} catch (ConversionFailedException e) {
|
||||
assertTrue(e.getCause() instanceof ConverterNotFoundException);
|
||||
}
|
||||
conversionService.addConverterFactory(new StringToNumberConverterFactory());
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -58,7 +65,19 @@ public class MapToMapConverterTests {
|
|||
map.put("2", "37");
|
||||
TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("notGenericMapSource"));
|
||||
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarMapTarget"));
|
||||
assertFalse(conversionService.canConvert(sourceType, targetType));
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
try {
|
||||
conversionService.convert(map, sourceType, targetType);
|
||||
} catch (ConversionFailedException e) {
|
||||
assertTrue(e.getCause() instanceof ConverterNotFoundException);
|
||||
}
|
||||
conversionService.addConverterFactory(new StringToNumberConverterFactory());
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Integer, Integer> result = (Map<Integer, Integer>) conversionService.convert(map, sourceType, targetType);
|
||||
assertFalse(map.equals(result));
|
||||
assertEquals((Integer) 9, result.get(1));
|
||||
assertEquals((Integer) 37, result.get(2));
|
||||
}
|
||||
|
||||
public Map notGenericMapSource;
|
||||
|
@ -70,7 +89,12 @@ public class MapToMapConverterTests {
|
|||
map.put("2", Arrays.asList("37", "23"));
|
||||
TypeDescriptor sourceType = TypeDescriptor.forObject(map);
|
||||
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget"));
|
||||
assertFalse(conversionService.canConvert(sourceType, targetType));
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
try {
|
||||
conversionService.convert(map, sourceType, targetType);
|
||||
} catch (ConversionFailedException e) {
|
||||
assertTrue(e.getCause() instanceof ConverterNotFoundException);
|
||||
}
|
||||
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
|
||||
conversionService.addConverterFactory(new StringToNumberConverterFactory());
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
|
@ -83,8 +107,6 @@ public class MapToMapConverterTests {
|
|||
|
||||
public Map<Integer, List<Integer>> collectionMapTarget;
|
||||
|
||||
public Map<String, List<String>> sourceCollectionMapTarget;
|
||||
|
||||
@Test
|
||||
public void collectionMapSourceTarget() throws Exception {
|
||||
Map<String, List<String>> map = new HashMap<String, List<String>>();
|
||||
|
@ -92,7 +114,12 @@ public class MapToMapConverterTests {
|
|||
map.put("2", Arrays.asList("37", "23"));
|
||||
TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("sourceCollectionMapTarget"));
|
||||
TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget"));
|
||||
assertFalse(conversionService.canConvert(sourceType, targetType));
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
try {
|
||||
conversionService.convert(map, sourceType, targetType);
|
||||
} catch (ConversionFailedException e) {
|
||||
assertTrue(e.getCause() instanceof ConverterNotFoundException);
|
||||
}
|
||||
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
|
||||
conversionService.addConverterFactory(new StringToNumberConverterFactory());
|
||||
assertTrue(conversionService.canConvert(sourceType, targetType));
|
||||
|
@ -103,6 +130,8 @@ public class MapToMapConverterTests {
|
|||
assertEquals(Arrays.asList(37, 23), result.get(2));
|
||||
}
|
||||
|
||||
public Map<String, List<String>> sourceCollectionMapTarget;
|
||||
|
||||
@Test
|
||||
public void collectionMapNotGenericTarget() throws Exception {
|
||||
Map<String, List<String>> map = new HashMap<String, List<String>>();
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue