added TypeDescriptor resolveCollectionElement and Map key/value types
This commit is contained in:
parent
9c3c1c64b3
commit
5db1687d29
|
|
@ -36,13 +36,13 @@ import org.springframework.util.ObjectUtils;
|
||||||
*/
|
*/
|
||||||
public class TypeDescriptor {
|
public class TypeDescriptor {
|
||||||
|
|
||||||
|
static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
|
||||||
|
|
||||||
/** Constant defining a TypeDescriptor for a <code>null</code> value */
|
/** Constant defining a TypeDescriptor for a <code>null</code> value */
|
||||||
public static final TypeDescriptor NULL = new TypeDescriptor();
|
public static final TypeDescriptor NULL = new TypeDescriptor();
|
||||||
|
|
||||||
private static final Map<Class<?>, TypeDescriptor> typeDescriptorCache = new HashMap<Class<?>, TypeDescriptor>();
|
private static final Map<Class<?>, TypeDescriptor> typeDescriptorCache = new HashMap<Class<?>, TypeDescriptor>();
|
||||||
|
|
||||||
static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
typeDescriptorCache.put(boolean.class, new TypeDescriptor(boolean.class));
|
typeDescriptorCache.put(boolean.class, new TypeDescriptor(boolean.class));
|
||||||
typeDescriptorCache.put(Boolean.class, new TypeDescriptor(Boolean.class));
|
typeDescriptorCache.put(Boolean.class, new TypeDescriptor(Boolean.class));
|
||||||
|
|
@ -237,21 +237,21 @@ public class TypeDescriptor {
|
||||||
* Returns the Object wrapper type if the underlying type is a primitive.
|
* Returns the Object wrapper type if the underlying type is a primitive.
|
||||||
*/
|
*/
|
||||||
public Class<?> getObjectType() {
|
public Class<?> getObjectType() {
|
||||||
return ClassUtils.resolvePrimitiveIfNecessary(getType());
|
return getType() != null ? ClassUtils.resolvePrimitiveIfNecessary(getType()) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of this type: the fully qualified class name.
|
* Returns the name of this type: the fully qualified class name.
|
||||||
*/
|
*/
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return ClassUtils.getQualifiedName(getType());
|
return getType() != null ? ClassUtils.getQualifiedName(getType()) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this type a primitive type?
|
* Is this type a primitive type?
|
||||||
*/
|
*/
|
||||||
public boolean isPrimitive() {
|
public boolean isPrimitive() {
|
||||||
return getType().isPrimitive();
|
return getType() != null && getType().isPrimitive();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -304,21 +304,21 @@ public class TypeDescriptor {
|
||||||
* Is this type a {@link Collection} type?
|
* Is this type a {@link Collection} type?
|
||||||
*/
|
*/
|
||||||
public boolean isCollection() {
|
public boolean isCollection() {
|
||||||
return Collection.class.isAssignableFrom(getType());
|
return getType() != null && Collection.class.isAssignableFrom(getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this type an array type?
|
* Is this type an array type?
|
||||||
*/
|
*/
|
||||||
public boolean isArray() {
|
public boolean isArray() {
|
||||||
return getType().isArray();
|
return getType() != null && getType().isArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this type is a {@link Collection} or array, returns the underlying element type.
|
* If this type is a {@link Collection} or array, returns the underlying element type.
|
||||||
* Returns <code>null</code> if this type is neither an array or collection.
|
|
||||||
* Returns Object.class if this type is a collection and the element type was not explicitly declared.
|
* Returns Object.class if this type is a collection and the element type was not explicitly declared.
|
||||||
* @return the map element type, or <code>null</code> if not a collection or array.
|
* @return the map element type, or <code>null</code> if not a collection or array.
|
||||||
|
* @throws IllegalStateException if this descriptor is not for a java.util.Collection or Array
|
||||||
*/
|
*/
|
||||||
public Class<?> getElementType() {
|
public Class<?> getElementType() {
|
||||||
return getElementTypeDescriptor().getType();
|
return getElementTypeDescriptor().getType();
|
||||||
|
|
@ -326,27 +326,47 @@ public class TypeDescriptor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The collection or array element type as a type descriptor.
|
* The collection or array element type as a type descriptor.
|
||||||
* Returns {@link TypeDescriptor#NULL} if this type is not a collection or an array.
|
|
||||||
* Returns TypeDescriptor.valueOf(Object.class) if this type is a collection and the element type is not explicitly declared.
|
* Returns TypeDescriptor.valueOf(Object.class) if this type is a collection and the element type is not explicitly declared.
|
||||||
|
* @throws IllegalStateException if this descriptor is not for a java.util.Collection or Array
|
||||||
*/
|
*/
|
||||||
public TypeDescriptor getElementTypeDescriptor() {
|
public TypeDescriptor getElementTypeDescriptor() {
|
||||||
|
if (!isCollection() && !isArray()) {
|
||||||
|
throw new IllegalStateException("Not a java.util.Collection or Array");
|
||||||
|
}
|
||||||
return this.elementType;
|
return this.elementType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this type descriptor that has its elementType populated from the specified Collection.
|
||||||
|
* This property will be set by calculating the "common element type" of the specified Collection.
|
||||||
|
* For example, if the collection contains String elements, the returned TypeDescriptor will have its elementType set to String.
|
||||||
|
* This method is designed to be used when converting values read from Collection fields or method return values that are not parameterized e.g. Collection vs. Collection<String>
|
||||||
|
* In this scenario the elementType will be Object.class before invoking this method.
|
||||||
|
* @param colection the collection to derive the elementType from
|
||||||
|
* @return a new TypeDescriptor with the resolved elementType property
|
||||||
|
* @throws IllegalArgumentException if this is not a type descriptor for a java.util.Collection.
|
||||||
|
*/
|
||||||
|
public TypeDescriptor resolveCollectionElementType(Collection<?> collection) {
|
||||||
|
if (!isCollection()) {
|
||||||
|
throw new IllegalStateException("Not a java.util.Collection");
|
||||||
|
}
|
||||||
|
return new TypeDescriptor(type, CommonElement.typeDescriptor(collection), mapKeyType, mapValueType, annotations);
|
||||||
|
}
|
||||||
|
|
||||||
// map type descriptor operations
|
// map type descriptor operations
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this type a {@link Map} type?
|
* Is this type a {@link Map} type?
|
||||||
*/
|
*/
|
||||||
public boolean isMap() {
|
public boolean isMap() {
|
||||||
return Map.class.isAssignableFrom(getType());
|
return getType() != null && Map.class.isAssignableFrom(getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this type is a {@link Map}, returns the underlying key type.
|
* If this type is a {@link Map}, returns the underlying key type.
|
||||||
* Returns <code>null</code> if this type is not map.
|
|
||||||
* Returns Object.class if this type is a map and its key type was not explicitly declared.
|
* Returns Object.class if this type is a map and its key type was not explicitly declared.
|
||||||
* @return the map key type, or <code>null</code> if not a map.
|
* @return the map key type, or <code>null</code> if not a map.
|
||||||
|
* @throws IllegalStateException if this descriptor is not for a java.util.Map
|
||||||
*/
|
*/
|
||||||
public Class<?> getMapKeyType() {
|
public Class<?> getMapKeyType() {
|
||||||
return getMapKeyTypeDescriptor().getType();
|
return getMapKeyTypeDescriptor().getType();
|
||||||
|
|
@ -354,10 +374,13 @@ public class TypeDescriptor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The map key type as a type descriptor.
|
* The map key type as a type descriptor.
|
||||||
* Returns {@link TypeDescriptor#NULL} if this type is not a map.
|
|
||||||
* Returns TypeDescriptor.valueOf(Object.class) if this type is a map and the key type is not explicitly declared.
|
* Returns TypeDescriptor.valueOf(Object.class) if this type is a map and the key type is not explicitly declared.
|
||||||
|
* @throws IllegalStateException if this descriptor is not for a java.util.Map
|
||||||
*/
|
*/
|
||||||
public TypeDescriptor getMapKeyTypeDescriptor() {
|
public TypeDescriptor getMapKeyTypeDescriptor() {
|
||||||
|
if (!isMap()) {
|
||||||
|
throw new IllegalStateException("Not a map");
|
||||||
|
}
|
||||||
return this.mapKeyType;
|
return this.mapKeyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -366,6 +389,7 @@ public class TypeDescriptor {
|
||||||
* Returns <code>null</code> if this type is not map.
|
* Returns <code>null</code> if this type is not map.
|
||||||
* Returns Object.class if this type is a map and its value type was not explicitly declared.
|
* Returns Object.class if this type is a map and its value type was not explicitly declared.
|
||||||
* @return the map value type, or <code>null</code> if not a map.
|
* @return the map value type, or <code>null</code> if not a map.
|
||||||
|
* @throws IllegalStateException if this descriptor is not for a java.util.Map
|
||||||
*/
|
*/
|
||||||
public Class<?> getMapValueType() {
|
public Class<?> getMapValueType() {
|
||||||
return getMapValueTypeDescriptor().getType();
|
return getMapValueTypeDescriptor().getType();
|
||||||
|
|
@ -373,12 +397,32 @@ public class TypeDescriptor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The map value type as a type descriptor.
|
* The map value type as a type descriptor.
|
||||||
* Returns {@link TypeDescriptor#NULL} if this type is not a map.
|
|
||||||
* Returns TypeDescriptor.valueOf(Object.class) if this type is a map and the value type is not explicitly declared.
|
* Returns TypeDescriptor.valueOf(Object.class) if this type is a map and the value type is not explicitly declared.
|
||||||
|
* @throws IllegalStateException if this descriptor is not for a java.util.Map
|
||||||
*/
|
*/
|
||||||
public TypeDescriptor getMapValueTypeDescriptor() {
|
public TypeDescriptor getMapValueTypeDescriptor() {
|
||||||
|
if (!isMap()) {
|
||||||
|
throw new IllegalStateException("Not a map");
|
||||||
|
}
|
||||||
return this.mapValueType;
|
return this.mapValueType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this type descriptor that has its mapKeyType and mapValueType properties populated from the specified Map.
|
||||||
|
* These properties will be set by calculating the "common element type" of the specified Map's keySet and values collection.
|
||||||
|
* For example, if the Map contains String keys and Integer values, the returned TypeDescriptor will have its mapKeyType set to String and its mapValueType to Integer.
|
||||||
|
* This method is designed to be used when converting values read from Map fields or method return values that are not parameterized e.g. Map vs. Map<String, Integer>.
|
||||||
|
* In this scenario the key and value types will be Object.class before invoking this method.
|
||||||
|
* @param map the map to derive key and value types from
|
||||||
|
* @return a new TypeDescriptor with the resolved mapKeyType and mapValueType properties
|
||||||
|
* @throws IllegalArgumentException if this is not a type descriptor for a java.util.Map.
|
||||||
|
*/
|
||||||
|
public TypeDescriptor resolveMapKeyValueTypes(Map<?, ?> map) {
|
||||||
|
if (!isMap()) {
|
||||||
|
throw new IllegalStateException("Not a java.util.Map");
|
||||||
|
}
|
||||||
|
return new TypeDescriptor(type, elementType, CommonElement.typeDescriptor(map.keySet()), CommonElement.typeDescriptor(map.values()), annotations);
|
||||||
|
}
|
||||||
|
|
||||||
// extending Object
|
// extending Object
|
||||||
|
|
||||||
|
|
@ -386,20 +430,22 @@ public class TypeDescriptor {
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!(obj instanceof TypeDescriptor) || obj == TypeDescriptor.NULL) {
|
if (!(obj instanceof TypeDescriptor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TypeDescriptor other = (TypeDescriptor) obj;
|
TypeDescriptor other = (TypeDescriptor) obj;
|
||||||
boolean annotatedTypeEquals = getType().equals(other.getType()) && ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations());
|
boolean annotatedTypeEquals = ObjectUtils.nullSafeEquals(getType(), other.getType()) && ObjectUtils.nullSafeEquals(getAnnotations(), other.getAnnotations());
|
||||||
if (isCollection()) {
|
if (!annotatedTypeEquals) {
|
||||||
return annotatedTypeEquals && ObjectUtils.nullSafeEquals(getElementType(), other.getElementType());
|
return false;
|
||||||
|
}
|
||||||
|
if (isCollection() || isArray()) {
|
||||||
|
return ObjectUtils.nullSafeEquals(getElementType(), other.getElementType());
|
||||||
}
|
}
|
||||||
else if (isMap()) {
|
else if (isMap()) {
|
||||||
return annotatedTypeEquals && ObjectUtils.nullSafeEquals(getMapKeyType(), other.getMapKeyType()) &&
|
return ObjectUtils.nullSafeEquals(getMapKeyType(), other.getMapKeyType()) && ObjectUtils.nullSafeEquals(getMapValueType(), other.getMapValueType());
|
||||||
ObjectUtils.nullSafeEquals(getMapValueType(), other.getMapValueType());
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return annotatedTypeEquals;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -440,11 +486,11 @@ public class TypeDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDescriptor(Class<?> collectionType, TypeDescriptor elementType) {
|
TypeDescriptor(Class<?> collectionType, TypeDescriptor elementType) {
|
||||||
this(collectionType, elementType, TypeDescriptor.NULL, TypeDescriptor.NULL);
|
this(collectionType, elementType, TypeDescriptor.NULL, TypeDescriptor.NULL, EMPTY_ANNOTATION_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeDescriptor(Class<?> mapType, TypeDescriptor keyType, TypeDescriptor valueType) {
|
TypeDescriptor(Class<?> mapType, TypeDescriptor keyType, TypeDescriptor valueType) {
|
||||||
this(mapType, TypeDescriptor.NULL, keyType, valueType);
|
this(mapType, TypeDescriptor.NULL, keyType, valueType, EMPTY_ANNOTATION_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Annotation[] nullSafeAnnotations(Annotation[] annotations) {
|
static Annotation[] nullSafeAnnotations(Annotation[] annotations) {
|
||||||
|
|
@ -458,15 +504,15 @@ public class TypeDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeDescriptor() {
|
private TypeDescriptor() {
|
||||||
this(null, TypeDescriptor.NULL, TypeDescriptor.NULL, TypeDescriptor.NULL);
|
this(null, TypeDescriptor.NULL, TypeDescriptor.NULL, TypeDescriptor.NULL, EMPTY_ANNOTATION_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeDescriptor(Class<?> type, TypeDescriptor elementType, TypeDescriptor mapKeyType, TypeDescriptor mapValueType) {
|
private TypeDescriptor(Class<?> type, TypeDescriptor elementType, TypeDescriptor mapKeyType, TypeDescriptor mapValueType, Annotation[] annotations) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.elementType = elementType;
|
this.elementType = elementType;
|
||||||
this.mapKeyType = mapKeyType;
|
this.mapKeyType = mapKeyType;
|
||||||
this.mapValueType = mapValueType;
|
this.mapValueType = mapValueType;
|
||||||
this.annotations = EMPTY_ANNOTATION_ARRAY;
|
this.annotations = annotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal helpers
|
// internal helpers
|
||||||
|
|
@ -477,5 +523,5 @@ public class TypeDescriptor {
|
||||||
}
|
}
|
||||||
return new TypeDescriptor(descriptor);
|
return new TypeDescriptor(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -57,10 +57,11 @@ final class CollectionToArrayConverter implements ConditionalGenericConverter {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Collection<?> sourceCollection = (Collection<?>) source;
|
Collection<?> sourceCollection = (Collection<?>) source;
|
||||||
Object array = Array.newInstance(targetType.getElementType(), sourceCollection.size());
|
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
|
||||||
|
Object array = Array.newInstance(targetElementType.getType(), sourceCollection.size());
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (Object sourceElement : sourceCollection) {
|
for (Object sourceElement : sourceCollection) {
|
||||||
Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor());
|
Object targetElement = this.conversionService.convert(sourceElement, sourceType.getElementTypeDescriptor(), targetElementType);
|
||||||
Array.set(array, i++, targetElement);
|
Array.set(array, i++, targetElement);
|
||||||
}
|
}
|
||||||
return array;
|
return array;
|
||||||
|
|
|
||||||
|
|
@ -167,36 +167,24 @@ public class GenericConversionService implements ConfigurableConversionService {
|
||||||
logger.debug("Converting value " + StylerUtils.style(source) + " of " + sourceType + " to " + targetType);
|
logger.debug("Converting value " + StylerUtils.style(source) + " of " + sourceType + " to " + targetType);
|
||||||
}
|
}
|
||||||
if (sourceType == TypeDescriptor.NULL) {
|
if (sourceType == TypeDescriptor.NULL) {
|
||||||
Assert.isTrue(source == null, "The value must be null if sourceType == TypeDescriptor.NULL");
|
Assert.isTrue(source == null, "The source must be [null] if sourceType == [null]");
|
||||||
Object result = convertNullSource(sourceType, targetType);
|
return handleResult(sourceType, targetType, convertNullSource(sourceType, targetType));
|
||||||
if (result == null) {
|
|
||||||
assertNotPrimitiveTargetType(sourceType, targetType);
|
|
||||||
}
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Converted to " + StylerUtils.style(result));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
if (targetType == TypeDescriptor.NULL) {
|
if (targetType == TypeDescriptor.NULL) {
|
||||||
logger.debug("Converted to null");
|
logger.debug("Converted to null");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Assert.isTrue(source == null || sourceType.getObjectType().isInstance(source));
|
if (source != null && !sourceType.getObjectType().isInstance(source)) {
|
||||||
|
throw new IllegalArgumentException("The source to convert from must be an instance of " + sourceType + "; instead it was a " + source.getClass().getName());
|
||||||
|
}
|
||||||
GenericConverter converter = getConverter(sourceType, targetType);
|
GenericConverter converter = getConverter(sourceType, targetType);
|
||||||
if (converter == null) {
|
if (converter != null) {
|
||||||
return handleConverterNotFound(source, sourceType, targetType);
|
return handleResult(sourceType, targetType, ConversionUtils.invokeConverter(converter, source, sourceType, targetType));
|
||||||
|
} else {
|
||||||
|
return handleConverterNotFound(source, sourceType, targetType);
|
||||||
}
|
}
|
||||||
Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
|
|
||||||
if (result == null) {
|
|
||||||
assertNotPrimitiveTargetType(sourceType, targetType);
|
|
||||||
}
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Converted to " + StylerUtils.style(result));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
List<String> converterStrings = new ArrayList<String>();
|
List<String> converterStrings = new ArrayList<String>();
|
||||||
for (Map<Class<?>, MatchableConverters> targetConverters : this.converters.values()) {
|
for (Map<Class<?>, MatchableConverters> targetConverters : this.converters.values()) {
|
||||||
|
|
@ -325,7 +313,7 @@ public class GenericConversionService implements ConfigurableConversionService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertNotNull(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
private void assertNotNull(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
Assert.notNull(sourceType, "The sourceType to convert to is required");
|
Assert.notNull(sourceType, "The sourceType to convert from is required");
|
||||||
Assert.notNull(targetType, "The targetType to convert to is required");
|
Assert.notNull(targetType, "The targetType to convert to is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -537,6 +525,15 @@ public class GenericConversionService implements ConfigurableConversionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Object handleResult(TypeDescriptor sourceType, TypeDescriptor targetType, Object result) {
|
||||||
|
if (result == null) {
|
||||||
|
assertNotPrimitiveTargetType(sourceType, targetType);
|
||||||
|
}
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Converted to " + StylerUtils.style(result));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
private void assertNotPrimitiveTargetType(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
private void assertNotPrimitiveTargetType(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
if (targetType.isPrimitive()) {
|
if (targetType.isPrimitive()) {
|
||||||
throw new ConversionFailedException(sourceType, targetType, null,
|
throw new ConversionFailedException(sourceType, targetType, null,
|
||||||
|
|
|
||||||
|
|
@ -48,14 +48,14 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
Class<?> source = sourceType.getObjectType();
|
Class<?> source = sourceType.getType();
|
||||||
Class<?> target = targetType.getObjectType();
|
Class<?> target = targetType.getType();
|
||||||
return (!source.equals(target) && hasValueOfMethodOrConstructor(target, source));
|
return !source.equals(target) && hasValueOfMethodOrConstructor(target, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
Class<?> sourceClass = sourceType.getObjectType();
|
Class<?> sourceClass = sourceType.getType();
|
||||||
Class<?> targetClass = targetType.getObjectType();
|
Class<?> targetClass = targetType.getType();
|
||||||
Method method = getValueOfMethodOn(targetClass, sourceClass);
|
Method method = getValueOfMethodOn(targetClass, sourceClass);
|
||||||
try {
|
try {
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
|
|
@ -79,9 +79,8 @@ final class ObjectToObjectConverter implements ConditionalGenericConverter {
|
||||||
") method or Constructor(" + sourceClass.getName() + ") exists on " + targetClass.getName());
|
") method or Constructor(" + sourceClass.getName() + ") exists on " + targetClass.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static boolean hasValueOfMethodOrConstructor(Class<?> targetClass, Class<?> sourceClass) {
|
public static boolean hasValueOfMethodOrConstructor(Class<?> targetClass, Class<?> sourceClass) {
|
||||||
return (getValueOfMethodOn(targetClass, sourceClass) != null || getConstructor(targetClass, sourceClass) != null);
|
return getValueOfMethodOn(targetClass, sourceClass) != null || getConstructor(targetClass, sourceClass) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Method getValueOfMethodOn(Class<?> targetClass, Class<?> sourceClass) {
|
private static Method getValueOfMethodOn(Class<?> targetClass, Class<?> sourceClass) {
|
||||||
|
|
|
||||||
|
|
@ -56,8 +56,7 @@ final class StringToArrayConverter implements ConditionalGenericConverter {
|
||||||
Object target = Array.newInstance(targetType.getElementType(), fields.length);
|
Object target = Array.newInstance(targetType.getElementType(), fields.length);
|
||||||
for (int i = 0; i < fields.length; i++) {
|
for (int i = 0; i < fields.length; i++) {
|
||||||
String sourceElement = fields[i];
|
String sourceElement = fields[i];
|
||||||
Object targetElement = this.conversionService.convert(sourceElement.trim(),
|
Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetType.getElementTypeDescriptor());
|
||||||
sourceType, targetType.getElementTypeDescriptor());
|
|
||||||
Array.set(target, i, targetElement);
|
Array.set(target, i, targetElement);
|
||||||
}
|
}
|
||||||
return target;
|
return target;
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,7 @@ final class StringToCharacterConverter implements Converter<String, Character> {
|
||||||
}
|
}
|
||||||
if (source.length() > 1) {
|
if (source.length() > 1) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Can only convert a [String] with length of 1 to a [Character]; string value '" + source
|
"Can only convert a [String] with length of 1 to a [Character]; string value '" + source + "' has length of " + source.length());
|
||||||
+ "' has length of " + source.length());
|
|
||||||
}
|
}
|
||||||
return source.charAt(0);
|
return source.charAt(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.springframework.core.GenericCollectionTypeResolver;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -61,6 +62,18 @@ public class TypeDescriptorTests {
|
||||||
|
|
||||||
public Map<String, List<Integer>> nestedMapField = new HashMap<String, List<Integer>>();
|
public Map<String, List<Integer>> nestedMapField = new HashMap<String, List<Integer>>();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nullTypeDescriptor() {
|
||||||
|
TypeDescriptor desc = TypeDescriptor.NULL;
|
||||||
|
assertEquals(false, desc.isMap());
|
||||||
|
assertEquals(false, desc.isCollection());
|
||||||
|
assertEquals(false, desc.isArray());
|
||||||
|
assertEquals(null, desc.getType());
|
||||||
|
assertEquals(null, desc.getObjectType());
|
||||||
|
assertEquals(null, desc.getName());
|
||||||
|
assertEquals(0, desc.getAnnotations().length);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void parameterPrimitive() throws Exception {
|
public void parameterPrimitive() throws Exception {
|
||||||
TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterPrimitive", int.class), 0));
|
TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterPrimitive", int.class), 0));
|
||||||
|
|
@ -70,14 +83,8 @@ public class TypeDescriptorTests {
|
||||||
assertEquals("int", desc.toString());
|
assertEquals("int", desc.toString());
|
||||||
assertTrue(desc.isPrimitive());
|
assertTrue(desc.isPrimitive());
|
||||||
assertEquals(0, desc.getAnnotations().length);
|
assertEquals(0, desc.getAnnotations().length);
|
||||||
assertTrue(!desc.isCollection());
|
assertFalse(desc.isCollection());
|
||||||
assertNull(desc.getElementType());
|
assertFalse(desc.isMap());
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getElementTypeDescriptor());
|
|
||||||
assertTrue(!desc.isMap());
|
|
||||||
assertNull(desc.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(desc.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testParameterPrimitive(int primitive) {
|
public void testParameterPrimitive(int primitive) {
|
||||||
|
|
@ -95,13 +102,7 @@ public class TypeDescriptorTests {
|
||||||
assertEquals(0, desc.getAnnotations().length);
|
assertEquals(0, desc.getAnnotations().length);
|
||||||
assertFalse(desc.isCollection());
|
assertFalse(desc.isCollection());
|
||||||
assertFalse(desc.isArray());
|
assertFalse(desc.isArray());
|
||||||
assertNull(desc.getElementType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getElementTypeDescriptor());
|
|
||||||
assertFalse(desc.isMap());
|
assertFalse(desc.isMap());
|
||||||
assertNull(desc.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(desc.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testParameterScalar(String value) {
|
public void testParameterScalar(String value) {
|
||||||
|
|
@ -127,10 +128,6 @@ public class TypeDescriptorTests {
|
||||||
assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapKeyTypeDescriptor().getType());
|
assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapKeyTypeDescriptor().getType());
|
||||||
assertEquals(Enum.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor().getType());
|
assertEquals(Enum.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor().getType());
|
||||||
assertFalse(desc.isMap());
|
assertFalse(desc.isMap());
|
||||||
assertNull(desc.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(desc.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testParameterList(List<List<Map<Integer, Enum<?>>>> list) {
|
public void testParameterList(List<List<Map<Integer, Enum<?>>>> list) {
|
||||||
|
|
@ -152,10 +149,6 @@ public class TypeDescriptorTests {
|
||||||
assertEquals(Object.class, desc.getElementType());
|
assertEquals(Object.class, desc.getElementType());
|
||||||
assertEquals(TypeDescriptor.valueOf(Object.class), desc.getElementTypeDescriptor());
|
assertEquals(TypeDescriptor.valueOf(Object.class), desc.getElementTypeDescriptor());
|
||||||
assertFalse(desc.isMap());
|
assertFalse(desc.isMap());
|
||||||
assertNull(desc.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(desc.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testParameterListNoParamTypes(List list) {
|
public void testParameterListNoParamTypes(List list) {
|
||||||
|
|
@ -176,11 +169,7 @@ public class TypeDescriptorTests {
|
||||||
assertTrue(desc.isArray());
|
assertTrue(desc.isArray());
|
||||||
assertEquals(Integer.class, desc.getElementType());
|
assertEquals(Integer.class, desc.getElementType());
|
||||||
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor());
|
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor());
|
||||||
assertTrue(!desc.isMap());
|
assertFalse(desc.isMap());
|
||||||
assertNull(desc.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(desc.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testParameterArray(Integer[] array) {
|
public void testParameterArray(Integer[] array) {
|
||||||
|
|
@ -199,8 +188,6 @@ public class TypeDescriptorTests {
|
||||||
assertEquals(0, desc.getAnnotations().length);
|
assertEquals(0, desc.getAnnotations().length);
|
||||||
assertFalse(desc.isCollection());
|
assertFalse(desc.isCollection());
|
||||||
assertFalse(desc.isArray());
|
assertFalse(desc.isArray());
|
||||||
assertNull(desc.getElementType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getElementTypeDescriptor());
|
|
||||||
assertTrue(desc.isMap());
|
assertTrue(desc.isMap());
|
||||||
assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueTypeDescriptor());
|
assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueTypeDescriptor());
|
||||||
assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueTypeDescriptor().getElementTypeDescriptor());
|
assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueTypeDescriptor().getElementTypeDescriptor());
|
||||||
|
|
@ -383,12 +370,6 @@ public class TypeDescriptorTests {
|
||||||
assertFalse(typeDescriptor.isMap());
|
assertFalse(typeDescriptor.isMap());
|
||||||
assertEquals(Integer.class, typeDescriptor.getType());
|
assertEquals(Integer.class, typeDescriptor.getType());
|
||||||
assertEquals(Integer.class, typeDescriptor.getObjectType());
|
assertEquals(Integer.class, typeDescriptor.getObjectType());
|
||||||
assertNull(typeDescriptor.getElementType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getElementTypeDescriptor());
|
|
||||||
assertNull(typeDescriptor.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(typeDescriptor.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer fieldScalar;
|
public Integer fieldScalar;
|
||||||
|
|
@ -488,12 +469,6 @@ public class TypeDescriptorTests {
|
||||||
assertFalse(typeDescriptor.isMap());
|
assertFalse(typeDescriptor.isMap());
|
||||||
assertEquals(Integer.class, typeDescriptor.getType());
|
assertEquals(Integer.class, typeDescriptor.getType());
|
||||||
assertEquals(Integer.class, typeDescriptor.getObjectType());
|
assertEquals(Integer.class, typeDescriptor.getObjectType());
|
||||||
assertNull(typeDescriptor.getElementType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getElementTypeDescriptor());
|
|
||||||
assertNull(typeDescriptor.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(typeDescriptor.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -505,12 +480,6 @@ public class TypeDescriptorTests {
|
||||||
assertFalse(typeDescriptor.isMap());
|
assertFalse(typeDescriptor.isMap());
|
||||||
assertEquals(Integer.TYPE, typeDescriptor.getType());
|
assertEquals(Integer.TYPE, typeDescriptor.getType());
|
||||||
assertEquals(Integer.class, typeDescriptor.getObjectType());
|
assertEquals(Integer.class, typeDescriptor.getObjectType());
|
||||||
assertNull(typeDescriptor.getElementType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getElementTypeDescriptor());
|
|
||||||
assertNull(typeDescriptor.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(typeDescriptor.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -520,10 +489,6 @@ public class TypeDescriptorTests {
|
||||||
assertFalse(typeDescriptor.isCollection());
|
assertFalse(typeDescriptor.isCollection());
|
||||||
assertFalse(typeDescriptor.isMap());
|
assertFalse(typeDescriptor.isMap());
|
||||||
assertEquals(Integer.TYPE, typeDescriptor.getElementType());
|
assertEquals(Integer.TYPE, typeDescriptor.getElementType());
|
||||||
assertNull(typeDescriptor.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(typeDescriptor.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -533,10 +498,6 @@ public class TypeDescriptorTests {
|
||||||
assertFalse(typeDescriptor.isArray());
|
assertFalse(typeDescriptor.isArray());
|
||||||
assertFalse(typeDescriptor.isMap());
|
assertFalse(typeDescriptor.isMap());
|
||||||
assertEquals(Object.class, typeDescriptor.getElementType());
|
assertEquals(Object.class, typeDescriptor.getElementType());
|
||||||
assertNull(typeDescriptor.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(typeDescriptor.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, typeDescriptor.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -734,10 +695,6 @@ public class TypeDescriptorTests {
|
||||||
assertEquals(Integer.class, desc.getElementType());
|
assertEquals(Integer.class, desc.getElementType());
|
||||||
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor());
|
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor());
|
||||||
assertFalse(desc.isMap());
|
assertFalse(desc.isMap());
|
||||||
assertNull(desc.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(desc.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -754,10 +711,6 @@ public class TypeDescriptorTests {
|
||||||
assertEquals(List.class, desc.getElementType());
|
assertEquals(List.class, desc.getElementType());
|
||||||
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor().getElementTypeDescriptor());
|
assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor().getElementTypeDescriptor());
|
||||||
assertFalse(desc.isMap());
|
assertFalse(desc.isMap());
|
||||||
assertNull(desc.getMapKeyType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapKeyTypeDescriptor());
|
|
||||||
assertNull(desc.getMapValueType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getMapValueTypeDescriptor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -771,8 +724,6 @@ public class TypeDescriptorTests {
|
||||||
assertEquals(0, desc.getAnnotations().length);
|
assertEquals(0, desc.getAnnotations().length);
|
||||||
assertFalse(desc.isCollection());
|
assertFalse(desc.isCollection());
|
||||||
assertFalse(desc.isArray());
|
assertFalse(desc.isArray());
|
||||||
assertNull(desc.getElementType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getElementTypeDescriptor());
|
|
||||||
assertTrue(desc.isMap());
|
assertTrue(desc.isMap());
|
||||||
assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
|
assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
|
||||||
assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getType());
|
assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getType());
|
||||||
|
|
@ -790,8 +741,6 @@ public class TypeDescriptorTests {
|
||||||
assertEquals(0, desc.getAnnotations().length);
|
assertEquals(0, desc.getAnnotations().length);
|
||||||
assertFalse(desc.isCollection());
|
assertFalse(desc.isCollection());
|
||||||
assertFalse(desc.isArray());
|
assertFalse(desc.isArray());
|
||||||
assertNull(desc.getElementType());
|
|
||||||
assertEquals(TypeDescriptor.NULL, desc.getElementTypeDescriptor());
|
|
||||||
assertTrue(desc.isMap());
|
assertTrue(desc.isMap());
|
||||||
assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
|
assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType());
|
||||||
assertEquals(String.class, desc.getMapValueTypeDescriptor().getMapKeyTypeDescriptor().getType());
|
assertEquals(String.class, desc.getMapValueTypeDescriptor().getMapKeyTypeDescriptor().getType());
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,18 @@ public class CollectionToCollectionConverterTests {
|
||||||
TypeDescriptor sourceType = TypeDescriptor.forObject(resources);
|
TypeDescriptor sourceType = TypeDescriptor.forObject(resources);
|
||||||
assertEquals(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources"))));
|
assertEquals(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources"))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=ConverterNotFoundException.class)
|
||||||
|
public void allNullsNotConvertible() throws Exception {
|
||||||
|
List<Resource> resources = new ArrayList<Resource>();
|
||||||
|
resources.add(null);
|
||||||
|
resources.add(null);
|
||||||
|
TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("allNullsNotConvertible"));
|
||||||
|
assertEquals(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> allNullsNotConvertible;
|
||||||
|
|
||||||
@Test(expected=ConverterNotFoundException.class)
|
@Test(expected=ConverterNotFoundException.class)
|
||||||
public void nothingInCommon() throws Exception {
|
public void nothingInCommon() throws Exception {
|
||||||
List<Object> resources = new ArrayList<Object>();
|
List<Object> resources = new ArrayList<Object>();
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,12 @@ public class GenericConversionServiceTests {
|
||||||
|
|
||||||
@Test(expected=ConversionFailedException.class)
|
@Test(expected=ConversionFailedException.class)
|
||||||
public void convertNullSourcePrimitiveTargetTypeDescriptor() {
|
public void convertNullSourcePrimitiveTargetTypeDescriptor() {
|
||||||
assertEquals(null, conversionService.convert(null, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(int.class)));
|
conversionService.convert(null, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(int.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=IllegalArgumentException.class)
|
||||||
|
public void convertNotNullSourceNullSourceTypeDescriptor() {
|
||||||
|
conversionService.convert("3", TypeDescriptor.NULL, TypeDescriptor.valueOf(int.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -129,6 +134,11 @@ public class GenericConversionServiceTests {
|
||||||
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), TypeDescriptor.NULL));
|
assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), TypeDescriptor.NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=IllegalArgumentException.class)
|
||||||
|
public void convertWrongSourceTypeDescriptor() {
|
||||||
|
conversionService.convert("3", TypeDescriptor.valueOf(Integer.class), TypeDescriptor.valueOf(Long.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void convertWrongTypeArgument() {
|
public void convertWrongTypeArgument() {
|
||||||
conversionService.addConverterFactory(new StringToNumberConverterFactory());
|
conversionService.addConverterFactory(new StringToNumberConverterFactory());
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@
|
||||||
|
|
||||||
package org.springframework.expression;
|
package org.springframework.expression;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.core.convert.TypeDescriptor;
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -31,12 +34,10 @@ public class TypedValue {
|
||||||
|
|
||||||
public static final TypedValue NULL = new TypedValue(null);
|
public static final TypedValue NULL = new TypedValue(null);
|
||||||
|
|
||||||
|
|
||||||
private final Object value;
|
private final Object value;
|
||||||
|
|
||||||
private TypeDescriptor typeDescriptor;
|
private TypeDescriptor typeDescriptor;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a TypedValue for a simple object. The type descriptor is inferred
|
* Create a TypedValue for a simple object. The type descriptor is inferred
|
||||||
* from the object, so no generic information is preserved.
|
* from the object, so no generic information is preserved.
|
||||||
|
|
@ -44,7 +45,8 @@ public class TypedValue {
|
||||||
*/
|
*/
|
||||||
public TypedValue(Object value) {
|
public TypedValue(Object value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.typeDescriptor = null; // initialized when/if requested
|
// initialized when/if requested
|
||||||
|
this.typeDescriptor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -54,10 +56,9 @@ public class TypedValue {
|
||||||
*/
|
*/
|
||||||
public TypedValue(Object value, TypeDescriptor typeDescriptor) {
|
public TypedValue(Object value, TypeDescriptor typeDescriptor) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.typeDescriptor = typeDescriptor;
|
this.typeDescriptor = initTypeDescriptor(value, typeDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
return this.value;
|
return this.value;
|
||||||
}
|
}
|
||||||
|
|
@ -69,12 +70,27 @@ public class TypedValue {
|
||||||
return this.typeDescriptor;
|
return this.typeDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder str = new StringBuilder();
|
StringBuilder str = new StringBuilder();
|
||||||
str.append("TypedValue: '").append(this.value).append("' of [").append(getTypeDescriptor() + "]");
|
str.append("TypedValue: '").append(this.value).append("' of [").append(getTypeDescriptor() + "]");
|
||||||
return str.toString();
|
return str.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interal helpers
|
||||||
|
|
||||||
|
private static TypeDescriptor initTypeDescriptor(Object value, TypeDescriptor typeDescriptor) {
|
||||||
|
if (value == null) {
|
||||||
|
return typeDescriptor;
|
||||||
|
}
|
||||||
|
if (typeDescriptor.isCollection() && Object.class.equals(typeDescriptor.getElementType())) {
|
||||||
|
return typeDescriptor.resolveCollectionElementType((Collection<?>) value);
|
||||||
|
} else if (typeDescriptor.isMap() && Object.class.equals(typeDescriptor.getMapKeyType())
|
||||||
|
&& Object.class.equals(typeDescriptor.getMapValueType())){
|
||||||
|
return typeDescriptor.resolveMapKeyValueTypes((Map<?, ?>) value);
|
||||||
|
} else {
|
||||||
|
return typeDescriptor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,13 +90,9 @@ public class Indexer extends SpelNodeImpl {
|
||||||
|
|
||||||
// Indexing into a Map
|
// Indexing into a Map
|
||||||
if (targetObject instanceof Map) {
|
if (targetObject instanceof Map) {
|
||||||
if (targetObjectTypeDescriptor.isMap()) {
|
Object possiblyConvertedKey = state.convertValue(index, targetObjectTypeDescriptor.getMapKeyTypeDescriptor());
|
||||||
Object possiblyConvertedKey = state.convertValue(index, targetObjectTypeDescriptor.getMapKeyTypeDescriptor());
|
Object o = ((Map<?, ?>) targetObject).get(possiblyConvertedKey);
|
||||||
Object o = ((Map<?, ?>) targetObject).get(possiblyConvertedKey);
|
return new TypedValue(o, targetObjectTypeDescriptor.getMapValueTypeDescriptor());
|
||||||
return new TypedValue(o, targetObjectTypeDescriptor.getMapValueTypeDescriptor());
|
|
||||||
} else {
|
|
||||||
return new TypedValue(((Map<?, ?>) targetObject).get(index));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetObject == null) {
|
if (targetObject == null) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
package org.springframework.expression.spel;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.expression.Expression;
|
||||||
|
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||||
|
|
||||||
|
public class IndexingTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void emptyList() {
|
||||||
|
listOfScalarNotGeneric = new ArrayList();
|
||||||
|
SpelExpressionParser parser = new SpelExpressionParser();
|
||||||
|
Expression expression = parser.parseExpression("listOfScalarNotGeneric");
|
||||||
|
assertEquals("java.util.List<java.lang.Object>", expression.getValueTypeDescriptor(this).toString());
|
||||||
|
assertEquals("", expression.getValue(this, String.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void resolveCollectionElementType() {
|
||||||
|
listNotGeneric = new ArrayList();
|
||||||
|
listNotGeneric.add(5);
|
||||||
|
listNotGeneric.add(6);
|
||||||
|
SpelExpressionParser parser = new SpelExpressionParser();
|
||||||
|
Expression expression = parser.parseExpression("listNotGeneric");
|
||||||
|
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.List<@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.lang.Integer>", expression.getValueTypeDescriptor(this).toString());
|
||||||
|
assertEquals("5,6", expression.getValue(this, String.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void resolveCollectionElementTypeNull() {
|
||||||
|
SpelExpressionParser parser = new SpelExpressionParser();
|
||||||
|
Expression expression = parser.parseExpression("listNotGeneric");
|
||||||
|
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.List<@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.lang.Object>", expression.getValueTypeDescriptor(this).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@FieldAnnotation
|
||||||
|
public List listNotGeneric;
|
||||||
|
|
||||||
|
@Target({ElementType.FIELD})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface FieldAnnotation {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void resolveMapKeyValueTypes() {
|
||||||
|
mapNotGeneric = new HashMap();
|
||||||
|
mapNotGeneric.put("baseAmount", 3.11);
|
||||||
|
mapNotGeneric.put("bonusAmount", 7.17);
|
||||||
|
SpelExpressionParser parser = new SpelExpressionParser();
|
||||||
|
Expression expression = parser.parseExpression("mapNotGeneric");
|
||||||
|
assertEquals("@org.springframework.expression.spel.IndexingTests$FieldAnnotation java.util.Map<java.lang.String, java.lang.Double>", expression.getValueTypeDescriptor(this).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@FieldAnnotation
|
||||||
|
public Map mapNotGeneric;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListOfScalar() {
|
||||||
|
listOfScalarNotGeneric = new ArrayList();
|
||||||
|
listOfScalarNotGeneric.add("5");
|
||||||
|
SpelExpressionParser parser = new SpelExpressionParser();
|
||||||
|
Expression expression = parser.parseExpression("listOfScalarNotGeneric[0]");
|
||||||
|
assertEquals(new Integer(5), expression.getValue(this, Integer.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List listOfScalarNotGeneric;
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListsOfMap() {
|
||||||
|
listOfMapsNotGeneric = new ArrayList();
|
||||||
|
Map map = new HashMap();
|
||||||
|
map.put("fruit", "apple");
|
||||||
|
listOfMapsNotGeneric.add(map);
|
||||||
|
SpelExpressionParser parser = new SpelExpressionParser();
|
||||||
|
Expression expression = parser.parseExpression("listOfMapsNotGeneric[0]['fruit']");
|
||||||
|
assertEquals("apple", expression.getValue(this, String.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public List listOfMapsNotGeneric;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,7 @@ import java.util.Map;
|
||||||
|
|
||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.expression.EvaluationContext;
|
import org.springframework.expression.EvaluationContext;
|
||||||
import org.springframework.expression.Expression;
|
import org.springframework.expression.Expression;
|
||||||
|
|
@ -205,14 +206,15 @@ public class SpelDocumentationTests extends ExpressionTestCase {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore
|
||||||
public void testDictionaryAccess() throws Exception {
|
public void testDictionaryAccess() throws Exception {
|
||||||
StandardEvaluationContext societyContext = new StandardEvaluationContext();
|
StandardEvaluationContext societyContext = new StandardEvaluationContext();
|
||||||
societyContext.setRootObject(new IEEE());
|
societyContext.setRootObject(new IEEE());
|
||||||
// Officer's Dictionary
|
// Officer's Dictionary
|
||||||
// Inventor pupin = parser.parseExpression("officers['president']").getValue(societyContext, Inventor.class);
|
Inventor pupin = parser.parseExpression("officers['president']").getValue(societyContext, Inventor.class);
|
||||||
//
|
|
||||||
// // evaluates to "Idvor"
|
// evaluates to "Idvor"
|
||||||
// String city = parser.parseExpression("officers['president'].PlaceOfBirth.city").getValue(societyContext, String.class);
|
String city = parser.parseExpression("officers['president'].PlaceOfBirth.city").getValue(societyContext, String.class);
|
||||||
|
|
||||||
// setting values
|
// setting values
|
||||||
Inventor i = parser.parseExpression("officers['advisors'][0]").getValue(societyContext,Inventor.class);
|
Inventor i = parser.parseExpression("officers['advisors'][0]").getValue(societyContext,Inventor.class);
|
||||||
|
|
|
||||||
|
|
@ -698,6 +698,7 @@ public class SpringEL300Tests extends ExpressionTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void testMapOfMap_SPR7244() throws Exception {
|
public void testMapOfMap_SPR7244() throws Exception {
|
||||||
Map<String,Object> map = new LinkedHashMap();
|
Map<String,Object> map = new LinkedHashMap();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue