Fixed regression with constructing TypeDescriptor from null Class

Issue: SPR-11354
This commit is contained in:
Juergen Hoeller 2014-01-24 13:16:35 +01:00
parent 42db41e007
commit eeae5fba95
2 changed files with 39 additions and 16 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -306,6 +306,28 @@ public class FormattingConversionServiceTests {
TypeDescriptor.valueOf(String.class)); TypeDescriptor.valueOf(String.class));
} }
@Test
public void testRegisterDefaultValueViaFormatter() {
registerDefaultValue(Date.class, new Date());
}
private <T> void registerDefaultValue(Class<T> clazz, final T defaultValue) {
formattingService.addFormatterForFieldType(clazz, new Formatter<T>() {
@Override
public T parse(String text, Locale locale) throws ParseException {
return defaultValue;
}
@Override
public String print(T t, Locale locale) {
return defaultValue.toString();
}
@Override
public String toString() {
return defaultValue.toString();
}
});
}
public static class ValueBean { public static class ValueBean {

View File

@ -47,10 +47,10 @@ public class TypeDescriptor implements Serializable {
private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<Class<?>, TypeDescriptor>(); private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<Class<?>, TypeDescriptor>();
private static final Class<?>[] CACHED_COMMON_TYPES = {Boolean.class, byte.class, private static final Class<?>[] CACHED_COMMON_TYPES = {
Byte.class, char.class, Character.class, short.class, Short.class, int.class, boolean.class, Boolean.class, byte.class, Byte.class, char.class, Character.class,
Integer.class, long.class, Long.class, float.class, Float.class, double.class, double.class, Double.class, int.class, Integer.class, long.class, Long.class,
Double.class, String.class}; float.class, Float.class, short.class, Short.class, String.class, Object.class};
static { static {
for (Class<?> preCachedClass : CACHED_COMMON_TYPES) { for (Class<?> preCachedClass : CACHED_COMMON_TYPES) {
@ -125,7 +125,7 @@ public class TypeDescriptor implements Serializable {
private Annotation[] nullSafeAnnotations(Annotation[] annotations) { private Annotation[] nullSafeAnnotations(Annotation[] annotations) {
return annotations != null ? annotations : EMPTY_ANNOTATION_ARRAY; return (annotations != null ? annotations : EMPTY_ANNOTATION_ARRAY);
} }
/** /**
@ -500,11 +500,13 @@ public class TypeDescriptor implements Serializable {
* field is available to provide additional conversion context. * field is available to provide additional conversion context.
* <p>Generally prefer use of {@link #forObject(Object)} for constructing type * <p>Generally prefer use of {@link #forObject(Object)} for constructing type
* descriptors from source objects, as it handles the {@code null} object case. * descriptors from source objects, as it handles the {@code null} object case.
* @param type the class * @param type the class (may be {@code null} to indicate {@code Object.class})
* @return the type descriptor * @return the corresponding type descriptor
*/ */
public static TypeDescriptor valueOf(Class<?> type) { public static TypeDescriptor valueOf(Class<?> type) {
Assert.notNull(type, "Type must not be null"); if (type == null) {
type = Object.class;
}
TypeDescriptor desc = commonTypesCache.get(type); TypeDescriptor desc = commonTypesCache.get(type);
return (desc != null ? desc : new TypeDescriptor(ResolvableType.forClass(type), null, null)); return (desc != null ? desc : new TypeDescriptor(ResolvableType.forClass(type), null, null));
} }
@ -522,12 +524,11 @@ public class TypeDescriptor implements Serializable {
* @return the collection type descriptor * @return the collection type descriptor
*/ */
public static TypeDescriptor collection(Class<?> collectionType, TypeDescriptor elementTypeDescriptor) { public static TypeDescriptor collection(Class<?> collectionType, TypeDescriptor elementTypeDescriptor) {
Assert.notNull(collectionType, "CollectionType must not be null"); Assert.notNull(collectionType, "collectionType must not be null");
if (!Collection.class.isAssignableFrom(collectionType)) { if (!Collection.class.isAssignableFrom(collectionType)) {
throw new IllegalArgumentException("collectionType must be a java.util.Collection"); throw new IllegalArgumentException("collectionType must be a java.util.Collection");
} }
ResolvableType element = (elementTypeDescriptor == null ? null ResolvableType element = (elementTypeDescriptor != null ? elementTypeDescriptor.resolvableType : null);
: elementTypeDescriptor.resolvableType);
return new TypeDescriptor(ResolvableType.forClassWithGenerics(collectionType, element), null, null); return new TypeDescriptor(ResolvableType.forClassWithGenerics(collectionType, element), null, null);
} }
@ -549,8 +550,8 @@ public class TypeDescriptor implements Serializable {
if (!Map.class.isAssignableFrom(mapType)) { if (!Map.class.isAssignableFrom(mapType)) {
throw new IllegalArgumentException("mapType must be a java.util.Map"); throw new IllegalArgumentException("mapType must be a java.util.Map");
} }
ResolvableType key = (keyTypeDescriptor == null ? null : keyTypeDescriptor.resolvableType); ResolvableType key = (keyTypeDescriptor != null ? keyTypeDescriptor.resolvableType : null);
ResolvableType value = (valueTypeDescriptor == null ? null : valueTypeDescriptor.resolvableType); ResolvableType value = (valueTypeDescriptor != null ? valueTypeDescriptor.resolvableType : null);
return new TypeDescriptor(ResolvableType.forClassWithGenerics(mapType, key, value), null, null); return new TypeDescriptor(ResolvableType.forClassWithGenerics(mapType, key, value), null, null);
} }
@ -655,8 +656,8 @@ public class TypeDescriptor implements Serializable {
* Create a new type descriptor for an object. * Create a new type descriptor for an object.
* <p>Use this factory method to introspect a source object before asking the * <p>Use this factory method to introspect a source object before asking the
* conversion system to convert it to some another type. * conversion system to convert it to some another type.
* <p>If the provided object is null, returns null, else calls {@link #valueOf(Class)} * <p>If the provided object is {@code null}, returns {@code null}, else calls
* to build a TypeDescriptor from the object's class. * {@link #valueOf(Class)} to build a TypeDescriptor from the object's class.
* @param source the source object * @param source the source object
* @return the type descriptor * @return the type descriptor
*/ */