removed custom converter for m3 to add back in rc1; also ensure type descriptor get type always returns wrapper types if primitive
This commit is contained in:
parent
b988f1a539
commit
ebb203a251
|
|
@ -54,21 +54,6 @@ public interface ConversionService {
|
||||||
public Object executeConversion(Object source, TypeDescriptor targetType) throws ConversionExecutorNotFoundException,
|
public Object executeConversion(Object source, TypeDescriptor targetType) throws ConversionExecutorNotFoundException,
|
||||||
ConversionException;
|
ConversionException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the source to targetType using a custom converter.
|
|
||||||
* @param converterId the id of the custom converter, which must be registered with this conversion service and
|
|
||||||
* capable of converting to the targetType
|
|
||||||
* @param source the source to convert from (may be null)
|
|
||||||
* @param targetType the target type to convert to
|
|
||||||
* @return the converted object, an instance of the <code>targetType</code>, or <code>null</code> if a null source
|
|
||||||
* was provided
|
|
||||||
* @throws ConversionExecutorNotFoundException if no suitable conversion executor could be found to convert the
|
|
||||||
* source to an instance of targetType
|
|
||||||
* @throws ConversionException if an exception occurred during the conversion process
|
|
||||||
*/
|
|
||||||
public Object executeConversion(String converterId, Object source, TypeDescriptor targetType)
|
|
||||||
throws ConversionExecutorNotFoundException, ConversionException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a ConversionExecutor that converts objects from sourceType to targetType.
|
* Get a ConversionExecutor that converts objects from sourceType to targetType.
|
||||||
* The returned ConversionExecutor is thread-safe and may safely be cached for later use by client code.
|
* The returned ConversionExecutor is thread-safe and may safely be cached for later use by client code.
|
||||||
|
|
@ -80,19 +65,6 @@ public interface ConversionService {
|
||||||
public ConversionExecutor getConversionExecutor(Class<?> sourceType, TypeDescriptor targetType)
|
public ConversionExecutor getConversionExecutor(Class<?> sourceType, TypeDescriptor targetType)
|
||||||
throws ConversionExecutorNotFoundException;
|
throws ConversionExecutorNotFoundException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a ConversionExecutor that converts objects from from sourceType to targetType using a custom converter.
|
|
||||||
* The returned ConversionExecutor is thread-safe and may safely be cached for use in client code.
|
|
||||||
* @param converterId the id of the custom converter, which must be registered with this conversion service and
|
|
||||||
* capable of converting from sourceType to targetType (required)
|
|
||||||
* @param sourceType the source type to convert from (required)
|
|
||||||
* @param targetType the target type to convert to (required)
|
|
||||||
* @return the executor that can execute instance type conversion, never null
|
|
||||||
* @throws ConversionExecutorNotFoundException when no suitable conversion executor could be found
|
|
||||||
*/
|
|
||||||
public ConversionExecutor getConversionExecutor(String converterId, Class<?> sourceType,
|
|
||||||
TypeDescriptor targetType) throws ConversionExecutorNotFoundException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a type by its name; may be the fully-qualified class name or a registered type alias such as 'int'.
|
* Get a type by its name; may be the fully-qualified class name or a registered type alias such as 'int'.
|
||||||
* @return the class, or <code>null</code> if no such name exists
|
* @return the class, or <code>null</code> if no such name exists
|
||||||
|
|
|
||||||
|
|
@ -31,13 +31,11 @@ import org.springframework.util.Assert;
|
||||||
*
|
*
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
* @author Andy Clement
|
* @author Andy Clement
|
||||||
*
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
*/
|
||||||
public class TypeDescriptor {
|
public class TypeDescriptor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constant value typeDescriptor for the type of a null value
|
* Constant value typeDescriptor for the type of a null value
|
||||||
*/
|
*/
|
||||||
public final static TypeDescriptor NULL_TYPE_DESCRIPTOR = new TypeDescriptor((Class<?>) null);
|
public final static TypeDescriptor NULL_TYPE_DESCRIPTOR = new TypeDescriptor((Class<?>) null);
|
||||||
|
|
||||||
|
|
@ -84,50 +82,16 @@ public class TypeDescriptor {
|
||||||
*/
|
*/
|
||||||
public Class<?> getType() {
|
public Class<?> getType() {
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
return type;
|
return wrapperType(type);
|
||||||
} else if (field != null) {
|
} else if (field != null) {
|
||||||
return field.getType();
|
return wrapperType(field.getType());
|
||||||
} else if (methodParameter != null) {
|
} else if (methodParameter != null) {
|
||||||
return methodParameter.getParameterType();
|
return wrapperType(methodParameter.getParameterType());
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If the actual type is a primitive, returns its wrapper type, else just returns {@link #getType()}.
|
|
||||||
* @return the wrapper type if the underlying type is a primitive, else the actual type as-is
|
|
||||||
*/
|
|
||||||
public Class<?> getWrapperTypeIfPrimitive() {
|
|
||||||
Class<?> type = getType();
|
|
||||||
if (type == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (type.isPrimitive()) {
|
|
||||||
if (type.equals(int.class)) {
|
|
||||||
return Integer.class;
|
|
||||||
} else if (type.equals(short.class)) {
|
|
||||||
return Short.class;
|
|
||||||
} else if (type.equals(long.class)) {
|
|
||||||
return Long.class;
|
|
||||||
} else if (type.equals(float.class)) {
|
|
||||||
return Float.class;
|
|
||||||
} else if (type.equals(double.class)) {
|
|
||||||
return Double.class;
|
|
||||||
} else if (type.equals(byte.class)) {
|
|
||||||
return Byte.class;
|
|
||||||
} else if (type.equals(boolean.class)) {
|
|
||||||
return Boolean.class;
|
|
||||||
} else if (type.equals(char.class)) {
|
|
||||||
return Character.class;
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Should never happen - primitive type is not a primitive?");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of this type; the fully qualified classname.
|
* Returns the name of this type; the fully qualified classname.
|
||||||
*/
|
*/
|
||||||
|
|
@ -343,7 +307,33 @@ public class TypeDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal helpers
|
// internal helpers
|
||||||
|
|
||||||
|
private Class<?> wrapperType(Class<?> type) {
|
||||||
|
if (type.isPrimitive()) {
|
||||||
|
if (type.equals(int.class)) {
|
||||||
|
return Integer.class;
|
||||||
|
} else if (type.equals(short.class)) {
|
||||||
|
return Short.class;
|
||||||
|
} else if (type.equals(long.class)) {
|
||||||
|
return Long.class;
|
||||||
|
} else if (type.equals(float.class)) {
|
||||||
|
return Float.class;
|
||||||
|
} else if (type.equals(double.class)) {
|
||||||
|
return Double.class;
|
||||||
|
} else if (type.equals(byte.class)) {
|
||||||
|
return Byte.class;
|
||||||
|
} else if (type.equals(boolean.class)) {
|
||||||
|
return Boolean.class;
|
||||||
|
} else if (type.equals(char.class)) {
|
||||||
|
return Character.class;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Should never happen - primitive type is not a primitive?");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Class<?> getArrayComponentType() {
|
private Class<?> getArrayComponentType() {
|
||||||
return getType().getComponentType();
|
return getType().getComponentType();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,21 +51,15 @@ public class GenericConversionService implements ConversionService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An indexed map of Converters. Each Map.Entry key is a source class (S) that can be converted from. Each Map.Entry
|
* An indexed map of Converters. Each Map.Entry key is a source class (S) that can be converted from. Each Map.Entry
|
||||||
* value is a Map that defines the targetClass-to-Converter mappings for that source.
|
* value is a Map that defines the targetType-to-Converter mappings for that source.
|
||||||
*/
|
*/
|
||||||
private final Map sourceClassConverters = new HashMap();
|
private final Map sourceTypeConverters = new HashMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An indexed map of SuperConverters. Each Map.Entry key is a source class (S) that can be converted from. Each
|
* An indexed map of SuperConverters. Each Map.Entry key is a source class (S) that can be converted from. Each
|
||||||
* Map.Entry value is a Map that defines the targetClass-to-SuperConverter mappings for that source.
|
* Map.Entry value is a Map that defines the targetType-to-SuperConverter mappings for that source.
|
||||||
*/
|
*/
|
||||||
private final Map sourceClassSuperConverters = new HashMap();
|
private final Map sourceTypeSuperConverters = new HashMap();
|
||||||
|
|
||||||
/**
|
|
||||||
* A map of custom converters. Custom converters are assigned a unique identifier that can be used to lookup the
|
|
||||||
* converter. This allows multiple converters for the same source->target class to be registered.
|
|
||||||
*/
|
|
||||||
private final Map customConverters = new HashMap();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indexes classes by well-known aliases.
|
* Indexes classes by well-known aliases.
|
||||||
|
|
@ -97,14 +91,14 @@ public class GenericConversionService implements ConversionService {
|
||||||
*/
|
*/
|
||||||
public void addConverter(Converter converter) {
|
public void addConverter(Converter converter) {
|
||||||
List typeInfo = getRequiredTypeInfo(converter);
|
List typeInfo = getRequiredTypeInfo(converter);
|
||||||
Class sourceClass = (Class) typeInfo.get(0);
|
Class sourceType = (Class) typeInfo.get(0);
|
||||||
Class targetClass = (Class) typeInfo.get(1);
|
Class targetType = (Class) typeInfo.get(1);
|
||||||
// index forward
|
// index forward
|
||||||
Map sourceMap = getSourceMap(sourceClass);
|
Map sourceMap = getSourceMap(sourceType);
|
||||||
sourceMap.put(targetClass, converter);
|
sourceMap.put(targetType, converter);
|
||||||
// index reverse
|
// index reverse
|
||||||
sourceMap = getSourceMap(targetClass);
|
sourceMap = getSourceMap(targetType);
|
||||||
sourceMap.put(sourceClass, new ReverseConverter(converter));
|
sourceMap.put(sourceType, new ReverseConverter(converter));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -113,38 +107,29 @@ public class GenericConversionService implements ConversionService {
|
||||||
*/
|
*/
|
||||||
public void addConverter(SuperConverter converter) {
|
public void addConverter(SuperConverter converter) {
|
||||||
List typeInfo = getRequiredTypeInfo(converter);
|
List typeInfo = getRequiredTypeInfo(converter);
|
||||||
Class sourceClass = (Class) typeInfo.get(0);
|
Class sourceType = (Class) typeInfo.get(0);
|
||||||
Class targetClass = (Class) typeInfo.get(1);
|
Class targetType = (Class) typeInfo.get(1);
|
||||||
// index forward
|
// index forward
|
||||||
Map sourceMap = getSourceSuperConverterMap(sourceClass);
|
Map sourceMap = getSourceSuperConverterMap(sourceType);
|
||||||
sourceMap.put(targetClass, converter);
|
sourceMap.put(targetType, converter);
|
||||||
if (converter instanceof SuperTwoWayConverter) {
|
if (converter instanceof SuperTwoWayConverter) {
|
||||||
// index reverse
|
// index reverse
|
||||||
sourceMap = getSourceSuperConverterMap(targetClass);
|
sourceMap = getSourceSuperConverterMap(targetType);
|
||||||
sourceMap.put(sourceClass, new ReverseSuperConverter((SuperTwoWayConverter) converter));
|
sourceMap.put(sourceType, new ReverseSuperConverter((SuperTwoWayConverter) converter));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Register the converter as a custom converter with this conversion service.
|
|
||||||
* @param id the id to assign the converter
|
|
||||||
* @param converter the converter to use a custom converter
|
|
||||||
*/
|
|
||||||
public void addConverter(String id, Converter converter) {
|
|
||||||
customConverters.put(id, converter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adapts a {@link SuperTwoWayConverter} that converts between BS and BT class hierarchies to a {@link Converter}
|
* Adapts a {@link SuperTwoWayConverter} that converts between BS and BT class hierarchies to a {@link Converter}
|
||||||
* that converts between the specific BS/BT sub types S and T.
|
* that converts between the specific BS/BT sub types S and T.
|
||||||
* @param sourceClass the source class S to convert from, which must be equal or extend BS
|
* @param sourceType the source class S to convert from, which must be equal or extend BS
|
||||||
* @param targetClass the target type T to convert to, which must equal or extend BT
|
* @param targetType the target type T to convert to, which must equal or extend BT
|
||||||
* @param converter the super two way converter
|
* @param converter the super two way converter
|
||||||
* @return a converter that converts from S to T by delegating to the super converter
|
* @return a converter that converts from S to T by delegating to the super converter
|
||||||
*/
|
*/
|
||||||
public static <S, T> Converter<S, T> converterFor(Class<S> sourceClass, Class<T> targetClass,
|
public static <S, T> Converter<S, T> converterFor(Class<S> sourceType, Class<T> targetType,
|
||||||
SuperTwoWayConverter converter) {
|
SuperTwoWayConverter converter) {
|
||||||
return new SuperTwoWayConverterConverter(converter, sourceClass, targetClass);
|
return new SuperTwoWayConverterConverter(converter, sourceType, targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -158,12 +143,25 @@ public class GenericConversionService implements ConversionService {
|
||||||
|
|
||||||
// implementing ConversionService
|
// implementing ConversionService
|
||||||
|
|
||||||
public boolean canConvert(Class<?> source, TypeDescriptor targetType) {
|
public boolean canConvert(Class<?> sourceType, TypeDescriptor targetType) {
|
||||||
return false;
|
try {
|
||||||
|
getConversionExecutor(sourceType, targetType);
|
||||||
|
return true;
|
||||||
|
} catch (ConversionExecutorNotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canConvert(Object source, TypeDescriptor targetType) {
|
public boolean canConvert(Object source, TypeDescriptor targetType) {
|
||||||
return false;
|
if (source == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
getConversionExecutor(source.getClass(), targetType);
|
||||||
|
return true;
|
||||||
|
} catch (ConversionExecutorNotFoundException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object executeConversion(Object source, TypeDescriptor targetType)
|
public Object executeConversion(Object source, TypeDescriptor targetType)
|
||||||
|
|
@ -174,14 +172,6 @@ public class GenericConversionService implements ConversionService {
|
||||||
return getConversionExecutor(source.getClass(), targetType).execute(source);
|
return getConversionExecutor(source.getClass(), targetType).execute(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object executeConversion(String converterId, Object source, TypeDescriptor targetType)
|
|
||||||
throws ConversionExecutorNotFoundException, ConversionException {
|
|
||||||
if (source == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return getConversionExecutor(converterId, source.getClass(), targetType).execute(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ConversionExecutor getConversionExecutor(Class sourceClass, TypeDescriptor targetType)
|
public ConversionExecutor getConversionExecutor(Class sourceClass, TypeDescriptor targetType)
|
||||||
throws ConversionExecutorNotFoundException {
|
throws ConversionExecutorNotFoundException {
|
||||||
Assert.notNull(sourceClass, "The sourceType to convert from is required");
|
Assert.notNull(sourceClass, "The sourceType to convert from is required");
|
||||||
|
|
@ -220,11 +210,11 @@ public class GenericConversionService implements ConversionService {
|
||||||
throw new UnsupportedOperationException("Object to Map conversion not yet supported");
|
throw new UnsupportedOperationException("Object to Map conversion not yet supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Converter converter = findRegisteredConverter(sourceType, targetType);
|
Converter converter = findRegisteredConverter(sourceClass, targetType.getType());
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
return new StaticConversionExecutor(sourceType, targetType, converter);
|
return new StaticConversionExecutor(sourceType, targetType, converter);
|
||||||
} else {
|
} else {
|
||||||
SuperConverter superConverter = findRegisteredSuperConverter(sourceType, targetType);
|
SuperConverter superConverter = findRegisteredSuperConverter(sourceClass, targetType.getType());
|
||||||
if (superConverter != null) {
|
if (superConverter != null) {
|
||||||
return new StaticSuperConversionExecutor(sourceType, targetType, superConverter);
|
return new StaticSuperConversionExecutor(sourceType, targetType, superConverter);
|
||||||
}
|
}
|
||||||
|
|
@ -241,11 +231,6 @@ public class GenericConversionService implements ConversionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConversionExecutor getConversionExecutor(String converterId, Class sourceType,
|
|
||||||
TypeDescriptor targetType) throws ConversionExecutorNotFoundException {
|
|
||||||
throw new UnsupportedOperationException("Not yet implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class getType(String name) throws IllegalArgumentException {
|
public Class getType(String name) throws IllegalArgumentException {
|
||||||
Class clazz = (Class) aliasMap.get(name);
|
Class clazz = (Class) aliasMap.get(name);
|
||||||
if (clazz != null) {
|
if (clazz != null) {
|
||||||
|
|
@ -305,34 +290,32 @@ public class GenericConversionService implements ConversionService {
|
||||||
+ "] on Converter [" + converterClass.getName() + "]");
|
+ "] on Converter [" + converterClass.getName() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map getSourceMap(Class sourceClass) {
|
private Map getSourceMap(Class sourceType) {
|
||||||
Map sourceMap = (Map) sourceClassConverters.get(sourceClass);
|
Map sourceMap = (Map) sourceTypeConverters.get(sourceType);
|
||||||
if (sourceMap == null) {
|
if (sourceMap == null) {
|
||||||
sourceMap = new HashMap();
|
sourceMap = new HashMap();
|
||||||
sourceClassConverters.put(sourceClass, sourceMap);
|
sourceTypeConverters.put(sourceType, sourceMap);
|
||||||
}
|
}
|
||||||
return sourceMap;
|
return sourceMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map getSourceSuperConverterMap(Class sourceClass) {
|
private Map getSourceSuperConverterMap(Class sourceType) {
|
||||||
Map sourceMap = (Map) sourceClassSuperConverters.get(sourceClass);
|
Map sourceMap = (Map) sourceTypeSuperConverters.get(sourceType);
|
||||||
if (sourceMap == null) {
|
if (sourceMap == null) {
|
||||||
sourceMap = new HashMap();
|
sourceMap = new HashMap();
|
||||||
sourceClassSuperConverters.put(sourceClass, sourceMap);
|
sourceTypeSuperConverters.put(sourceType, sourceMap);
|
||||||
}
|
}
|
||||||
return sourceMap;
|
return sourceMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Converter findRegisteredConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
private Converter findRegisteredConverter(Class<?> sourceType, Class<?> targetType) {
|
||||||
Class<?> sourceClass = sourceType.getWrapperTypeIfPrimitive();
|
if (sourceType.isInterface()) {
|
||||||
Class<?> targetClass = targetType.getWrapperTypeIfPrimitive();
|
|
||||||
if (sourceClass.isInterface()) {
|
|
||||||
LinkedList classQueue = new LinkedList();
|
LinkedList classQueue = new LinkedList();
|
||||||
classQueue.addFirst(sourceClass);
|
classQueue.addFirst(sourceType);
|
||||||
while (!classQueue.isEmpty()) {
|
while (!classQueue.isEmpty()) {
|
||||||
Class currentClass = (Class) classQueue.removeLast();
|
Class currentClass = (Class) classQueue.removeLast();
|
||||||
Map converters = getConvertersForSource(currentClass);
|
Map converters = getConvertersForSource(currentClass);
|
||||||
Converter converter = getConverter(converters, targetClass);
|
Converter converter = getConverter(converters, targetType);
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
@ -342,14 +325,14 @@ public class GenericConversionService implements ConversionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Map objectConverters = getConvertersForSource(Object.class);
|
Map objectConverters = getConvertersForSource(Object.class);
|
||||||
return getConverter(objectConverters, targetClass);
|
return getConverter(objectConverters, targetType);
|
||||||
} else {
|
} else {
|
||||||
LinkedList classQueue = new LinkedList();
|
LinkedList classQueue = new LinkedList();
|
||||||
classQueue.addFirst(sourceClass);
|
classQueue.addFirst(sourceType);
|
||||||
while (!classQueue.isEmpty()) {
|
while (!classQueue.isEmpty()) {
|
||||||
Class currentClass = (Class) classQueue.removeLast();
|
Class currentClass = (Class) classQueue.removeLast();
|
||||||
Map converters = getConvertersForSource(currentClass);
|
Map converters = getConvertersForSource(currentClass);
|
||||||
Converter converter = getConverter(converters, targetClass);
|
Converter converter = getConverter(converters, targetType);
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
@ -365,25 +348,23 @@ public class GenericConversionService implements ConversionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map getConvertersForSource(Class sourceClass) {
|
private Map getConvertersForSource(Class sourceType) {
|
||||||
Map converters = (Map) sourceClassConverters.get(sourceClass);
|
Map converters = (Map) sourceTypeConverters.get(sourceType);
|
||||||
return converters != null ? converters : Collections.emptyMap();
|
return converters != null ? converters : Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Converter getConverter(Map converters, Class targetClass) {
|
private Converter getConverter(Map converters, Class targetType) {
|
||||||
return (Converter) converters.get(targetClass);
|
return (Converter) converters.get(targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SuperConverter findRegisteredSuperConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
private SuperConverter findRegisteredSuperConverter(Class<?> sourceType, Class<?> targetType) {
|
||||||
Class<?> sourceClass = sourceType.getWrapperTypeIfPrimitive();
|
if (sourceType.isInterface()) {
|
||||||
Class<?> targetClass = targetType.getWrapperTypeIfPrimitive();
|
|
||||||
if (sourceClass.isInterface()) {
|
|
||||||
LinkedList classQueue = new LinkedList();
|
LinkedList classQueue = new LinkedList();
|
||||||
classQueue.addFirst(sourceClass);
|
classQueue.addFirst(sourceType);
|
||||||
while (!classQueue.isEmpty()) {
|
while (!classQueue.isEmpty()) {
|
||||||
Class currentClass = (Class) classQueue.removeLast();
|
Class currentClass = (Class) classQueue.removeLast();
|
||||||
Map converters = getSuperConvertersForSource(currentClass);
|
Map converters = getSuperConvertersForSource(currentClass);
|
||||||
SuperConverter converter = findSuperConverter(converters, targetClass);
|
SuperConverter converter = findSuperConverter(converters, targetType);
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
@ -393,14 +374,14 @@ public class GenericConversionService implements ConversionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Map objectConverters = getSuperConvertersForSource(Object.class);
|
Map objectConverters = getSuperConvertersForSource(Object.class);
|
||||||
return findSuperConverter(objectConverters, targetClass);
|
return findSuperConverter(objectConverters, targetType);
|
||||||
} else {
|
} else {
|
||||||
LinkedList classQueue = new LinkedList();
|
LinkedList classQueue = new LinkedList();
|
||||||
classQueue.addFirst(sourceClass);
|
classQueue.addFirst(sourceType);
|
||||||
while (!classQueue.isEmpty()) {
|
while (!classQueue.isEmpty()) {
|
||||||
Class currentClass = (Class) classQueue.removeLast();
|
Class currentClass = (Class) classQueue.removeLast();
|
||||||
Map converters = getSuperConvertersForSource(currentClass);
|
Map converters = getSuperConvertersForSource(currentClass);
|
||||||
SuperConverter converter = findSuperConverter(converters, targetClass);
|
SuperConverter converter = findSuperConverter(converters, targetType);
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
@ -416,18 +397,18 @@ public class GenericConversionService implements ConversionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map getSuperConvertersForSource(Class sourceClass) {
|
private Map getSuperConvertersForSource(Class sourceType) {
|
||||||
Map converters = (Map) sourceClassSuperConverters.get(sourceClass);
|
Map converters = (Map) sourceTypeSuperConverters.get(sourceType);
|
||||||
return converters != null ? converters : Collections.emptyMap();
|
return converters != null ? converters : Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SuperConverter findSuperConverter(Map converters, Class targetClass) {
|
private SuperConverter findSuperConverter(Map converters, Class targetType) {
|
||||||
if (converters.isEmpty()) {
|
if (converters.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (targetClass.isInterface()) {
|
if (targetType.isInterface()) {
|
||||||
LinkedList classQueue = new LinkedList();
|
LinkedList classQueue = new LinkedList();
|
||||||
classQueue.addFirst(targetClass);
|
classQueue.addFirst(targetType);
|
||||||
while (!classQueue.isEmpty()) {
|
while (!classQueue.isEmpty()) {
|
||||||
Class currentClass = (Class) classQueue.removeLast();
|
Class currentClass = (Class) classQueue.removeLast();
|
||||||
SuperConverter converter = (SuperConverter) converters.get(currentClass);
|
SuperConverter converter = (SuperConverter) converters.get(currentClass);
|
||||||
|
|
@ -442,7 +423,7 @@ public class GenericConversionService implements ConversionService {
|
||||||
return (SuperConverter) converters.get(Object.class);
|
return (SuperConverter) converters.get(Object.class);
|
||||||
} else {
|
} else {
|
||||||
LinkedList classQueue = new LinkedList();
|
LinkedList classQueue = new LinkedList();
|
||||||
classQueue.addFirst(targetClass);
|
classQueue.addFirst(targetType);
|
||||||
while (!classQueue.isEmpty()) {
|
while (!classQueue.isEmpty()) {
|
||||||
Class currentClass = (Class) classQueue.removeLast();
|
Class currentClass = (Class) classQueue.removeLast();
|
||||||
SuperConverter converter = (SuperConverter) converters.get(currentClass);
|
SuperConverter converter = (SuperConverter) converters.get(currentClass);
|
||||||
|
|
@ -461,9 +442,4 @@ public class GenericConversionService implements ConversionService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConversionExecutor getElementConverter(Class<?> sourceElementType, Class<?> targetElementType) {
|
|
||||||
return getConversionExecutor(sourceElementType, TypeDescriptor
|
|
||||||
.valueOf(targetElementType));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +20,6 @@ import static junit.framework.Assert.assertNull;
|
||||||
import static junit.framework.Assert.assertSame;
|
import static junit.framework.Assert.assertSame;
|
||||||
import static junit.framework.Assert.fail;
|
import static junit.framework.Assert.fail;
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
@ -31,7 +30,6 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.core.convert.ConversionException;
|
|
||||||
import org.springframework.core.convert.ConversionExecutionException;
|
import org.springframework.core.convert.ConversionExecutionException;
|
||||||
import org.springframework.core.convert.ConversionExecutor;
|
import org.springframework.core.convert.ConversionExecutor;
|
||||||
import org.springframework.core.convert.ConversionExecutorNotFoundException;
|
import org.springframework.core.convert.ConversionExecutorNotFoundException;
|
||||||
|
|
@ -348,273 +346,7 @@ public class GenericConversionServiceTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
@Test
|
||||||
public void customConverterConvertForwardIndex() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("princy", String.class, type(Principal.class));
|
|
||||||
assertEquals("keith", ((Principal) executor.execute("keith")).getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterConvertReverseIndex() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("princy", Principal.class, type(String.class));
|
|
||||||
assertEquals("keith", executor.execute(new Principal() {
|
|
||||||
public String getName() {
|
|
||||||
return "keith";
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterConvertForSameType() {
|
|
||||||
service.addConverter("trimmer", new Trimmer());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("trimmer", String.class, type(String.class));
|
|
||||||
assertEquals("a string", executor.execute("a string "));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterLookupNotCompatibleSource() {
|
|
||||||
service.addConverter("trimmer", new Trimmer());
|
|
||||||
try {
|
|
||||||
service.getConversionExecutor("trimmer", Object.class, type(String.class));
|
|
||||||
fail("Should have failed");
|
|
||||||
} catch (ConversionException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterLookupNotCompatibleTarget() {
|
|
||||||
service.addConverter("trimmer", new Trimmer());
|
|
||||||
try {
|
|
||||||
service.getConversionExecutor("trimmer", String.class, type(Object.class));
|
|
||||||
} catch (ConversionException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterLookupNotCompatibleTargetReverse() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
try {
|
|
||||||
service.getConversionExecutor("princy", Principal.class, type(Integer.class));
|
|
||||||
} catch (ConversionException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterConvertArrayToArray() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("princy", String[].class, type(Principal[].class));
|
|
||||||
Principal[] p = (Principal[]) executor.execute(new String[] { "princy1", "princy2" });
|
|
||||||
assertEquals("princy1", p[0].getName());
|
|
||||||
assertEquals("princy2", p[1].getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterConvertArrayToArrayReverse() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("princy", Principal[].class, type(String[].class));
|
|
||||||
final Principal princy1 = new Principal() {
|
|
||||||
public String getName() {
|
|
||||||
return "princy1";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
final Principal princy2 = new Principal() {
|
|
||||||
public String getName() {
|
|
||||||
return "princy2";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
String[] p = (String[]) executor.execute(new Principal[] { princy1, princy2 });
|
|
||||||
assertEquals("princy1", p[0]);
|
|
||||||
assertEquals("princy2", p[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterLookupArrayToArrayBogusSource() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
try {
|
|
||||||
service.getConversionExecutor("princy", Integer[].class, type(Principal[].class));
|
|
||||||
fail("Should have failed");
|
|
||||||
} catch (ConversionExecutorNotFoundException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterLookupArrayToArrayBogusTarget() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
try {
|
|
||||||
service.getConversionExecutor("princy", Principal[].class, type(Integer[].class));
|
|
||||||
} catch (ConversionExecutorNotFoundException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterConvertArrayToCollection() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("princy", String[].class, type(List.class));
|
|
||||||
List list = (List) executor.execute(new String[] { "princy1", "princy2" });
|
|
||||||
assertEquals("princy1", ((Principal) list.get(0)).getName());
|
|
||||||
assertEquals("princy2", ((Principal) list.get(1)).getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterConvertArrayToCollectionReverse() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("princy", Principal[].class, type(List.class));
|
|
||||||
final Principal princy1 = new Principal() {
|
|
||||||
public String getName() {
|
|
||||||
return "princy1";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
final Principal princy2 = new Principal() {
|
|
||||||
public String getName() {
|
|
||||||
return "princy2";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
List p = (List) executor.execute(new Principal[] { princy1, princy2 });
|
|
||||||
assertEquals("princy1", p.get(0));
|
|
||||||
assertEquals("princy2", p.get(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterLookupArrayToCollectionBogusSource() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
try {
|
|
||||||
service.getConversionExecutor("princy", Integer[].class, type(List.class));
|
|
||||||
fail("Should have failed");
|
|
||||||
} catch (ConversionExecutorNotFoundException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterLookupCollectionToArray() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("princy", List.class, type(Principal[].class));
|
|
||||||
List princyList = new ArrayList();
|
|
||||||
princyList.add("princy1");
|
|
||||||
princyList.add("princy2");
|
|
||||||
Principal[] p = (Principal[]) executor.execute(princyList);
|
|
||||||
assertEquals("princy1", p[0].getName());
|
|
||||||
assertEquals("princy2", p[1].getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterLookupCollectionToArrayReverse() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("princy", List.class, type(String[].class));
|
|
||||||
final Principal princy1 = new Principal() {
|
|
||||||
public String getName() {
|
|
||||||
return "princy1";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
final Principal princy2 = new Principal() {
|
|
||||||
public String getName() {
|
|
||||||
return "princy2";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
List princyList = new ArrayList();
|
|
||||||
princyList.add(princy1);
|
|
||||||
princyList.add(princy2);
|
|
||||||
String[] p = (String[]) executor.execute(princyList);
|
|
||||||
assertEquals("princy1", p[0]);
|
|
||||||
assertEquals("princy2", p[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterLookupCollectionToArrayBogusTarget() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
try {
|
|
||||||
service.getConversionExecutor("princy", List.class, type(Integer[].class));
|
|
||||||
fail("Should have failed");
|
|
||||||
} catch (ConversionExecutorNotFoundException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterConvertObjectToArray() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("princy", String.class, type(Principal[].class));
|
|
||||||
Principal[] p = (Principal[]) executor.execute("princy1");
|
|
||||||
assertEquals("princy1", p[0].getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterConvertObjectToArrayReverse() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
ConversionExecutor executor = service.getConversionExecutor("princy", Principal.class, type(String[].class));
|
|
||||||
final Principal princy1 = new Principal() {
|
|
||||||
public String getName() {
|
|
||||||
return "princy1";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
String[] p = (String[]) executor.execute(princy1);
|
|
||||||
assertEquals("princy1", p[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore
|
|
||||||
@Test
|
|
||||||
public void customConverterLookupObjectToArrayBogusSource() {
|
|
||||||
service.addConverter("princy", new CustomTwoWayConverter());
|
|
||||||
try {
|
|
||||||
service.getConversionExecutor("princy", Integer.class, type(Principal[].class));
|
|
||||||
fail("Should have failed");
|
|
||||||
} catch (ConversionExecutorNotFoundException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class CustomTwoWayConverter implements Converter<String, Principal> {
|
|
||||||
|
|
||||||
public Principal convert(final String source) throws Exception {
|
|
||||||
return new Principal() {
|
|
||||||
public String getName() {
|
|
||||||
return (String) source;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public String convertBack(Principal target) throws Exception {
|
|
||||||
return ((Principal) target).getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class Trimmer implements Converter<String, String> {
|
|
||||||
|
|
||||||
public String convert(String source) throws Exception {
|
|
||||||
return ((String) source).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String convertBack(String target) throws Exception {
|
|
||||||
throw new UnsupportedOperationException("Will never run");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testSuperTwoWayConverterConverterAdaption() {
|
public void testSuperTwoWayConverterConverterAdaption() {
|
||||||
service.addConverter(GenericConversionService.converterFor(String.class, FooEnum.class, new StringToEnum()));
|
service.addConverter(GenericConversionService.converterFor(String.class, FooEnum.class, new StringToEnum()));
|
||||||
assertEquals(FooEnum.BAR, service.executeConversion("BAR", type(FooEnum.class)));
|
assertEquals(FooEnum.BAR, service.executeConversion("BAR", type(FooEnum.class)));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue