public ConversionExecutor getConversionExecutor(String id, Class<?> sourceClass, Class<?> targetClass)
throws ConversionExecutorNotFoundException {
Assert.hasText(id, "The id of the custom converter is required");
Assert.notNull(sourceClass, "The source class to convert from is required");
Assert.notNull(targetClass, "The target class to convert to is required");
Converter converter = customConverters.get(id);
if (converter == null) {
if (parent != null) {
return parent.getConversionExecutor(id, sourceClass, targetClass);
} else {
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
"No custom ConversionExecutor found with id '" + id + "' for converting from sourceClass ["
+ sourceClass.getName() + "] to targetClass [" + targetClass.getName() + "]");
}
}
sourceClass = convertToWrapperClassIfNecessary(sourceClass);
targetClass = convertToWrapperClassIfNecessary(targetClass);
if (sourceClass.isArray()) {
Class<?> sourceComponentType = sourceClass.getComponentType();
if (targetClass.isArray()) {
Class<?> targetComponentType = targetClass.getComponentType();
if (converter.getSourceClass().isAssignableFrom(sourceComponentType)) {
if (!converter.getTargetClass().isAssignableFrom(targetComponentType)) {
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
"Custom ConversionExecutor with id '" + id
+ "' cannot convert from an array storing elements of type ["
+ sourceComponentType.getName() + "] to an array of storing elements of type ["
+ targetComponentType.getName() + "]");
}
ConversionExecutor elementConverter = new StaticConversionExecutor(sourceComponentType,
targetComponentType, converter);
return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToArray(elementConverter));
} else if (converter.getTargetClass().isAssignableFrom(sourceComponentType)
&& converter instanceof TwoWayConverter) {
TwoWayConverter twoWay = (TwoWayConverter) converter;
ConversionExecutor elementConverter = new StaticConversionExecutor(sourceComponentType,
targetComponentType, new ReverseConverter(twoWay));
return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToArray(elementConverter));
} else {
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
"Custom ConversionExecutor with id '" + id
+ "' cannot convert from an array storing elements of type ["
+ sourceComponentType.getName() + "] to an array storing elements of type ["
+ targetComponentType.getName() + "]");
}
} else if (Collection.class.isAssignableFrom(targetClass)) {
if (!targetClass.isInterface() && Modifier.isAbstract(targetClass.getModifiers())) {
throw new IllegalArgumentException("Conversion target class [" + targetClass.getName()
+ "] is invalid; cannot convert to abstract collection types--"
+ "request an interface or concrete implementation instead");
}
if (converter.getSourceClass().isAssignableFrom(sourceComponentType)) {
// type erasure has prevented us from getting the concrete type, this is best we can do for now
ConversionExecutor elementConverter = new StaticConversionExecutor(sourceComponentType,
converter.getTargetClass(), converter);
return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToCollection(
elementConverter));
} else if (converter.getTargetClass().isAssignableFrom(sourceComponentType)
&& converter instanceof TwoWayConverter) {
TwoWayConverter twoWay = (TwoWayConverter) converter;
ConversionExecutor elementConverter = new StaticConversionExecutor(sourceComponentType,
converter.getSourceClass(), new ReverseConverter(twoWay));
return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToCollection(
elementConverter));
} else {
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
"Custom ConversionExecutor with id '" + id
+ "' cannot convert from array an storing elements type ["
+ sourceComponentType.getName() + "] to a collection of type ["
+ targetClass.getName() + "]");
}
}
}
if (targetClass.isArray()) {
Class<?> targetComponentType = targetClass.getComponentType();
if (Collection.class.isAssignableFrom(sourceClass)) {
// type erasure limits us here as well
if (converter.getTargetClass().isAssignableFrom(targetComponentType)) {
ConversionExecutor elementConverter = new StaticConversionExecutor(converter.getSourceClass(),
targetComponentType, converter);
Converter collectionToArray = new ReverseConverter(new ArrayToCollection(elementConverter));
return new StaticConversionExecutor(sourceClass, targetClass, collectionToArray);
} else if (converter.getSourceClass().isAssignableFrom(targetComponentType)
&& converter instanceof TwoWayConverter) {
TwoWayConverter twoWay = (TwoWayConverter) converter;
ConversionExecutor elementConverter = new StaticConversionExecutor(converter.getTargetClass(),
targetComponentType, new ReverseConverter(twoWay));
Converter collectionToArray = new ReverseConverter(new ArrayToCollection(elementConverter));
return new StaticConversionExecutor(sourceClass, targetClass, collectionToArray);
} else {
throw new ConversionExecutorNotFoundException(sourceClass, targetClass,
"Custom ConversionExecutor with id '" + id + "' cannot convert from collection of type ["
+ sourceClass.getName() + "] to an array storing elements of type ["