restored TypeDescriptor getElementType, getMapKeyType, and getMapValueType compatibility; StringToCollection and Array Converters are now conditional and check targetElementType if present; TypeDesciptor#isAssignable no longer bothers with element type and map key/value types in checking assignability for consistency elsewhere; improved javadoc
This commit is contained in:
		
							parent
							
								
									a1a7c32052
								
							
						
					
					
						commit
						5e3a5202fb
					
				| 
						 | 
				
			
			@ -147,7 +147,7 @@ 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) {
 | 
			
		||||
				TypeDescriptor elementType = typeDescriptor.getElementType();
 | 
			
		||||
				TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();
 | 
			
		||||
				if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {
 | 
			
		||||
					convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -465,7 +465,7 @@ class TypeConverterDelegate {
 | 
			
		|||
			return original;
 | 
			
		||||
		}
 | 
			
		||||
		typeDescriptor = typeDescriptor.narrow(original);
 | 
			
		||||
		TypeDescriptor elementType = typeDescriptor.getElementType();
 | 
			
		||||
		TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();
 | 
			
		||||
		if (elementType == null && originalAllowed &&
 | 
			
		||||
				!this.propertyEditorRegistry.hasCustomEditorForElement(null, propertyName)) {
 | 
			
		||||
			return original;
 | 
			
		||||
| 
						 | 
				
			
			@ -512,7 +512,7 @@ class TypeConverterDelegate {
 | 
			
		|||
			Object element = it.next();
 | 
			
		||||
			String indexedPropertyName = buildIndexedPropertyName(propertyName, i);
 | 
			
		||||
			Object convertedElement = convertIfNecessary(
 | 
			
		||||
					indexedPropertyName, null, element, elementType != null ? elementType.getType() : null , typeDescriptor.getElementType());
 | 
			
		||||
					indexedPropertyName, null, element, elementType != null ? elementType.getType() : null , typeDescriptor.getElementTypeDescriptor());
 | 
			
		||||
			try {
 | 
			
		||||
				convertedCopy.add(convertedElement);
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -537,8 +537,8 @@ class TypeConverterDelegate {
 | 
			
		|||
			return original;
 | 
			
		||||
		}
 | 
			
		||||
		typeDescriptor = typeDescriptor.narrow(original);
 | 
			
		||||
		TypeDescriptor keyType = typeDescriptor.getMapKeyType();
 | 
			
		||||
		TypeDescriptor valueType = typeDescriptor.getMapValueType();
 | 
			
		||||
		TypeDescriptor keyType = typeDescriptor.getMapKeyTypeDescriptor();
 | 
			
		||||
		TypeDescriptor valueType = typeDescriptor.getMapValueTypeDescriptor();
 | 
			
		||||
		if (keyType == null && valueType == null && originalAllowed &&
 | 
			
		||||
				!this.propertyEditorRegistry.hasCustomEditorForElement(null, propertyName)) {
 | 
			
		||||
			return original;
 | 
			
		||||
| 
						 | 
				
			
			@ -585,8 +585,8 @@ class TypeConverterDelegate {
 | 
			
		|||
			Object key = entry.getKey();
 | 
			
		||||
			Object value = entry.getValue();
 | 
			
		||||
			String keyedPropertyName = buildKeyedPropertyName(propertyName, key);
 | 
			
		||||
			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());
 | 
			
		||||
			Object convertedKey = convertIfNecessary(keyedPropertyName, null, key, keyType != null ? keyType.getType() : null, typeDescriptor.getMapKeyTypeDescriptor());
 | 
			
		||||
			Object convertedValue = convertIfNecessary(keyedPropertyName, null, value, valueType!= null ? valueType.getType() : null, typeDescriptor.getMapValueTypeDescriptor());
 | 
			
		||||
			try {
 | 
			
		||||
				convertedCopy.put(convertedKey, convertedValue);
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ abstract class AbstractDescriptor {
 | 
			
		|||
		return type;		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public TypeDescriptor getElementType() {
 | 
			
		||||
	public TypeDescriptor getElementTypeDescriptor() {
 | 
			
		||||
		if (isCollection()) {
 | 
			
		||||
			Class<?> elementType = resolveCollectionElementType();
 | 
			
		||||
			return elementType != null ? new TypeDescriptor(nested(elementType, 0)) : null;
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +46,7 @@ abstract class AbstractDescriptor {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public TypeDescriptor getMapKeyType() {
 | 
			
		||||
	public TypeDescriptor getMapKeyTypeDescriptor() {
 | 
			
		||||
		if (isMap()) {
 | 
			
		||||
			Class<?> keyType = resolveMapKeyType();
 | 
			
		||||
			return keyType != null ? new TypeDescriptor(nested(keyType, 0)) : null;
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +55,7 @@ abstract class AbstractDescriptor {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public TypeDescriptor getMapValueType() {
 | 
			
		||||
	public TypeDescriptor getMapValueTypeDescriptor() {
 | 
			
		||||
		if (isMap()) {
 | 
			
		||||
			Class<?> valueType = resolveMapValueType();
 | 
			
		||||
			return valueType != null ? new TypeDescriptor(nested(valueType, 1)) : null;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,6 +61,7 @@ class FieldDescriptor extends AbstractDescriptor {
 | 
			
		|||
		super(type);
 | 
			
		||||
		this.field = field;
 | 
			
		||||
		this.nestingLevel = nestingLevel;
 | 
			
		||||
		// TODO typeIndex is not preserved at current nestingLevel is not preserved: see SPR-8394
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -60,11 +60,11 @@ public class TypeDescriptor {
 | 
			
		|||
 | 
			
		||||
	private final Class<?> type;
 | 
			
		||||
 | 
			
		||||
	private final TypeDescriptor elementType;
 | 
			
		||||
	private final TypeDescriptor elementTypeDescriptor;
 | 
			
		||||
 | 
			
		||||
	private final TypeDescriptor mapKeyType;
 | 
			
		||||
	private final TypeDescriptor mapKeyTypeDescriptor;
 | 
			
		||||
 | 
			
		||||
	private final TypeDescriptor mapValueType;
 | 
			
		||||
	private final TypeDescriptor mapValueTypeDescriptor;
 | 
			
		||||
 | 
			
		||||
	private final Annotation[] annotations;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -113,14 +113,14 @@ public class TypeDescriptor {
 | 
			
		|||
	 * For example, a List<String> could be converted to a List<EmailAddress> by converting to a targetType built with this method.
 | 
			
		||||
	 * The method call to construct such a TypeDescriptor would look something like: collection(List.class, TypeDescriptor.valueOf(EmailAddress.class));
 | 
			
		||||
	 * @param collectionType the collection type, which must implement {@link Collection}.
 | 
			
		||||
	 * @param elementType the collection's element type, used to convert collection elements
 | 
			
		||||
	 * @param elementTypeDescriptor a descriptor for the collection's element type, used to convert collection elements
 | 
			
		||||
	 * @return the collection type descriptor
 | 
			
		||||
	 */
 | 
			
		||||
	public static TypeDescriptor collection(Class<?> collectionType, TypeDescriptor elementType) {
 | 
			
		||||
	public static TypeDescriptor collection(Class<?> collectionType, TypeDescriptor elementTypeDescriptor) {
 | 
			
		||||
		if (!Collection.class.isAssignableFrom(collectionType)) {
 | 
			
		||||
			throw new IllegalArgumentException("collectionType must be a java.util.Collection");
 | 
			
		||||
		}
 | 
			
		||||
		return new TypeDescriptor(collectionType, elementType);
 | 
			
		||||
		return new TypeDescriptor(collectionType, elementTypeDescriptor);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -129,15 +129,15 @@ public class TypeDescriptor {
 | 
			
		|||
	 * For example, a Map<String, String> could be converted to a Map<Id, EmailAddress> by converting to a targetType built with this method:
 | 
			
		||||
	 * The method call to construct such a TypeDescriptor would look something like: map(Map.class, TypeDescriptor.valueOf(Id.class), TypeDescriptor.valueOf(EmailAddress.class));
 | 
			
		||||
	 * @param mapType the map type, which must implement {@link Map}.
 | 
			
		||||
	 * @param keyType the map's key type, used to convert map keys
 | 
			
		||||
	 * @param valueType the map's value type, used to convert map values
 | 
			
		||||
	 * @param keyTypeDescriptor a descriptor for the map's key type, used to convert map keys
 | 
			
		||||
	 * @param valueTypeDescriptor the map's value type, used to convert map values
 | 
			
		||||
	 * @return the map type descriptor
 | 
			
		||||
	 */
 | 
			
		||||
	public static TypeDescriptor map(Class<?> mapType, TypeDescriptor keyType, TypeDescriptor valueType) {
 | 
			
		||||
	public static TypeDescriptor map(Class<?> mapType, TypeDescriptor keyTypeDescriptor, TypeDescriptor valueTypeDescriptor) {
 | 
			
		||||
		if (!Map.class.isAssignableFrom(mapType)) {
 | 
			
		||||
			throw new IllegalArgumentException("mapType must be a java.util.Map");
 | 
			
		||||
		}
 | 
			
		||||
		return new TypeDescriptor(mapType, keyType, valueType);
 | 
			
		||||
		return new TypeDescriptor(mapType, keyTypeDescriptor, valueTypeDescriptor);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -151,9 +151,13 @@ public class TypeDescriptor {
 | 
			
		|||
	 * @param methodParameter the method parameter with a nestingLevel of 1
 | 
			
		||||
	 * @param nestingLevel the nesting level of the collection/array element or map key/value declaration within the method parameter.
 | 
			
		||||
	 * @return the nested type descriptor at the specified nesting level, or null if it could not be obtained.
 | 
			
		||||
	 * @throws IllegalArgumentException if the nesting level of the input {@link MethodParameter} argument is not 1.
 | 
			
		||||
	 * @throws IllegalArgumentException if the types up to the specified nesting level are not of collection, array, or map types.
 | 
			
		||||
	 */
 | 
			
		||||
	public static TypeDescriptor nested(MethodParameter methodParameter, int nestingLevel) {
 | 
			
		||||
		if (methodParameter.getNestingLevel() != 1) {
 | 
			
		||||
			throw new IllegalArgumentException("methodParameter nesting level must be 1: use the nestingLevel parameter to specify the desired nestingLevel for nested type traversal");
 | 
			
		||||
		}
 | 
			
		||||
		return nested(new ParameterDescriptor(methodParameter), nestingLevel);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -236,7 +240,7 @@ public class TypeDescriptor {
 | 
			
		|||
		if (value == null) {
 | 
			
		||||
			return this;
 | 
			
		||||
		}
 | 
			
		||||
		return new TypeDescriptor(value.getClass(), elementType, mapKeyType, mapValueType, annotations);
 | 
			
		||||
		return new TypeDescriptor(value.getClass(), elementTypeDescriptor, mapKeyTypeDescriptor, mapValueTypeDescriptor, annotations);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -275,24 +279,13 @@ public class TypeDescriptor {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns true if an object of this type can be assigned to a reference of given targetType.
 | 
			
		||||
	 * @param targetType the target type
 | 
			
		||||
	 * @return true if this type is assignable to the target
 | 
			
		||||
	 * Returns true if an object of this type can be assigned to a reference of the given type.
 | 
			
		||||
	 * @param typeDescriptor the descriptor for the target type
 | 
			
		||||
	 * @return true if this type is assignable to the type represented by the provided type descriptor.
 | 
			
		||||
	 * @see #getObjectType()
 | 
			
		||||
	 */
 | 
			
		||||
	public boolean isAssignableTo(TypeDescriptor targetType) {
 | 
			
		||||
		boolean typesAssignable = targetType.getObjectType().isAssignableFrom(getObjectType());
 | 
			
		||||
		if (!typesAssignable) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		if (isArray() && targetType.isArray()) {
 | 
			
		||||
			return getElementType().isAssignableTo(targetType.getElementType());
 | 
			
		||||
		}
 | 
			
		||||
		if (isCollection() && targetType.isCollection()) {
 | 
			
		||||
			return collectionElementsAssignable(targetType.getElementType());
 | 
			
		||||
		} else if (isMap() && targetType.isMap()) {
 | 
			
		||||
			return mapKeysAssignable(targetType.getMapKeyType()) && mapValuesAssignable(targetType.getMapValueType());
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
	public boolean isAssignableTo(TypeDescriptor typeDescriptor) {
 | 
			
		||||
		return typeDescriptor.getObjectType().isAssignableFrom(getObjectType());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// indexable type descriptor operations
 | 
			
		||||
| 
						 | 
				
			
			@ -318,14 +311,14 @@ public class TypeDescriptor {
 | 
			
		|||
	 * @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 TypeDescriptor getElementType() {
 | 
			
		||||
	public TypeDescriptor getElementTypeDescriptor() {
 | 
			
		||||
		assertCollectionOrArray();
 | 
			
		||||
		return this.elementType;
 | 
			
		||||
		return this.elementTypeDescriptor;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * If this type is a {@link Collection} or an Array, creates a elementType descriptor from the provided collection or array element.
 | 
			
		||||
	 * Narrows the {@link #getElementType() elementType} property to the class of the provided collection or array element.
 | 
			
		||||
	 * If this type is a {@link Collection} or an Array, creates a element TypeDescriptor from the provided collection or array element.
 | 
			
		||||
	 * Narrows the {@link #getElementTypeDescriptor() elementType} property to the class of the provided collection or array element.
 | 
			
		||||
	 * For example, if this describes a java.util.List<java.lang.Number< and the element argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer.
 | 
			
		||||
	 * If this describes a java.util.List<?> and the element argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer as well.
 | 
			
		||||
	 * Annotation and nested type context will be preserved in the narrowed TypeDescriptor that is returned. 
 | 
			
		||||
| 
						 | 
				
			
			@ -334,13 +327,8 @@ public class TypeDescriptor {
 | 
			
		|||
	 * @throws IllegalStateException if this type is not a java.util.Collection or Array type
 | 
			
		||||
	 * @see #narrow(Object)
 | 
			
		||||
	 */
 | 
			
		||||
	public TypeDescriptor elementType(Object element) {
 | 
			
		||||
		assertCollectionOrArray();
 | 
			
		||||
		if (elementType != null) {
 | 
			
		||||
			return elementType.narrow(element);
 | 
			
		||||
		} else {
 | 
			
		||||
			return element != null ? new TypeDescriptor(element.getClass(), null, null, null, annotations) : null;
 | 
			
		||||
		}
 | 
			
		||||
	public TypeDescriptor elementTypeDescriptor(Object element) {
 | 
			
		||||
		return narrow(element, getElementTypeDescriptor());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// map type descriptor operations
 | 
			
		||||
| 
						 | 
				
			
			@ -358,14 +346,14 @@ public class TypeDescriptor {
 | 
			
		|||
	 * @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 TypeDescriptor getMapKeyType() {
 | 
			
		||||
	public TypeDescriptor getMapKeyTypeDescriptor() {
 | 
			
		||||
		assertMap();
 | 
			
		||||
		return this.mapKeyType;
 | 
			
		||||
		return this.mapKeyTypeDescriptor;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * If this type is a {@link Map}, creates a mapKeyType descriptor from the provided map key.
 | 
			
		||||
	 * Narrows the {@link #getMapKeyType() mapKeyType} property to the class of the provided map key.
 | 
			
		||||
	 * If this type is a {@link Map}, creates a mapKey {@link TypeDescriptor} from the provided map key.
 | 
			
		||||
	 * Narrows the {@link #getMapKeyTypeDescriptor() mapKeyType} property to the class of the provided map key.
 | 
			
		||||
	 * For example, if this describes a java.util.Map<java.lang.Number, java.lang.String< and the key argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer.
 | 
			
		||||
	 * If this describes a java.util.Map<?, ?> and the key argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer as well.
 | 
			
		||||
	 * Annotation and nested type context will be preserved in the narrowed TypeDescriptor that is returned. 
 | 
			
		||||
| 
						 | 
				
			
			@ -374,13 +362,8 @@ public class TypeDescriptor {
 | 
			
		|||
	 * @throws IllegalStateException if this type is not a java.util.Map.
 | 
			
		||||
	 * @see #narrow(Object)
 | 
			
		||||
	 */
 | 
			
		||||
	public TypeDescriptor mapKeyType(Object mapKey) {
 | 
			
		||||
		assertMap();
 | 
			
		||||
		if (mapKeyType != null) {
 | 
			
		||||
			return mapKeyType.narrow(mapKey);
 | 
			
		||||
		} else {
 | 
			
		||||
			return mapKey != null ? new TypeDescriptor(mapKey.getClass(), null, null, null, annotations) : null;
 | 
			
		||||
		}
 | 
			
		||||
	public TypeDescriptor mapKeyTypeDescriptor(Object mapKey) {
 | 
			
		||||
		return narrow(mapKey, getMapKeyTypeDescriptor());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -389,14 +372,14 @@ public class TypeDescriptor {
 | 
			
		|||
	 * @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 getMapValueType() {
 | 
			
		||||
	public TypeDescriptor getMapValueTypeDescriptor() {
 | 
			
		||||
		assertMap();
 | 
			
		||||
		return this.mapValueType;
 | 
			
		||||
		return this.mapValueTypeDescriptor;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * If this type is a {@link Map}, creates a mapValueType descriptor from the provided map value.
 | 
			
		||||
	 * Narrows the {@link #getMapValueType() mapValueType} property to the class of the provided map value.
 | 
			
		||||
	 * If this type is a {@link Map}, creates a mapValue {@link TypeDescriptor} from the provided map value.
 | 
			
		||||
	 * Narrows the {@link #getMapValueTypeDescriptor() mapValueType} property to the class of the provided map value.
 | 
			
		||||
	 * For example, if this describes a java.util.Map<java.lang.String, java.lang.Number< and the value argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer.
 | 
			
		||||
	 * If this describes a java.util.Map<?, ?> and the value argument is a java.lang.Integer, the returned TypeDescriptor will be java.lang.Integer as well.
 | 
			
		||||
	 * Annotation and nested type context will be preserved in the narrowed TypeDescriptor that is returned. 
 | 
			
		||||
| 
						 | 
				
			
			@ -404,13 +387,8 @@ public class TypeDescriptor {
 | 
			
		|||
	 * @return the map value type descriptor
 | 
			
		||||
	 * @throws IllegalStateException if this type is not a java.util.Map. 
 | 
			
		||||
	 */
 | 
			
		||||
	public TypeDescriptor mapValueType(Object mapValue) {
 | 
			
		||||
		assertMap();
 | 
			
		||||
		if (mapValueType != null) {
 | 
			
		||||
			return mapValueType.narrow(mapValue);
 | 
			
		||||
		} else {
 | 
			
		||||
			return mapValue != null ? new TypeDescriptor(mapValue.getClass(), null, null, null, annotations) : null;
 | 
			
		||||
		}
 | 
			
		||||
	public TypeDescriptor mapValueTypeDescriptor(Object mapValue) {
 | 
			
		||||
		return narrow(mapValue, getMapValueTypeDescriptor());		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// extending Object
 | 
			
		||||
| 
						 | 
				
			
			@ -423,16 +401,14 @@ public class TypeDescriptor {
 | 
			
		|||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		TypeDescriptor other = (TypeDescriptor) obj;
 | 
			
		||||
		boolean annotatedTypeEquals = ObjectUtils.nullSafeEquals(getType(), other.getType())
 | 
			
		||||
				&& ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations());
 | 
			
		||||
		boolean annotatedTypeEquals = ObjectUtils.nullSafeEquals(getType(), other.getType()) && ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations());
 | 
			
		||||
		if (!annotatedTypeEquals) {
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		if (isCollection() || isArray()) {
 | 
			
		||||
			return ObjectUtils.nullSafeEquals(getElementType(), other.getElementType());
 | 
			
		||||
			return ObjectUtils.nullSafeEquals(getElementTypeDescriptor(), other.getElementTypeDescriptor());
 | 
			
		||||
		} else if (isMap()) {
 | 
			
		||||
			return ObjectUtils.nullSafeEquals(getMapKeyType(), other.getMapKeyType())
 | 
			
		||||
					&& ObjectUtils.nullSafeEquals(getMapValueType(), other.getMapValueType());
 | 
			
		||||
			return ObjectUtils.nullSafeEquals(getMapKeyTypeDescriptor(), other.getMapKeyTypeDescriptor()) && ObjectUtils.nullSafeEquals(getMapValueTypeDescriptor(), other.getMapValueTypeDescriptor());
 | 
			
		||||
		} else {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -450,21 +426,53 @@ public class TypeDescriptor {
 | 
			
		|||
		}
 | 
			
		||||
		builder.append(ClassUtils.getQualifiedName(getType()));
 | 
			
		||||
		if (isMap()) {
 | 
			
		||||
			builder.append("<").append(wildcard(getMapKeyType()));
 | 
			
		||||
			builder.append(", ").append(wildcard(getMapValueType())).append(">");
 | 
			
		||||
			builder.append("<").append(wildcard(getMapKeyTypeDescriptor()));
 | 
			
		||||
			builder.append(", ").append(wildcard(getMapValueTypeDescriptor())).append(">");
 | 
			
		||||
		} else if (isCollection()) {
 | 
			
		||||
			builder.append("<").append(wildcard(getElementType())).append(">");
 | 
			
		||||
			builder.append("<").append(wildcard(getElementTypeDescriptor())).append(">");
 | 
			
		||||
		}
 | 
			
		||||
		return builder.toString();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// helper public class
 | 
			
		||||
	// deprecations in Spring 3.1
 | 
			
		||||
	
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the value of {@link TypeDescriptor#getType() getType()} for the {@link #getElementTypeDescriptor() elementTypeDescriptor}.
 | 
			
		||||
	 * @deprecated in Spring 3.1 in favor of {@link #getElementTypeDescriptor()}.
 | 
			
		||||
	 * @throws IllegalStateException if this type is not a java.util.Collection or Array type
 | 
			
		||||
	 */
 | 
			
		||||
	@Deprecated
 | 
			
		||||
	public Class<?> getElementType() {
 | 
			
		||||
		return getElementTypeDescriptor().getType();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the value of {@link TypeDescriptor#getType() getType()} for the {@link #getMapKeyTypeDescriptor() mapKeyTypeDescriptor}.
 | 
			
		||||
	 * @deprecated in Spring 3.1 in favor of {@link #getMapKeyTypeDescriptor()}.
 | 
			
		||||
	 * @throws IllegalStateException if this type is not a java.util.Map.
 | 
			
		||||
	 */
 | 
			
		||||
	@Deprecated
 | 
			
		||||
	public Class<?> getMapKeyType() {
 | 
			
		||||
		return getMapKeyTypeDescriptor().getType();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * Returns the value of {@link TypeDescriptor#getType() getType()} for the {@link #getMapValueTypeDescriptor() mapValueTypeDescriptor}.
 | 
			
		||||
	 * @deprecated in Spring 3.1 in favor of {@link #getMapValueTypeDescriptor()}.
 | 
			
		||||
	 * @throws IllegalStateException if this type is not a java.util.Map.
 | 
			
		||||
	 */
 | 
			
		||||
	@Deprecated
 | 
			
		||||
	public Class<?> getMapValueType() {
 | 
			
		||||
		return getMapValueTypeDescriptor().getType();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// package private helpers
 | 
			
		||||
 | 
			
		||||
	TypeDescriptor(AbstractDescriptor descriptor) {
 | 
			
		||||
		this.type = descriptor.getType();
 | 
			
		||||
		this.elementType = descriptor.getElementType();
 | 
			
		||||
		this.mapKeyType = descriptor.getMapKeyType();
 | 
			
		||||
		this.mapValueType = descriptor.getMapValueType();
 | 
			
		||||
		this.elementTypeDescriptor = descriptor.getElementTypeDescriptor();
 | 
			
		||||
		this.mapKeyTypeDescriptor = descriptor.getMapKeyTypeDescriptor();
 | 
			
		||||
		this.mapValueTypeDescriptor = descriptor.getMapValueTypeDescriptor();
 | 
			
		||||
		this.annotations = descriptor.getAnnotations();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -478,20 +486,20 @@ public class TypeDescriptor {
 | 
			
		|||
		this(new ClassDescriptor(type));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private TypeDescriptor(Class<?> collectionType, TypeDescriptor elementType) {
 | 
			
		||||
		this(collectionType, elementType, null, null, EMPTY_ANNOTATION_ARRAY);
 | 
			
		||||
	private TypeDescriptor(Class<?> collectionType, TypeDescriptor elementTypeDescriptor) {
 | 
			
		||||
		this(collectionType, elementTypeDescriptor, null, null, EMPTY_ANNOTATION_ARRAY);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private TypeDescriptor(Class<?> mapType, TypeDescriptor keyType, TypeDescriptor valueType) {
 | 
			
		||||
		this(mapType, null, keyType, valueType, EMPTY_ANNOTATION_ARRAY);
 | 
			
		||||
	private TypeDescriptor(Class<?> mapType, TypeDescriptor keyTypeDescriptor, TypeDescriptor valueTypeDescriptor) {
 | 
			
		||||
		this(mapType, null, keyTypeDescriptor, valueTypeDescriptor, EMPTY_ANNOTATION_ARRAY);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private TypeDescriptor(Class<?> type, TypeDescriptor elementType, TypeDescriptor mapKeyType,
 | 
			
		||||
			TypeDescriptor mapValueType, Annotation[] annotations) {
 | 
			
		||||
	private TypeDescriptor(Class<?> type, TypeDescriptor elementTypeDescriptor, TypeDescriptor mapKeyTypeDescriptor,
 | 
			
		||||
			TypeDescriptor mapValueTypeDescriptor, Annotation[] annotations) {
 | 
			
		||||
		this.type = type;
 | 
			
		||||
		this.elementType = elementType;
 | 
			
		||||
		this.mapKeyType = mapKeyType;
 | 
			
		||||
		this.mapValueType = mapValueType;
 | 
			
		||||
		this.elementTypeDescriptor = elementTypeDescriptor;
 | 
			
		||||
		this.mapKeyTypeDescriptor = mapKeyTypeDescriptor;
 | 
			
		||||
		this.mapValueTypeDescriptor = mapValueTypeDescriptor;
 | 
			
		||||
		this.annotations = annotations;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -507,39 +515,6 @@ public class TypeDescriptor {
 | 
			
		|||
 | 
			
		||||
	// 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 void assertCollectionOrArray() {
 | 
			
		||||
		if (!isCollection() && !isArray()) {
 | 
			
		||||
			throw new IllegalStateException("Not a java.util.Collection or Array");
 | 
			
		||||
| 
						 | 
				
			
			@ -552,8 +527,16 @@ public class TypeDescriptor {
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	private String wildcard(TypeDescriptor nestedType) {
 | 
			
		||||
		return nestedType != null ? nestedType.toString() : "?";
 | 
			
		||||
	private TypeDescriptor narrow(Object value, TypeDescriptor typeDescriptor) {
 | 
			
		||||
		if (typeDescriptor != null) {
 | 
			
		||||
			return typeDescriptor.narrow(value);
 | 
			
		||||
		} else {
 | 
			
		||||
			return value != null ? new TypeDescriptor(value.getClass(), null, null, null, annotations) : null;
 | 
			
		||||
		}		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	private String wildcard(TypeDescriptor typeDescriptor) {
 | 
			
		||||
		return typeDescriptor != null ? typeDescriptor.toString() : "?";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +55,7 @@ final class ArrayToCollectionConverter implements GenericConverter {
 | 
			
		|||
		}		
 | 
			
		||||
		int length = Array.getLength(source);
 | 
			
		||||
		Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), length);
 | 
			
		||||
		if (targetType.getElementType() == null) {
 | 
			
		||||
		if (targetType.getElementTypeDescriptor() == null) {
 | 
			
		||||
			for (int i = 0; i < length; i++) {
 | 
			
		||||
				Object sourceElement = Array.get(source, i);
 | 
			
		||||
				target.add(sourceElement);
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +63,7 @@ final class ArrayToCollectionConverter implements GenericConverter {
 | 
			
		|||
		} else {
 | 
			
		||||
			for (int i = 0; i < length; i++) {
 | 
			
		||||
				Object sourceElement = Array.get(source, i);
 | 
			
		||||
				Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType.getElementType());
 | 
			
		||||
				Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor());
 | 
			
		||||
				target.add(targetElement);
 | 
			
		||||
			}
 | 
			
		||||
		}		
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,10 +53,10 @@ final class CollectionToArrayConverter implements GenericConverter {
 | 
			
		|||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
		Collection<?> sourceCollection = (Collection<?>) source;
 | 
			
		||||
		Object array = Array.newInstance(targetType.getElementType().getType(), sourceCollection.size());
 | 
			
		||||
		Object array = Array.newInstance(targetType.getElementTypeDescriptor().getType(), sourceCollection.size());
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		for (Object sourceElement : sourceCollection) {
 | 
			
		||||
			Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType.getElementType());
 | 
			
		||||
			Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor());
 | 
			
		||||
			Array.set(array, i++, targetElement);
 | 
			
		||||
		}
 | 
			
		||||
		return array;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,13 +55,13 @@ final class CollectionToCollectionConverter implements GenericConverter {
 | 
			
		|||
		}
 | 
			
		||||
		Collection<?> sourceCollection = (Collection<?>) source;
 | 
			
		||||
		Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size());
 | 
			
		||||
		if (targetType.getElementType() == null) {
 | 
			
		||||
		if (targetType.getElementTypeDescriptor() == null) {
 | 
			
		||||
			for (Object element : sourceCollection) {
 | 
			
		||||
				target.add(element);
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			for (Object sourceElement : sourceCollection) {
 | 
			
		||||
				Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType.getElementType());
 | 
			
		||||
				Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementTypeDescriptor(sourceElement), targetType.getElementTypeDescriptor());
 | 
			
		||||
				target.add(targetElement);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,7 @@ final class CollectionToObjectConverter implements GenericConverter {
 | 
			
		|||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
		Object firstElement = sourceCollection.iterator().next();
 | 
			
		||||
		return this.conversionService.convert(firstElement, sourceType.elementType(firstElement), targetType);
 | 
			
		||||
		return this.conversionService.convert(firstElement, sourceType.elementTypeDescriptor(firstElement), targetType);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ final class CollectionToStringConverter implements GenericConverter {
 | 
			
		|||
			if (i > 0) {
 | 
			
		||||
				sb.append(DELIMITER);
 | 
			
		||||
			}
 | 
			
		||||
			Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementType(sourceElement), targetType);
 | 
			
		||||
			Object targetElement = this.conversionService.convert(sourceElement, sourceType.elementTypeDescriptor(sourceElement), targetType);
 | 
			
		||||
			sb.append(targetElement);
 | 
			
		||||
			i++;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,8 +58,8 @@ final class MapToMapConverter implements GenericConverter {
 | 
			
		|||
		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());
 | 
			
		||||
			Object targetKey = convertKey(sourceKey, sourceType, targetType.getMapKeyTypeDescriptor());
 | 
			
		||||
			Object targetValue = convertValue(sourceValue, sourceType, targetType.getMapValueTypeDescriptor());
 | 
			
		||||
			targetMap.put(targetKey, targetValue);
 | 
			
		||||
		}
 | 
			
		||||
		return targetMap;
 | 
			
		||||
| 
						 | 
				
			
			@ -71,14 +71,14 @@ final class MapToMapConverter implements GenericConverter {
 | 
			
		|||
		if (targetType == null) {
 | 
			
		||||
			return sourceKey;
 | 
			
		||||
		}
 | 
			
		||||
		return this.conversionService.convert(sourceKey, sourceType.mapKeyType(sourceKey), targetType);
 | 
			
		||||
		return this.conversionService.convert(sourceKey, sourceType.mapKeyTypeDescriptor(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);
 | 
			
		||||
		return this.conversionService.convert(sourceValue, sourceType.mapValueTypeDescriptor(sourceValue), targetType);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -47,8 +47,8 @@ final class ObjectToArrayConverter implements GenericConverter {
 | 
			
		|||
		if (source == null) {
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
		Object target = Array.newInstance(targetType.getElementType().getType(), 1);
 | 
			
		||||
		Object targetElement = this.conversionService.convert(source, sourceType, targetType.getElementType());
 | 
			
		||||
		Object target = Array.newInstance(targetType.getElementTypeDescriptor().getType(), 1);
 | 
			
		||||
		Object targetElement = this.conversionService.convert(source, sourceType, targetType.getElementTypeDescriptor());
 | 
			
		||||
		Array.set(target, 0, targetElement);
 | 
			
		||||
		return target;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,10 +51,10 @@ final class ObjectToCollectionConverter implements GenericConverter {
 | 
			
		|||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
		Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), 1);
 | 
			
		||||
		if (targetType.getElementType() == null || targetType.getElementType().isCollection()) {
 | 
			
		||||
		if (targetType.getElementTypeDescriptor() == null || targetType.getElementTypeDescriptor().isCollection()) {
 | 
			
		||||
			target.add(source);			
 | 
			
		||||
		} else {
 | 
			
		||||
			Object singleElement = this.conversionService.convert(source, sourceType, targetType.getElementType());
 | 
			
		||||
			Object singleElement = this.conversionService.convert(source, sourceType, targetType.getElementTypeDescriptor());
 | 
			
		||||
			target.add(singleElement);
 | 
			
		||||
		}
 | 
			
		||||
		return target;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ final class StringToArrayConverter implements ConditionalGenericConverter {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
 | 
			
		||||
		return this.conversionService.canConvert(sourceType, targetType.getElementType());
 | 
			
		||||
		return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
 | 
			
		||||
| 
						 | 
				
			
			@ -54,10 +54,10 @@ final class StringToArrayConverter implements ConditionalGenericConverter {
 | 
			
		|||
		}		
 | 
			
		||||
		String string = (String) source;
 | 
			
		||||
		String[] fields = StringUtils.commaDelimitedListToStringArray(string);
 | 
			
		||||
		Object target = Array.newInstance(targetType.getElementType().getType(), fields.length);
 | 
			
		||||
		Object target = Array.newInstance(targetType.getElementTypeDescriptor().getType(), fields.length);
 | 
			
		||||
		for (int i = 0; i < fields.length; i++) {
 | 
			
		||||
			String sourceElement = fields[i];
 | 
			
		||||
			Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementType());
 | 
			
		||||
			Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementTypeDescriptor());
 | 
			
		||||
			Array.set(target, i, targetElement);
 | 
			
		||||
		}
 | 
			
		||||
		return target;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,8 +46,8 @@ final class StringToCollectionConverter implements ConditionalGenericConverter {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
 | 
			
		||||
		if (targetType.getElementType() != null) {
 | 
			
		||||
			return this.conversionService.canConvert(sourceType, targetType.getElementType());
 | 
			
		||||
		if (targetType.getElementTypeDescriptor() != null) {
 | 
			
		||||
			return this.conversionService.canConvert(sourceType, targetType.getElementTypeDescriptor());
 | 
			
		||||
		} else {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -61,13 +61,13 @@ final class StringToCollectionConverter implements ConditionalGenericConverter {
 | 
			
		|||
		String string = (String) source;
 | 
			
		||||
		String[] fields = StringUtils.commaDelimitedListToStringArray(string);
 | 
			
		||||
		Collection<Object> target = CollectionFactory.createCollection(targetType.getType(), fields.length);
 | 
			
		||||
		if (targetType.getElementType() == null) {
 | 
			
		||||
		if (targetType.getElementTypeDescriptor() == null) {
 | 
			
		||||
			for (String field : fields) {
 | 
			
		||||
				target.add(field.trim());
 | 
			
		||||
			}						
 | 
			
		||||
		} else {
 | 
			
		||||
			for (String field : fields) {
 | 
			
		||||
				Object targetElement = this.conversionService.convert(field.trim(), sourceType, targetType.getElementType());
 | 
			
		||||
				Object targetElement = this.conversionService.convert(field.trim(), sourceType, targetType.getElementTypeDescriptor());
 | 
			
		||||
				target.add(targetElement);
 | 
			
		||||
			}			
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -106,12 +106,12 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertEquals(0, desc.getAnnotations().length);
 | 
			
		||||
		assertTrue(desc.isCollection());
 | 
			
		||||
		assertFalse(desc.isArray());
 | 
			
		||||
		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());
 | 
			
		||||
		assertEquals(List.class, desc.getElementTypeDescriptor().getType());
 | 
			
		||||
		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());
 | 
			
		||||
		assertFalse(desc.isMap());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +131,7 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertEquals(0, desc.getAnnotations().length);
 | 
			
		||||
		assertTrue(desc.isCollection());
 | 
			
		||||
		assertFalse(desc.isArray());		
 | 
			
		||||
		assertNull(desc.getElementType());
 | 
			
		||||
		assertNull(desc.getElementTypeDescriptor());
 | 
			
		||||
		assertFalse(desc.isMap());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -151,8 +151,8 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertEquals(0, desc.getAnnotations().length);
 | 
			
		||||
		assertFalse(desc.isCollection());
 | 
			
		||||
		assertTrue(desc.isArray());
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementType().getType());
 | 
			
		||||
		assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor());
 | 
			
		||||
		assertFalse(desc.isMap());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -173,11 +173,11 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertFalse(desc.isCollection());
 | 
			
		||||
		assertFalse(desc.isArray());
 | 
			
		||||
		assertTrue(desc.isMap());
 | 
			
		||||
		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());
 | 
			
		||||
		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());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public void testParameterMap(Map<Integer, List<String>> map) {
 | 
			
		||||
| 
						 | 
				
			
			@ -206,8 +206,8 @@ public class TypeDescriptorTests {
 | 
			
		|||
	public void propertyComplex() throws Exception {
 | 
			
		||||
		Property property = new Property(getClass(), getClass().getMethod("getComplexProperty", null), getClass().getMethod("setComplexProperty", Map.class));		
 | 
			
		||||
		TypeDescriptor desc = new TypeDescriptor(property);
 | 
			
		||||
		assertEquals(String.class, desc.getMapKeyType().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapValueType().getElementType().getElementType().getType());
 | 
			
		||||
		assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public Map<String, List<List<Integer>>> getComplexProperty() {
 | 
			
		||||
| 
						 | 
				
			
			@ -232,7 +232,7 @@ public class TypeDescriptorTests {
 | 
			
		|||
		Property property = new Property(getClass(), genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));		
 | 
			
		||||
		TypeDescriptor desc = new TypeDescriptor(property);
 | 
			
		||||
		assertEquals(List.class, desc.getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementType().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementTypeDescriptor().getType());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public interface GenericType<T> {
 | 
			
		||||
| 
						 | 
				
			
			@ -276,7 +276,7 @@ public class TypeDescriptorTests {
 | 
			
		|||
		Property property = new Property(genericBean.getClass(), genericBean.getClass().getMethod("getListProperty", null), genericBean.getClass().getMethod("setListProperty", List.class));		
 | 
			
		||||
		TypeDescriptor desc = new TypeDescriptor(property);
 | 
			
		||||
		assertEquals(List.class, desc.getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementType().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -308,8 +308,8 @@ public class TypeDescriptorTests {
 | 
			
		|||
		Property property = new Property(getClass(), getClass().getMethod("getProperty", null), getClass().getMethod("setProperty", Map.class));		
 | 
			
		||||
		TypeDescriptor desc = new TypeDescriptor(property);
 | 
			
		||||
		assertEquals(Map.class, desc.getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapKeyType().getElementType().getType());
 | 
			
		||||
		assertEquals(Long.class, desc.getMapValueType().getElementType().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
		assertNotNull(desc.getAnnotation(MethodAnnotation1.class));
 | 
			
		||||
		assertNotNull(desc.getAnnotation(MethodAnnotation2.class));
 | 
			
		||||
		assertNotNull(desc.getAnnotation(MethodAnnotation3.class));
 | 
			
		||||
| 
						 | 
				
			
			@ -364,7 +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().getType());
 | 
			
		||||
		assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertEquals("java.util.List<java.lang.String>", typeDescriptor.toString());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -373,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().getType());
 | 
			
		||||
		assertEquals(String.class, typeDescriptor.getElementType().getElementType().getType());
 | 
			
		||||
		assertEquals(List.class, typeDescriptor.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
		assertEquals("java.util.List<java.util.List<java.lang.String>>", typeDescriptor.toString());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -383,8 +383,8 @@ public class TypeDescriptorTests {
 | 
			
		|||
		TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfUnknown"));
 | 
			
		||||
		assertFalse(typeDescriptor.isArray());
 | 
			
		||||
		assertEquals(List.class, typeDescriptor.getType());
 | 
			
		||||
		assertEquals(List.class, typeDescriptor.getElementType().getType());
 | 
			
		||||
		assertNull(typeDescriptor.getElementType().getElementType());
 | 
			
		||||
		assertEquals(List.class, typeDescriptor.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertNull(typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor());
 | 
			
		||||
		assertEquals("java.util.List<java.util.List<?>>", typeDescriptor.toString());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -392,7 +392,7 @@ public class TypeDescriptorTests {
 | 
			
		|||
	public void fieldArray() throws Exception {
 | 
			
		||||
		TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("intArray"));
 | 
			
		||||
		assertTrue(typeDescriptor.isArray());
 | 
			
		||||
		assertEquals(Integer.TYPE,typeDescriptor.getElementType().getType());
 | 
			
		||||
		assertEquals(Integer.TYPE,typeDescriptor.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertEquals("int[]",typeDescriptor.toString());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -401,8 +401,8 @@ public class TypeDescriptorTests {
 | 
			
		|||
	public void fieldComplexTypeDescriptor() throws Exception {
 | 
			
		||||
		TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("arrayOfListOfString"));
 | 
			
		||||
		assertTrue(typeDescriptor.isArray());
 | 
			
		||||
		assertEquals(List.class,typeDescriptor.getElementType());
 | 
			
		||||
		assertEquals(String.class, typeDescriptor.getElementType().getElementType());
 | 
			
		||||
		assertEquals(List.class,typeDescriptor.getElementTypeDescriptor());
 | 
			
		||||
		assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor());
 | 
			
		||||
		assertEquals("java.util.List[]",typeDescriptor.toString());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -410,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().getType());
 | 
			
		||||
		assertEquals(List.class, typeDescriptor.getMapValueType().getType());
 | 
			
		||||
		assertEquals(Integer.class, typeDescriptor.getMapValueType().getElementType().getType());
 | 
			
		||||
		assertEquals(String.class,typeDescriptor.getMapKeyTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(List.class, typeDescriptor.getMapValueTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(Integer.class, typeDescriptor.getMapValueTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
		assertEquals("java.util.Map<java.lang.String, java.util.List<java.lang.Integer>>", typeDescriptor.toString());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -422,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.getMapKeyType().getElementType());
 | 
			
		||||
		assertEquals(Long.class, desc.getMapValueType().getElementType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor());
 | 
			
		||||
		assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public Map<List<Integer>, List<Long>> fieldMap;
 | 
			
		||||
| 
						 | 
				
			
			@ -472,7 +472,7 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertTrue(typeDescriptor.isArray());
 | 
			
		||||
		assertFalse(typeDescriptor.isCollection());
 | 
			
		||||
		assertFalse(typeDescriptor.isMap());
 | 
			
		||||
		assertEquals(Integer.TYPE, typeDescriptor.getElementType().getType());
 | 
			
		||||
		assertEquals(Integer.TYPE, typeDescriptor.getElementTypeDescriptor().getType());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -481,7 +481,7 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertTrue(typeDescriptor.isCollection());
 | 
			
		||||
		assertFalse(typeDescriptor.isArray());
 | 
			
		||||
		assertFalse(typeDescriptor.isMap());
 | 
			
		||||
		assertNull(typeDescriptor.getElementType());
 | 
			
		||||
		assertNull(typeDescriptor.getElementTypeDescriptor());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -514,6 +514,11 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertEquals(String.class, t1.getType());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test(expected=IllegalArgumentException.class)
 | 
			
		||||
	public void nestedMethodParameterNot1NestedLevel() throws Exception {
 | 
			
		||||
		TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0, 2), 2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test(expected=IllegalStateException.class)
 | 
			
		||||
	public void nestedTooManyLevels() throws Exception {
 | 
			
		||||
		TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 3);
 | 
			
		||||
| 
						 | 
				
			
			@ -597,8 +602,8 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertEquals(0, desc.getAnnotations().length);
 | 
			
		||||
		assertTrue(desc.isCollection());
 | 
			
		||||
		assertFalse(desc.isArray());
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementType().getType());
 | 
			
		||||
		assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor());
 | 
			
		||||
		assertFalse(desc.isMap());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -613,8 +618,8 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertEquals(0, desc.getAnnotations().length);
 | 
			
		||||
		assertTrue(desc.isCollection());
 | 
			
		||||
		assertFalse(desc.isArray());
 | 
			
		||||
		assertEquals(List.class, desc.getElementType().getType());
 | 
			
		||||
		assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementType().getElementType());
 | 
			
		||||
		assertEquals(List.class, desc.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor().getElementTypeDescriptor());
 | 
			
		||||
		assertFalse(desc.isMap());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -630,8 +635,8 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertFalse(desc.isCollection());
 | 
			
		||||
		assertFalse(desc.isArray());
 | 
			
		||||
		assertTrue(desc.isMap());
 | 
			
		||||
		assertEquals(String.class, desc.getMapKeyType().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapValueType().getType());
 | 
			
		||||
		assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getType());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -647,9 +652,9 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertFalse(desc.isCollection());
 | 
			
		||||
		assertFalse(desc.isArray());
 | 
			
		||||
		assertTrue(desc.isMap());
 | 
			
		||||
		assertEquals(String.class, desc.getMapKeyType().getType());
 | 
			
		||||
		assertEquals(String.class, desc.getMapValueType().getMapKeyType().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapValueType().getMapValueType().getType());
 | 
			
		||||
		assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(String.class, desc.getMapValueTypeDescriptor().getMapKeyTypeDescriptor().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getMapValueTypeDescriptor().getType());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -664,17 +669,17 @@ public class TypeDescriptorTests {
 | 
			
		|||
	public void elementType() {
 | 
			
		||||
		TypeDescriptor desc = TypeDescriptor.valueOf(List.class);
 | 
			
		||||
		Integer value = new Integer(3);
 | 
			
		||||
		desc = desc.elementType(value);
 | 
			
		||||
		desc = desc.elementTypeDescriptor(value);
 | 
			
		||||
		assertEquals(Integer.class, desc.getType());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void elementTypePreserveContext() throws Exception {
 | 
			
		||||
		TypeDescriptor desc = new TypeDescriptor(getClass().getField("listPreserveContext"));
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementType().getElementType().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
		List<Integer> value = new ArrayList<Integer>(3);
 | 
			
		||||
		desc = desc.elementType(value);
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementType().getType());
 | 
			
		||||
		desc = desc.elementTypeDescriptor(value);
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertNotNull(desc.getAnnotation(FieldAnnotation.class));		
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -685,17 +690,17 @@ public class TypeDescriptorTests {
 | 
			
		|||
	public void mapKeyType() {
 | 
			
		||||
		TypeDescriptor desc = TypeDescriptor.valueOf(Map.class);
 | 
			
		||||
		Integer value = new Integer(3);
 | 
			
		||||
		desc = desc.mapKeyType(value);
 | 
			
		||||
		desc = desc.mapKeyTypeDescriptor(value);
 | 
			
		||||
		assertEquals(Integer.class, desc.getType());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void mapKeyTypePreserveContext() throws Exception {
 | 
			
		||||
		TypeDescriptor desc = new TypeDescriptor(getClass().getField("mapPreserveContext"));
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapKeyType().getElementType().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
		List<Integer> value = new ArrayList<Integer>(3);
 | 
			
		||||
		desc = desc.mapKeyType(value);
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementType().getType());
 | 
			
		||||
		desc = desc.mapKeyTypeDescriptor(value);
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertNotNull(desc.getAnnotation(FieldAnnotation.class));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -706,17 +711,17 @@ public class TypeDescriptorTests {
 | 
			
		|||
	public void mapValueType() {
 | 
			
		||||
		TypeDescriptor desc = TypeDescriptor.valueOf(Map.class);
 | 
			
		||||
		Integer value = new Integer(3);
 | 
			
		||||
		desc = desc.mapValueType(value);
 | 
			
		||||
		desc = desc.mapValueTypeDescriptor(value);
 | 
			
		||||
		assertEquals(Integer.class, desc.getType());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void mapValueTypePreserveContext() throws Exception {
 | 
			
		||||
		TypeDescriptor desc = new TypeDescriptor(getClass().getField("mapPreserveContext"));
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapValueType().getElementType().getType());
 | 
			
		||||
		assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
		List<Integer> value = new ArrayList<Integer>(3);
 | 
			
		||||
		desc = desc.mapValueType(value);
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementType().getType());
 | 
			
		||||
		desc = desc.mapValueTypeDescriptor(value);
 | 
			
		||||
		assertEquals(Integer.class, desc.getElementTypeDescriptor().getType());
 | 
			
		||||
		assertNotNull(desc.getAnnotation(FieldAnnotation.class));		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -744,4 +749,29 @@ public class TypeDescriptorTests {
 | 
			
		|||
		assertEquals(t11, t12);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Test
 | 
			
		||||
	public void isAssignableTypes() {
 | 
			
		||||
		assertTrue(TypeDescriptor.valueOf(Integer.class).isAssignableTo(TypeDescriptor.valueOf(Number.class)));		
 | 
			
		||||
		assertFalse(TypeDescriptor.valueOf(Number.class).isAssignableTo(TypeDescriptor.valueOf(Integer.class)));
 | 
			
		||||
		assertFalse(TypeDescriptor.valueOf(String.class).isAssignableTo(TypeDescriptor.valueOf(String[].class)));		
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void isAssignableElementTypes() throws Exception {
 | 
			
		||||
		assertTrue(new TypeDescriptor(getClass().getField("listField")).isAssignableTo(new TypeDescriptor(getClass().getField("listField"))));		
 | 
			
		||||
		assertTrue(new TypeDescriptor(getClass().getField("isAssignableElementTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("listField"))));
 | 
			
		||||
		assertTrue(TypeDescriptor.valueOf(List.class).isAssignableTo(new TypeDescriptor(getClass().getField("listField"))));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	public List<Number> isAssignableElementTypes;
 | 
			
		||||
	
 | 
			
		||||
	@Test
 | 
			
		||||
	public void isAssignableMapKeyValueTypes() throws Exception {
 | 
			
		||||
		assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField"))));		
 | 
			
		||||
		assertTrue(new TypeDescriptor(getClass().getField("isAssignableMapKeyValueTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField"))));		
 | 
			
		||||
		assertTrue(TypeDescriptor.valueOf(Map.class).isAssignableTo(new TypeDescriptor(getClass().getField("mapField"))));
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	public Map<CharSequence, Number> isAssignableMapKeyValueTypes;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,11 +91,11 @@ public class Indexer extends SpelNodeImpl {
 | 
			
		|||
		// Indexing into a Map
 | 
			
		||||
		if (targetObject instanceof Map) {
 | 
			
		||||
			Object key = index;
 | 
			
		||||
			if (targetObjectTypeDescriptor.getMapKeyType() != null) {
 | 
			
		||||
				key = state.convertValue(key, targetObjectTypeDescriptor.getMapKeyType());
 | 
			
		||||
			if (targetObjectTypeDescriptor.getMapKeyTypeDescriptor() != null) {
 | 
			
		||||
				key = state.convertValue(key, targetObjectTypeDescriptor.getMapKeyTypeDescriptor());
 | 
			
		||||
			}
 | 
			
		||||
			Object value = ((Map<?, ?>) targetObject).get(key);
 | 
			
		||||
			return new TypedValue(value, targetObjectTypeDescriptor.mapValueType(value));
 | 
			
		||||
			return new TypedValue(value, targetObjectTypeDescriptor.mapValueTypeDescriptor(value));
 | 
			
		||||
		}
 | 
			
		||||
		
 | 
			
		||||
		if (targetObject == null) {
 | 
			
		||||
| 
						 | 
				
			
			@ -107,7 +107,7 @@ public class Indexer extends SpelNodeImpl {
 | 
			
		|||
			int idx = (Integer) state.convertValue(index, TypeDescriptor.valueOf(Integer.class));		
 | 
			
		||||
			if (targetObject.getClass().isArray()) {
 | 
			
		||||
				Object arrayElement = accessArrayElement(targetObject, idx);
 | 
			
		||||
				return new TypedValue(arrayElement, targetObjectTypeDescriptor.elementType(arrayElement));
 | 
			
		||||
				return new TypedValue(arrayElement, targetObjectTypeDescriptor.elementTypeDescriptor(arrayElement));
 | 
			
		||||
			} else if (targetObject instanceof Collection) {
 | 
			
		||||
				Collection c = (Collection) targetObject;
 | 
			
		||||
				if (idx >= c.size()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +118,7 @@ public class Indexer extends SpelNodeImpl {
 | 
			
		|||
				int pos = 0;
 | 
			
		||||
				for (Object o : c) {
 | 
			
		||||
					if (pos == idx) {
 | 
			
		||||
						return new TypedValue(o, targetObjectTypeDescriptor.elementType(o));
 | 
			
		||||
						return new TypedValue(o, targetObjectTypeDescriptor.elementTypeDescriptor(o));
 | 
			
		||||
					}
 | 
			
		||||
					pos++;
 | 
			
		||||
				}
 | 
			
		||||
| 
						 | 
				
			
			@ -187,11 +187,11 @@ public class Indexer extends SpelNodeImpl {
 | 
			
		|||
		if (targetObject instanceof Map) {
 | 
			
		||||
			Map map = (Map) targetObject;
 | 
			
		||||
			Object key = index.getValue();
 | 
			
		||||
			if (targetObjectTypeDescriptor.getMapKeyType() != null) {
 | 
			
		||||
				key = state.convertValue(index, targetObjectTypeDescriptor.getMapKeyType());
 | 
			
		||||
			if (targetObjectTypeDescriptor.getMapKeyTypeDescriptor() != null) {
 | 
			
		||||
				key = state.convertValue(index, targetObjectTypeDescriptor.getMapKeyTypeDescriptor());
 | 
			
		||||
			}
 | 
			
		||||
			if (targetObjectTypeDescriptor.getMapValueType() != null) {
 | 
			
		||||
				newValue = state.convertValue(newValue, targetObjectTypeDescriptor.getMapValueType());				
 | 
			
		||||
			if (targetObjectTypeDescriptor.getMapValueTypeDescriptor() != null) {
 | 
			
		||||
				newValue = state.convertValue(newValue, targetObjectTypeDescriptor.getMapValueTypeDescriptor());				
 | 
			
		||||
			}
 | 
			
		||||
			map.put(key, newValue);
 | 
			
		||||
			return;
 | 
			
		||||
| 
						 | 
				
			
			@ -199,7 +199,7 @@ public class Indexer extends SpelNodeImpl {
 | 
			
		|||
 | 
			
		||||
		if (targetObjectTypeDescriptor.isArray()) {
 | 
			
		||||
			int idx = (Integer)state.convertValue(index, TypeDescriptor.valueOf(Integer.class));
 | 
			
		||||
			setArrayElement(state, contextObject.getValue(), idx, newValue, targetObjectTypeDescriptor.getElementType().getType());
 | 
			
		||||
			setArrayElement(state, contextObject.getValue(), idx, newValue, targetObjectTypeDescriptor.getElementTypeDescriptor().getType());
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		else if (targetObject instanceof Collection) {
 | 
			
		||||
| 
						 | 
				
			
			@ -212,8 +212,8 @@ public class Indexer extends SpelNodeImpl {
 | 
			
		|||
			}
 | 
			
		||||
			if (targetObject instanceof List) {
 | 
			
		||||
				List list = (List) targetObject;
 | 
			
		||||
				if (targetObjectTypeDescriptor.getElementType() != null) {
 | 
			
		||||
					newValue = state.convertValue(newValue, targetObjectTypeDescriptor.getElementType());
 | 
			
		||||
				if (targetObjectTypeDescriptor.getElementTypeDescriptor() != null) {
 | 
			
		||||
					newValue = state.convertValue(newValue, targetObjectTypeDescriptor.getElementTypeDescriptor());
 | 
			
		||||
				}
 | 
			
		||||
				list.set(idx, newValue);
 | 
			
		||||
				return;
 | 
			
		||||
| 
						 | 
				
			
			@ -271,10 +271,10 @@ public class Indexer extends SpelNodeImpl {
 | 
			
		|||
	private boolean growCollection(ExpressionState state, TypeDescriptor targetType, int index,
 | 
			
		||||
			Collection collection) {
 | 
			
		||||
		if (state.getConfiguration().isAutoGrowCollections()) {
 | 
			
		||||
			if (targetType.getElementType() == null) {
 | 
			
		||||
			if (targetType.getElementTypeDescriptor() == null) {
 | 
			
		||||
				throw new SpelEvaluationException(getStartPosition(), SpelMessage.UNABLE_TO_GROW_COLLECTION_UNKNOWN_ELEMENT_TYPE);				
 | 
			
		||||
			}
 | 
			
		||||
			TypeDescriptor elementType = targetType.getElementType();
 | 
			
		||||
			TypeDescriptor elementType = targetType.getElementTypeDescriptor();
 | 
			
		||||
			Object newCollectionElement = null;
 | 
			
		||||
			try {
 | 
			
		||||
				int newElements = index - collection.size();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -142,7 +142,7 @@ public class Selection extends SpelNodeImpl {
 | 
			
		|||
				return new TypedValue(result);
 | 
			
		||||
			}
 | 
			
		||||
			else {
 | 
			
		||||
				Class<?> elementType = ClassUtils.resolvePrimitiveIfNecessary(op.getTypeDescriptor().getElementType().getType());
 | 
			
		||||
				Class<?> elementType = ClassUtils.resolvePrimitiveIfNecessary(op.getTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
				Object resultArray = Array.newInstance(elementType, result.size());
 | 
			
		||||
				System.arraycopy(result.toArray(), 0, resultArray, 0, result.size());
 | 
			
		||||
				return new TypedValue(resultArray);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -213,7 +213,7 @@ 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().getType();
 | 
			
		||||
			Class varargsParameterType = expectedArgTypes.get(expectedArgTypes.size() - 1).getElementTypeDescriptor().getType();
 | 
			
		||||
 | 
			
		||||
			// All remaining parameters must be of this type or convertable to this type
 | 
			
		||||
			for (int i = expectedArgTypes.size() - 1; i < suppliedArgTypes.size(); i++) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,13 +74,13 @@ public class ExpressionTestsUsingCoreConversionService extends ExpressionTestCas
 | 
			
		|||
		TypeConvertorUsingConversionService tcs = new TypeConvertorUsingConversionService();
 | 
			
		||||
		
 | 
			
		||||
		// ArrayList containing List<Integer> to List<String>
 | 
			
		||||
		Class<?> clazz = typeDescriptorForListOfString.getElementType().getType();
 | 
			
		||||
		Class<?> clazz = typeDescriptorForListOfString.getElementTypeDescriptor().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().getType();
 | 
			
		||||
		clazz = typeDescriptorForListOfInteger.getElementTypeDescriptor().getType();
 | 
			
		||||
		assertEquals(Integer.class,clazz);
 | 
			
		||||
		
 | 
			
		||||
		l = (List) tcs.convertValue(listOfString, TypeDescriptor.forObject(listOfString), typeDescriptorForListOfString);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -113,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().getType());
 | 
			
		||||
		assertEquals(Integer.class, typedValue.getTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
		Integer[] array = (Integer[]) value;
 | 
			
		||||
		assertEquals(5, array.length);
 | 
			
		||||
		assertEquals(new Integer(0), array[0]);
 | 
			
		||||
| 
						 | 
				
			
			@ -148,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().getType());
 | 
			
		||||
		assertEquals(Integer.class, typedValue.getTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
		Integer[] array = (Integer[]) value;
 | 
			
		||||
		assertEquals(5, array.length);
 | 
			
		||||
		assertEquals(new Integer(0), array[0]);
 | 
			
		||||
| 
						 | 
				
			
			@ -250,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().getType());
 | 
			
		||||
		assertEquals(Number.class, typedValue.getTypeDescriptor().getElementTypeDescriptor().getType());
 | 
			
		||||
		Number[] array = (Number[]) value;
 | 
			
		||||
		assertEquals(3, array.length);
 | 
			
		||||
		assertEquals(new Integer(5), array[0]);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -729,7 +729,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(null, evaluated.getElementType());
 | 
			
		||||
        Assert.assertEquals(null, evaluated.getElementTypeDescriptor());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -742,7 +742,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().getType());
 | 
			
		||||
        Assert.assertEquals(Boolean.class, evaluated.getElementTypeDescriptor().getType());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	@Test
 | 
			
		||||
| 
						 | 
				
			
			@ -755,7 +755,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(null, evaluated.getElementType());
 | 
			
		||||
        Assert.assertEquals(null, evaluated.getElementTypeDescriptor());
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	static class C {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue