|
|
|
@ -26,6 +26,7 @@ import org.springframework.core.GenericCollectionTypeResolver; |
|
|
|
import org.springframework.core.MethodParameter; |
|
|
|
import org.springframework.core.MethodParameter; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.util.ClassUtils; |
|
|
|
import org.springframework.util.ClassUtils; |
|
|
|
|
|
|
|
import org.springframework.util.ObjectUtils; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Context about a type to convert to. |
|
|
|
* Context about a type to convert to. |
|
|
|
@ -42,6 +43,7 @@ public class TypeDescriptor { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public static final TypeDescriptor NULL = new TypeDescriptor(); |
|
|
|
public static final TypeDescriptor NULL = new TypeDescriptor(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Class<?> type; |
|
|
|
private Class<?> type; |
|
|
|
|
|
|
|
|
|
|
|
private TypeDescriptor elementType; |
|
|
|
private TypeDescriptor elementType; |
|
|
|
@ -52,6 +54,7 @@ public class TypeDescriptor { |
|
|
|
|
|
|
|
|
|
|
|
private Annotation[] cachedFieldAnnotations; |
|
|
|
private Annotation[] cachedFieldAnnotations; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Create a new descriptor for the given type. |
|
|
|
* Create a new descriptor for the given type. |
|
|
|
* <p>Use this constructor when a conversion point comes from a source such as a Map |
|
|
|
* <p>Use this constructor when a conversion point comes from a source such as a Map |
|
|
|
@ -99,6 +102,7 @@ public class TypeDescriptor { |
|
|
|
this.elementType = elementType; |
|
|
|
this.elementType = elementType; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Return the wrapped MethodParameter, if any. |
|
|
|
* Return the wrapped MethodParameter, if any. |
|
|
|
* <p>Note: Either MethodParameter or Field is available. |
|
|
|
* <p>Note: Either MethodParameter or Field is available. |
|
|
|
@ -124,11 +128,14 @@ public class TypeDescriptor { |
|
|
|
public Class<?> getType() { |
|
|
|
public Class<?> getType() { |
|
|
|
if (this.type != null) { |
|
|
|
if (this.type != null) { |
|
|
|
return this.type; |
|
|
|
return this.type; |
|
|
|
} else if (this.field != null) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (this.field != null) { |
|
|
|
return this.field.getType(); |
|
|
|
return this.field.getType(); |
|
|
|
} else if (this.methodParameter != null) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (this.methodParameter != null) { |
|
|
|
return this.methodParameter.getParameterType(); |
|
|
|
return this.methodParameter.getParameterType(); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -139,7 +146,7 @@ public class TypeDescriptor { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Class<?> getObjectType() { |
|
|
|
public Class<?> getObjectType() { |
|
|
|
Class<?> type = getType(); |
|
|
|
Class<?> type = getType(); |
|
|
|
return type != null ? ClassUtils.resolvePrimitiveIfNecessary(type) : type; |
|
|
|
return (type != null ? ClassUtils.resolvePrimitiveIfNecessary(type) : type); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -147,8 +154,7 @@ public class TypeDescriptor { |
|
|
|
* @param type the type to test against |
|
|
|
* @param type the type to test against |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public boolean typeEquals(Class<?> type) { |
|
|
|
public boolean typeEquals(Class<?> type) { |
|
|
|
Class<?> thisType = getType(); |
|
|
|
return ObjectUtils.nullSafeEquals(getType(), type); |
|
|
|
return thisType != null ? thisType.equals(type) : false; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -158,7 +164,8 @@ public class TypeDescriptor { |
|
|
|
Class<?> type = getType(); |
|
|
|
Class<?> type = getType(); |
|
|
|
if (type != null) { |
|
|
|
if (type != null) { |
|
|
|
return getType().getName(); |
|
|
|
return getType().getName(); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -198,14 +205,17 @@ public class TypeDescriptor { |
|
|
|
* Return the element type as a type descriptor. |
|
|
|
* Return the element type as a type descriptor. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public TypeDescriptor getElementTypeDescriptor() { |
|
|
|
public TypeDescriptor getElementTypeDescriptor() { |
|
|
|
if (elementType != null) { |
|
|
|
if (this.elementType != null) { |
|
|
|
return elementType; |
|
|
|
return this.elementType; |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
if (isArray()) { |
|
|
|
if (isArray()) { |
|
|
|
return TypeDescriptor.valueOf(getArrayComponentType()); |
|
|
|
return TypeDescriptor.valueOf(getArrayComponentType()); |
|
|
|
} else if (isCollection()) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (isCollection()) { |
|
|
|
return TypeDescriptor.valueOf(getCollectionElementType()); |
|
|
|
return TypeDescriptor.valueOf(getCollectionElementType()); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
return TypeDescriptor.NULL; |
|
|
|
return TypeDescriptor.NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -232,9 +242,11 @@ public class TypeDescriptor { |
|
|
|
public Class<?> getMapKeyType() { |
|
|
|
public Class<?> getMapKeyType() { |
|
|
|
if (this.field != null) { |
|
|
|
if (this.field != null) { |
|
|
|
return GenericCollectionTypeResolver.getMapKeyFieldType(field); |
|
|
|
return GenericCollectionTypeResolver.getMapKeyFieldType(field); |
|
|
|
} else if (this.methodParameter != null) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (this.methodParameter != null) { |
|
|
|
return GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter); |
|
|
|
return GenericCollectionTypeResolver.getMapKeyParameterType(this.methodParameter); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -246,9 +258,11 @@ public class TypeDescriptor { |
|
|
|
public Class<?> getMapValueType() { |
|
|
|
public Class<?> getMapValueType() { |
|
|
|
if (this.field != null) { |
|
|
|
if (this.field != null) { |
|
|
|
return GenericCollectionTypeResolver.getMapValueFieldType(this.field); |
|
|
|
return GenericCollectionTypeResolver.getMapValueFieldType(this.field); |
|
|
|
} else if (this.methodParameter != null) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (this.methodParameter != null) { |
|
|
|
return GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter); |
|
|
|
return GenericCollectionTypeResolver.getMapValueParameterType(this.methodParameter); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -276,9 +290,11 @@ public class TypeDescriptor { |
|
|
|
this.cachedFieldAnnotations = this.field.getAnnotations(); |
|
|
|
this.cachedFieldAnnotations = this.field.getAnnotations(); |
|
|
|
} |
|
|
|
} |
|
|
|
return this.cachedFieldAnnotations; |
|
|
|
return this.cachedFieldAnnotations; |
|
|
|
} else if (this.methodParameter != null) { |
|
|
|
} |
|
|
|
|
|
|
|
else if (this.methodParameter != null) { |
|
|
|
return this.methodParameter.getParameterAnnotations(); |
|
|
|
return this.methodParameter.getParameterAnnotations(); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
return new Annotation[0]; |
|
|
|
return new Annotation[0]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -324,6 +340,28 @@ public class TypeDescriptor { |
|
|
|
return type != null && ClassUtils.isAssignable(targetType.getType(), type); |
|
|
|
return type != null && ClassUtils.isAssignable(targetType.getType(), type); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Class<?> getArrayComponentType() { |
|
|
|
|
|
|
|
return getType().getComponentType(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
|
|
|
|
private Class<?> getCollectionElementType() { |
|
|
|
|
|
|
|
if (this.type != null) { |
|
|
|
|
|
|
|
return GenericCollectionTypeResolver.getCollectionType((Class<? extends Collection>) this.type); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (this.field != null) { |
|
|
|
|
|
|
|
return GenericCollectionTypeResolver.getCollectionFieldType(this.field); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
return GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private boolean isTypeAssignableTo(Class<?> clazz) { |
|
|
|
|
|
|
|
Class<?> type = getType(); |
|
|
|
|
|
|
|
return (type != null && ClassUtils.isAssignable(clazz, type)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* @return a textual representation of the type descriptor (eg. Map<String,Foo>) for use in messages |
|
|
|
* @return a textual representation of the type descriptor (eg. Map<String,Foo>) for use in messages |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -332,7 +370,8 @@ public class TypeDescriptor { |
|
|
|
if (isArray()) { |
|
|
|
if (isArray()) { |
|
|
|
// TODO should properly handle multi dimensional arrays
|
|
|
|
// TODO should properly handle multi dimensional arrays
|
|
|
|
stringValue.append(getArrayComponentType().getName()).append("[]"); |
|
|
|
stringValue.append(getArrayComponentType().getName()).append("[]"); |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
Class<?> clazz = getType(); |
|
|
|
Class<?> clazz = getType(); |
|
|
|
if (clazz == null) { |
|
|
|
if (clazz == null) { |
|
|
|
return "null"; |
|
|
|
return "null"; |
|
|
|
@ -355,27 +394,23 @@ public class TypeDescriptor { |
|
|
|
return stringValue.toString(); |
|
|
|
return stringValue.toString(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// internal helpers
|
|
|
|
public String toString() { |
|
|
|
|
|
|
|
if (this == TypeDescriptor.NULL) { |
|
|
|
private Class<?> getArrayComponentType() { |
|
|
|
return "[TypeDescriptor.NULL]"; |
|
|
|
return getType().getComponentType(); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
|
|
|
|
StringBuilder builder = new StringBuilder(); |
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
builder.append("[TypeDescriptor "); |
|
|
|
private Class<?> getCollectionElementType() { |
|
|
|
Annotation[] anns = getAnnotations(); |
|
|
|
if (this.type != null) { |
|
|
|
for (Annotation ann : anns) { |
|
|
|
return GenericCollectionTypeResolver.getCollectionType((Class<? extends Collection>) this.type); |
|
|
|
builder.append("@").append(ann.annotationType().getName()).append(' '); |
|
|
|
} else if (this.field != null) { |
|
|
|
} |
|
|
|
return GenericCollectionTypeResolver.getCollectionFieldType(this.field); |
|
|
|
builder.append(getType().getName()); |
|
|
|
} else { |
|
|
|
builder.append("]"); |
|
|
|
return GenericCollectionTypeResolver.getCollectionParameterType(this.methodParameter); |
|
|
|
return builder.toString(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private boolean isTypeAssignableTo(Class<?> clazz) { |
|
|
|
|
|
|
|
Class<?> type = getType(); |
|
|
|
|
|
|
|
return (type != null && ClassUtils.isAssignable(clazz, type)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// static factory methods
|
|
|
|
// static factory methods
|
|
|
|
|
|
|
|
|
|
|
|
@ -406,21 +441,5 @@ public class TypeDescriptor { |
|
|
|
public static TypeDescriptor collection(Class<?> type, TypeDescriptor elementType) { |
|
|
|
public static TypeDescriptor collection(Class<?> type, TypeDescriptor elementType) { |
|
|
|
return new TypeDescriptor(type, elementType); |
|
|
|
return new TypeDescriptor(type, elementType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public String toString() { |
|
|
|
|
|
|
|
if (this == TypeDescriptor.NULL) { |
|
|
|
|
|
|
|
return "[TypeDescriptor.NULL]"; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
StringBuilder builder = new StringBuilder(); |
|
|
|
|
|
|
|
builder.append("[TypeDescriptor "); |
|
|
|
|
|
|
|
Annotation[] anns = getAnnotations(); |
|
|
|
|
|
|
|
for (Annotation ann : anns) { |
|
|
|
|
|
|
|
builder.append("@" + ann.annotationType().getName()).append(' '); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
builder.append(getType().getName()); |
|
|
|
|
|
|
|
builder.append("]"); |
|
|
|
|
|
|
|
return builder.toString(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|