From b0a9781f0f98ecf3bcb9664edaa55626fbdb7b37 Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Tue, 7 Jun 2011 02:51:44 +0000 Subject: [PATCH] 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 git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4478 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../beans/TypeConverterDelegate.java | 14 +- .../core/convert/AbstractDescriptor.java | 6 +- .../core/convert/FieldDescriptor.java | 1 + .../core/convert/TypeDescriptor.java | 217 ++++++++---------- .../support/ArrayToCollectionConverter.java | 4 +- .../support/CollectionToArrayConverter.java | 4 +- .../CollectionToCollectionConverter.java | 4 +- .../support/CollectionToObjectConverter.java | 2 +- .../support/CollectionToStringConverter.java | 2 +- .../convert/support/MapToMapConverter.java | 8 +- .../support/ObjectToArrayConverter.java | 4 +- .../support/ObjectToCollectionConverter.java | 4 +- .../support/StringToArrayConverter.java | 6 +- .../support/StringToCollectionConverter.java | 8 +- .../core/convert/TypeDescriptorTests.java | 142 +++++++----- .../expression/spel/ast/Indexer.java | 28 +-- .../expression/spel/ast/Selection.java | 2 +- .../spel/support/ReflectionHelper.java | 2 +- ...essionTestsUsingCoreConversionService.java | 4 +- .../spel/SelectionAndProjectionTests.java | 6 +- .../expression/spel/SpringEL300Tests.java | 6 +- 21 files changed, 244 insertions(+), 230 deletions(-) diff --git a/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java b/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java index 8d888edc6fe..0d9d11437a5 100644 --- a/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java +++ b/org.springframework.beans/src/main/java/org/springframework/beans/TypeConverterDelegate.java @@ -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); } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/AbstractDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/AbstractDescriptor.java index 9632decced8..3a1c0cda114 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/AbstractDescriptor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/AbstractDescriptor.java @@ -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; diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/FieldDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/FieldDescriptor.java index 40490d252e2..a03c561ebf2 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/FieldDescriptor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/FieldDescriptor.java @@ -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 } } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java index b4c64986297..7adc7059ca6 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java @@ -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 null 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 null 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 null 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() : "?"; } } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java index 70edcbb81ca..8bb233bca99 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ArrayToCollectionConverter.java @@ -55,7 +55,7 @@ final class ArrayToCollectionConverter implements GenericConverter { } int length = Array.getLength(source); Collection 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); } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArrayConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArrayConverter.java index 34c509e5747..ad9a3f2cf0e 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArrayConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToArrayConverter.java @@ -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; diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java index 731c94f3aec..fcfb8f1d874 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToCollectionConverter.java @@ -55,13 +55,13 @@ final class CollectionToCollectionConverter implements GenericConverter { } Collection sourceCollection = (Collection) source; Collection 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); } } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectConverter.java index 58a978d2c8d..0068041034a 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToObjectConverter.java @@ -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); } } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringConverter.java index f7c65b4b5e9..f65fefcfcd1 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/CollectionToStringConverter.java @@ -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++; } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java index ecd47687749..6f4e3647577 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/MapToMapConverter.java @@ -58,8 +58,8 @@ final class MapToMapConverter implements GenericConverter { for (Map.Entry 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); } } \ No newline at end of file diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToArrayConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToArrayConverter.java index bef3a32ddce..6d2d122aa0e 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToArrayConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToArrayConverter.java @@ -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; } diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionConverter.java index 9cc26d83ec3..c35ac04861d 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/ObjectToCollectionConverter.java @@ -51,10 +51,10 @@ final class ObjectToCollectionConverter implements GenericConverter { return null; } Collection 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; diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToArrayConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToArrayConverter.java index 3ee76bf1b83..21d03febb24 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToArrayConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToArrayConverter.java @@ -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; diff --git a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionConverter.java b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionConverter.java index 1fceba080d5..ad6ebf71bc2 100644 --- a/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionConverter.java +++ b/org.springframework.core/src/main/java/org/springframework/core/convert/support/StringToCollectionConverter.java @@ -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 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); } } diff --git a/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java b/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java index 4b3fedc717e..27db5e60827 100644 --- a/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java +++ b/org.springframework.core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java @@ -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> 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>> 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 { @@ -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", 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>", 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>", 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>", 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> 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 value = new ArrayList(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 value = new ArrayList(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 value = new ArrayList(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 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 isAssignableMapKeyValueTypes; + } diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java index 5e31ad6c4d9..b12c5d5c6a2 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Indexer.java @@ -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(); diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Selection.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Selection.java index 3cbac19ca4c..c20442e1d2c 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Selection.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Selection.java @@ -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); diff --git a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java index 42868bdc954..153b435bcaa 100644 --- a/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java +++ b/org.springframework.expression/src/main/java/org/springframework/expression/spel/support/ReflectionHelper.java @@ -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++) { diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionTestsUsingCoreConversionService.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionTestsUsingCoreConversionService.java index 0d0b50cb808..af7e57e6e14 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionTestsUsingCoreConversionService.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/ExpressionTestsUsingCoreConversionService.java @@ -74,13 +74,13 @@ public class ExpressionTestsUsingCoreConversionService extends ExpressionTestCas TypeConvertorUsingConversionService tcs = new TypeConvertorUsingConversionService(); // ArrayList containing List to List - 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 to List - clazz = typeDescriptorForListOfInteger.getElementType().getType(); + clazz = typeDescriptorForListOfInteger.getElementTypeDescriptor().getType(); assertEquals(Integer.class,clazz); l = (List) tcs.convertValue(listOfString, TypeDescriptor.forObject(listOfString), typeDescriptorForListOfString); diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/SelectionAndProjectionTests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/SelectionAndProjectionTests.java index 9f0a64ec1c8..30f68a4053b 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/SelectionAndProjectionTests.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/SelectionAndProjectionTests.java @@ -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]); diff --git a/org.springframework.expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java b/org.springframework.expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java index b0f02af27e0..c947e27e025 100644 --- a/org.springframework.expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java +++ b/org.springframework.expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java @@ -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 {