, TypeDescriptor>(18);
static {
typeDescriptorCache.put(boolean.class, new TypeDescriptor(boolean.class));
typeDescriptorCache.put(Boolean.class, new TypeDescriptor(Boolean.class));
typeDescriptorCache.put(byte.class, new TypeDescriptor(byte.class));
typeDescriptorCache.put(Byte.class, new TypeDescriptor(Byte.class));
typeDescriptorCache.put(char.class, new TypeDescriptor(char.class));
typeDescriptorCache.put(Character.class, new TypeDescriptor(Character.class));
typeDescriptorCache.put(double.class, new TypeDescriptor(double.class));
typeDescriptorCache.put(Double.class, new TypeDescriptor(Double.class));
typeDescriptorCache.put(int.class, new TypeDescriptor(int.class));
typeDescriptorCache.put(Integer.class, new TypeDescriptor(Integer.class));
typeDescriptorCache.put(long.class, new TypeDescriptor(long.class));
typeDescriptorCache.put(Long.class, new TypeDescriptor(Long.class));
typeDescriptorCache.put(float.class, new TypeDescriptor(float.class));
typeDescriptorCache.put(Float.class, new TypeDescriptor(Float.class));
typeDescriptorCache.put(short.class, new TypeDescriptor(short.class));
typeDescriptorCache.put(Short.class, new TypeDescriptor(Short.class));
typeDescriptorCache.put(String.class, new TypeDescriptor(String.class));
typeDescriptorCache.put(Object.class, new TypeDescriptor(Object.class));
}
private final Class type;
private final TypeDescriptor elementTypeDescriptor;
private final TypeDescriptor mapKeyTypeDescriptor;
private final TypeDescriptor mapValueTypeDescriptor;
private final Annotation[] annotations;
/**
* Create a new type descriptor from a {@link MethodParameter}.
* Use this constructor when a source or target conversion point is a
* constructor parameter, method parameter, or method return value.
* @param methodParameter the method parameter
*/
public TypeDescriptor(MethodParameter methodParameter) {
this(new ParameterDescriptor(methodParameter));
}
/**
* Create a new type descriptor from a {@link Field}.
*
Use this constructor when a source or target conversion point is a field.
* @param field the field
*/
public TypeDescriptor(Field field) {
this(new FieldDescriptor(field));
}
/**
* Create a new type descriptor from a {@link Property}.
*
Use this constructor when a source or target conversion point is a
* property on a Java class.
* @param property the property
*/
public TypeDescriptor(Property property) {
this(new BeanPropertyDescriptor(property));
}
/**
* Create a new type descriptor from the given type.
*
Use this to instruct the conversion system to convert an object to a
* specific target type, when no type location such as a method parameter or
* field is available to provide additional conversion context.
*
Generally prefer use of {@link #forObject(Object)} for constructing type
* descriptors from source objects, as it handles the {@code null} object case.
* @param type the class
* @return the type descriptor
*/
public static TypeDescriptor valueOf(Class type) {
if (type == null) {
type = Object.class;
}
TypeDescriptor desc = typeDescriptorCache.get(type);
return (desc != null ? desc : new TypeDescriptor(type));
}
/**
* Create a new type descriptor from a {@link java.util.Collection} type.
*
Useful for converting to typed Collections.
*
For example, a {@code List} could be converted to a
* {@code List} by converting to a targetType built with this method.
* The method call to construct such a {@code TypeDescriptor} would look something
* like: {@code collection(List.class, TypeDescriptor.valueOf(EmailAddress.class));}
* @param collectionType the collection type, which must implement {@link Collection}.
* @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 elementTypeDescriptor) {
if (!Collection.class.isAssignableFrom(collectionType)) {
throw new IllegalArgumentException("collectionType must be a java.util.Collection");
}
return new TypeDescriptor(collectionType, elementTypeDescriptor);
}
/**
* Create a new type descriptor from a {@link java.util.Map} type.
* Useful for converting to typed Maps.
*
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 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 keyTypeDescriptor, TypeDescriptor valueTypeDescriptor) {
if (!Map.class.isAssignableFrom(mapType)) {
throw new IllegalArgumentException("mapType must be a java.util.Map");
}
return new TypeDescriptor(mapType, keyTypeDescriptor, valueTypeDescriptor);
}
/**
* Create a new type descriptor as an array of the specified type.
*
For example to create a {@code Map[]} use
* {@code TypeDescriptor.array(TypeDescriptor.map(Map.class, TypeDescriptor.value(String.class), TypeDescriptor.value(String.class)))}.
* @param elementTypeDescriptor the {@link TypeDescriptor} of the array element or {@code null}
* @return an array {@link TypeDescriptor} or {@code null} if {@code elementTypeDescriptor} is {@code null}
* @since 3.2.1
*/
public static TypeDescriptor array(TypeDescriptor elementTypeDescriptor) {
if (elementTypeDescriptor == null) {
return null;
}
Class type = Array.newInstance(elementTypeDescriptor.getType(), 0).getClass();
return new TypeDescriptor(type, elementTypeDescriptor, null, null, elementTypeDescriptor.getAnnotations());
}
/**
* Creates a type descriptor for a nested type declared within the method parameter.
* For example, if the methodParameter is a {@code List} and the
* nesting level is 1, the nested type descriptor will be String.class.
* If the methodParameter is a {@code List>} and the nesting
* level is 2, the nested type descriptor will also be a String.class.
* If the methodParameter is a {@code Map} and the nesting
* level is 1, the nested type descriptor will be String, derived from the map value.
* If the methodParameter is a {@code List