refined generic converter concept
This commit is contained in:
parent
6420fd303b
commit
d3b43ebccb
|
@ -174,7 +174,7 @@ class TypeConverterDelegate {
|
||||||
else {
|
else {
|
||||||
typeDesc = TypeDescriptor.valueOf(requiredType);
|
typeDesc = TypeDescriptor.valueOf(requiredType);
|
||||||
}
|
}
|
||||||
if (conversionService.canConvert(convertedValue.getClass(), typeDesc)) {
|
if (conversionService.matches(convertedValue.getClass(), typeDesc)) {
|
||||||
return (T) conversionService.convert(convertedValue, typeDesc);
|
return (T) conversionService.convert(convertedValue, typeDesc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.core.convert;
|
package org.springframework.core.convert;
|
||||||
|
|
||||||
import org.springframework.core.style.StylerUtils;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when an attempt to execute a type conversion fails.
|
* Thrown when an attempt to execute a type conversion fails.
|
||||||
*
|
*
|
||||||
|
@ -27,7 +24,7 @@ import org.springframework.util.ClassUtils;
|
||||||
*/
|
*/
|
||||||
public class ConversionFailedException extends ConversionException {
|
public class ConversionFailedException extends ConversionException {
|
||||||
|
|
||||||
private Class<?> sourceType;
|
private TypeDescriptor sourceType;
|
||||||
|
|
||||||
private TypeDescriptor targetType;
|
private TypeDescriptor targetType;
|
||||||
|
|
||||||
|
@ -38,7 +35,7 @@ public class ConversionFailedException extends ConversionException {
|
||||||
* @param targetType the value's target type
|
* @param targetType the value's target type
|
||||||
* @param cause the cause of the conversion failure
|
* @param cause the cause of the conversion failure
|
||||||
*/
|
*/
|
||||||
public ConversionFailedException(Class<?> sourceType, TypeDescriptor targetType, Object value, Throwable cause) {
|
public ConversionFailedException(TypeDescriptor sourceType, TypeDescriptor targetType, Object value, Throwable cause) {
|
||||||
super(buildDefaultMessage(value, sourceType, targetType, cause), cause);
|
super(buildDefaultMessage(value, sourceType, targetType, cause), cause);
|
||||||
this.sourceType = sourceType;
|
this.sourceType = sourceType;
|
||||||
this.targetType = targetType;
|
this.targetType = targetType;
|
||||||
|
@ -47,7 +44,7 @@ public class ConversionFailedException extends ConversionException {
|
||||||
/**
|
/**
|
||||||
* Return the source type we tried to convert the value from.
|
* Return the source type we tried to convert the value from.
|
||||||
*/
|
*/
|
||||||
public Class<?> getSourceType() {
|
public TypeDescriptor getSourceType() {
|
||||||
return this.sourceType;
|
return this.sourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,11 +55,10 @@ public class ConversionFailedException extends ConversionException {
|
||||||
return this.targetType;
|
return this.targetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String buildDefaultMessage(Object value, TypeDescriptor sourceType, TypeDescriptor targetType,
|
||||||
private static String buildDefaultMessage(Object value, Class<?> sourceType, TypeDescriptor targetType, Throwable cause) {
|
Throwable cause) {
|
||||||
return "Unable to convert value " + StylerUtils.style(value) + " from type '" +
|
return "Unable to convert value " + value + " from type [" + sourceType.getName() + "] to type ["
|
||||||
ClassUtils.getQualifiedName(sourceType) + "' to type '" +
|
+ targetType.getName() + "]; reason = '" + cause.getMessage() + "'";
|
||||||
ClassUtils.getQualifiedName(targetType.getType()) + "'; reason = '" + cause.getMessage() + "'";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -18,10 +18,7 @@ package org.springframework.core.convert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service interface for type conversion. This is the entry point into the convert system.
|
* A service interface for type conversion. This is the entry point into the convert system.
|
||||||
*
|
* Call {@link #convert(Object, Class)} to perform a thread-safe type conversion using this system.
|
||||||
* <p>Call {@link #convert(Object, Class)} to perform a thread-safe type conversion using this system.
|
|
||||||
* Call {@link #convert(Object, TypeDescriptor)} to perform a conversion with additional context
|
|
||||||
* about the targetType to convert to.
|
|
||||||
*
|
*
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
|
@ -46,24 +43,25 @@ public interface ConversionService {
|
||||||
<T> T convert(Object source, Class<T> targetType);
|
<T> T convert(Object source, Class<T> targetType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if objects of sourceType can be converted to the targetType described by the TypeDescriptor.
|
* Returns true if objects of sourceType can be converted to the targetType.
|
||||||
* The TypeDescriptor provides additional context about the point where conversion is needed, often an object property location.
|
* The TypeDescriptors provide additional context about the variable locations where conversion would occur, often object property locations.
|
||||||
* This flavor of the canConvert operation is mainly for use by a data binding framework, and not by user code.
|
* This flavor of the canConvert operation is mainly for use by a data binding framework, and not by user code.
|
||||||
* @param source the source type to convert from (required)
|
* @param source context about the source type to convert from (required)
|
||||||
* @param targetType context about the target type to convert to (required)
|
* @param targetType context about the target type to convert to (required)
|
||||||
* @return true if a conversion can be performed, false if not
|
* @return true if a conversion can be performed between the source and target types, false if not
|
||||||
*/
|
*/
|
||||||
boolean canConvert(Class<?> sourceType, TypeDescriptor targetType);
|
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the source to the targetType described by the TypeDescriptor.
|
* Convert the source to targetTyp.
|
||||||
* The TypeDescriptor provides additional context about the point where conversion is needed, often a object property location.
|
* The TypeDescriptors provide additional context about the variable locations where conversion will occur, often object property locations.
|
||||||
* This flavor of the convert operation is mainly for use by a data binding framework, and not by user code.
|
* This flavor of the convert operation is mainly for use by a data binding framework, and not by user code.
|
||||||
* @param source the source to convert from (may be null)
|
* @param source the source to convert from (may be null)
|
||||||
|
* @param sourceType context about the source type to convert from (required)
|
||||||
* @param targetType context about the target type to convert to (required)
|
* @param targetType context about the target type to convert to (required)
|
||||||
* @return the converted object, an instance of {@link TypeDescriptor#getType()}</code>
|
* @return the converted object, an instance of {@link TypeDescriptor#getObjectType()}</code>
|
||||||
* @throws ConversionException if an exception occurred
|
* @throws ConversionException if an exception occurred
|
||||||
*/
|
*/
|
||||||
Object convert(Object source, TypeDescriptor targetType);
|
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,9 +24,9 @@ package org.springframework.core.convert;
|
||||||
*/
|
*/
|
||||||
public class ConverterNotFoundException extends ConversionException {
|
public class ConverterNotFoundException extends ConversionException {
|
||||||
|
|
||||||
private final Class<?> sourceType;
|
private final TypeDescriptor sourceType;
|
||||||
|
|
||||||
private final Class<?> targetType;
|
private final TypeDescriptor targetType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new conversion executor not found exception.
|
* Creates a new conversion executor not found exception.
|
||||||
|
@ -34,7 +34,7 @@ public class ConverterNotFoundException extends ConversionException {
|
||||||
* @param targetType the target type requested to convert to
|
* @param targetType the target type requested to convert to
|
||||||
* @param message a descriptive message
|
* @param message a descriptive message
|
||||||
*/
|
*/
|
||||||
public ConverterNotFoundException(Class<?> sourceType, Class<?> targetType) {
|
public ConverterNotFoundException(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
super("No converter found capable of converting from [" + sourceType.getName() + "] to [" + targetType.getName() + "]");
|
super("No converter found capable of converting from [" + sourceType.getName() + "] to [" + targetType.getName() + "]");
|
||||||
this.sourceType = sourceType;
|
this.sourceType = sourceType;
|
||||||
this.targetType = targetType;
|
this.targetType = targetType;
|
||||||
|
@ -43,14 +43,14 @@ public class ConverterNotFoundException extends ConversionException {
|
||||||
/**
|
/**
|
||||||
* Returns the source type that was requested to convert from.
|
* Returns the source type that was requested to convert from.
|
||||||
*/
|
*/
|
||||||
public Class<?> getSourceType() {
|
public TypeDescriptor getSourceType() {
|
||||||
return this.sourceType;
|
return this.sourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the target type that was requested to convert to.
|
* Returns the target type that was requested to convert to.
|
||||||
*/
|
*/
|
||||||
public Class<?> getTargetType() {
|
public TypeDescriptor getTargetType() {
|
||||||
return this.targetType;
|
return this.targetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -178,6 +178,13 @@ public class TypeDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the element type as a type descriptor.
|
||||||
|
*/
|
||||||
|
public TypeDescriptor getElementTypeDescriptor() {
|
||||||
|
return TypeDescriptor.valueOf(getElementType());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this type a {@link Map} type?
|
* Is this type a {@link Map} type?
|
||||||
*/
|
*/
|
||||||
|
@ -224,6 +231,14 @@ public class TypeDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TypeDescriptor getMapKeyTypeDescriptor() {
|
||||||
|
return TypeDescriptor.valueOf(getMapKeyType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeDescriptor getMapValueTypeDescriptor() {
|
||||||
|
return TypeDescriptor.valueOf(getMapValueType());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the annotations associated with the wrapped parameter/field, if any.
|
* Obtain the annotations associated with the wrapped parameter/field, if any.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.core.convert.support;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic converter that can convert from one array type to another.
|
||||||
|
*
|
||||||
|
* @author Keith Donald
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
class ArrayGenericConverter implements GenericConverter {
|
||||||
|
|
||||||
|
private GenericConversionService conversionService;
|
||||||
|
|
||||||
|
public ArrayGenericConverter(GenericConversionService conversionService) {
|
||||||
|
this.conversionService = conversionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
|
return sourceType.isArray() && targetType.isArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
|
if (sourceType.isAssignableTo(targetType)) {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
|
||||||
|
TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor();
|
||||||
|
Object target = Array.newInstance(targetElementType.getType(), Array.getLength(source));
|
||||||
|
GenericConverter converter = conversionService.getConverter(sourceElementType, targetElementType);
|
||||||
|
for (int i = 0; i < Array.getLength(target); i++) {
|
||||||
|
Array.set(target, i, converter.convert(Array.get(source, i), sourceElementType, targetElementType));
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,38 +28,43 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
class CollectionToCollectionGenericConverter implements GenericConverter {
|
class CollectionGenericConverter implements GenericConverter {
|
||||||
|
|
||||||
private GenericConversionService conversionService;
|
private GenericConversionService conversionService;
|
||||||
|
|
||||||
public CollectionToCollectionGenericConverter(GenericConversionService conversionService) {
|
public CollectionGenericConverter(GenericConversionService conversionService) {
|
||||||
this.conversionService = conversionService;
|
this.conversionService = conversionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object convert(Object source, TypeDescriptor targetType) {
|
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
|
return sourceType.isCollection() && targetType.isCollection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
Collection sourceCollection = (Collection) source;
|
Collection sourceCollection = (Collection) source;
|
||||||
Class targetElementType = targetType.getElementType();
|
TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
|
||||||
if (targetElementType == null) {
|
if (targetElementType == TypeDescriptor.NULL) {
|
||||||
return compatibleCollectionWithoutElementConversion(sourceCollection, targetType);
|
return compatibleCollectionWithoutElementConversion(sourceCollection, targetType);
|
||||||
}
|
}
|
||||||
Class sourceElementType = getElementType(sourceCollection);
|
TypeDescriptor sourceElementType = sourceType.getElementTypeDescriptor();
|
||||||
if (sourceElementType == null || targetElementType.isAssignableFrom(sourceElementType)) {
|
if (sourceElementType == TypeDescriptor.NULL) {
|
||||||
|
sourceElementType = getElementType(sourceCollection);
|
||||||
|
}
|
||||||
|
if (sourceElementType == TypeDescriptor.NULL || sourceElementType.isAssignableTo(targetElementType)) {
|
||||||
return compatibleCollectionWithoutElementConversion(sourceCollection, targetType);
|
return compatibleCollectionWithoutElementConversion(sourceCollection, targetType);
|
||||||
}
|
}
|
||||||
Collection targetCollection = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size());
|
Collection targetCollection = CollectionFactory.createCollection(targetType.getType(), sourceCollection.size());
|
||||||
TypeDescriptor targetElementTypeDescriptor = TypeDescriptor.valueOf(targetElementType);
|
GenericConverter elementConverter = conversionService.getConverter(sourceElementType, targetElementType);
|
||||||
GenericConverter elementConverter = conversionService.getConverter(sourceElementType,
|
|
||||||
targetElementTypeDescriptor);
|
|
||||||
for (Object element : sourceCollection) {
|
for (Object element : sourceCollection) {
|
||||||
targetCollection.add(elementConverter.convert(element, targetElementTypeDescriptor));
|
targetCollection.add(elementConverter.convert(element, sourceElementType, targetElementType));
|
||||||
}
|
}
|
||||||
return targetCollection;
|
return targetCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class getElementType(Collection collection) {
|
private TypeDescriptor getElementType(Collection collection) {
|
||||||
for (Object element : collection) {
|
for (Object element : collection) {
|
||||||
if (element != null) {
|
if (element != null) {
|
||||||
return element.getClass();
|
return TypeDescriptor.valueOf(element.getClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
|
@ -20,9 +20,9 @@ import java.lang.reflect.ParameterizedType;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.lang.reflect.TypeVariable;
|
import java.lang.reflect.TypeVariable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -38,7 +38,6 @@ import org.springframework.core.convert.converter.ConverterFactory;
|
||||||
import org.springframework.core.convert.converter.ConverterInfo;
|
import org.springframework.core.convert.converter.ConverterInfo;
|
||||||
import org.springframework.core.convert.converter.ConverterRegistry;
|
import org.springframework.core.convert.converter.ConverterRegistry;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base implementation of a conversion service.
|
* Base implementation of a conversion service.
|
||||||
|
@ -56,9 +55,12 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
|
|
||||||
private final Map<Class, Map<Class, GenericConverter>> sourceTypeConverters = new HashMap<Class, Map<Class, GenericConverter>>();
|
private final Map<Class, Map<Class, GenericConverter>> sourceTypeConverters = new HashMap<Class, Map<Class, GenericConverter>>();
|
||||||
|
|
||||||
|
private final Set<GenericConverter> matchableConverters = new LinkedHashSet<GenericConverter>();
|
||||||
|
|
||||||
public GenericConversionService() {
|
public GenericConversionService() {
|
||||||
addGenericConverter(Collection.class, Collection.class, new CollectionToCollectionGenericConverter(this));
|
addGenericConverter(new CollectionGenericConverter(this));
|
||||||
addGenericConverter(Map.class, Map.class, new MapToMapGenericConverter(this));
|
addGenericConverter(new MapGenericConverter(this));
|
||||||
|
addGenericConverter(new ArrayGenericConverter(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,106 +124,81 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeConvertible(Class<?> sourceType, Class<?> targetType) {
|
public void removeConvertible(Class<?> sourceType, Class<?> targetType) {
|
||||||
Map sourceMap = getSourceMap(sourceType);
|
getSourceMap(sourceType).remove(targetType);
|
||||||
sourceMap.remove(targetType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// implementing ConversionService
|
// implementing ConversionService
|
||||||
|
|
||||||
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
||||||
return canConvert(sourceType, TypeDescriptor.valueOf(targetType));
|
return canConvert(TypeDescriptor.valueOf(sourceType), TypeDescriptor.valueOf(targetType));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canConvert(Class<?> sourceType, TypeDescriptor targetType) {
|
public <T> T convert(Object source, Class<T> targetType) {
|
||||||
|
Assert.notNull(targetType, "The targetType to convert to is required");
|
||||||
|
return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
Assert.notNull(sourceType, "The sourceType to convert from is required");
|
Assert.notNull(sourceType, "The sourceType to convert from is required");
|
||||||
Assert.notNull(targetType, "The targetType to convert to is required");
|
Assert.notNull(targetType, "The targetType to convert to is required");
|
||||||
if (targetType == TypeDescriptor.NULL) {
|
if (targetType == TypeDescriptor.NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Class sourceClass = ClassUtils.resolvePrimitiveIfNecessary(sourceType);
|
return getConverter(sourceType, targetType) != null || this.parent != null
|
||||||
Class targetClass = targetType.getObjectType();
|
&& this.parent.canConvert(sourceType, targetType);
|
||||||
return getConverter(sourceClass, targetType) != null || this.parent != null
|
|
||||||
&& this.parent.canConvert(sourceClass, targetClass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T convert(Object source, Class<T> targetType) {
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
Assert.notNull(targetType, "The targetType to convert to is required");
|
Assert.notNull(sourceType, "The source type to convert to is required");
|
||||||
return (T) convert(source, TypeDescriptor.valueOf(targetType));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object convert(Object source, TypeDescriptor targetType) {
|
|
||||||
Assert.notNull(targetType, "The targetType to convert to is required");
|
Assert.notNull(targetType, "The targetType to convert to is required");
|
||||||
if (source == null) {
|
if (source == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Assert.isTrue(sourceType != TypeDescriptor.NULL,
|
||||||
|
"The source TypeDescriptor must not be TypeDescriptor.NULL when source != null");
|
||||||
if (targetType == TypeDescriptor.NULL) {
|
if (targetType == TypeDescriptor.NULL) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Class sourceType = ClassUtils.resolvePrimitiveIfNecessary(source.getClass());
|
|
||||||
GenericConverter converter = getConverter(sourceType, targetType);
|
GenericConverter converter = getConverter(sourceType, targetType);
|
||||||
if (converter != null) {
|
if (converter != null) {
|
||||||
try {
|
try {
|
||||||
return converter.convert(source, targetType);
|
return converter.convert(source, sourceType, targetType);
|
||||||
} catch (ConversionFailedException e) {
|
} catch (ConversionFailedException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ConversionFailedException(sourceType, targetType, source, e);
|
throw new ConversionFailedException(sourceType, targetType, source, e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (targetType.isAssignableValue(source)) {
|
if (this.parent != null) {
|
||||||
return source;
|
return this.parent.convert(source, sourceType, targetType);
|
||||||
} else {
|
} else {
|
||||||
throw new ConverterNotFoundException(sourceType, targetType.getObjectType());
|
if (targetType.isAssignableValue(source)) {
|
||||||
|
return source;
|
||||||
|
} else {
|
||||||
|
throw new ConverterNotFoundException(sourceType, targetType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// subclassing hooks
|
// subclassing hooks
|
||||||
|
|
||||||
protected GenericConverter getConverter(Class sourceType, TypeDescriptor targetType) {
|
protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
if (sourceType.isInterface()) {
|
GenericConverter converter = matchConverterByClassPair(sourceType.getObjectType(), targetType.getObjectType());
|
||||||
LinkedList<Class> classQueue = new LinkedList<Class>();
|
if (converter == null) {
|
||||||
classQueue.addFirst(sourceType);
|
for (GenericConverter matchableConverter : this.matchableConverters) {
|
||||||
while (!classQueue.isEmpty()) {
|
if (matchableConverter.canConvert(sourceType, targetType)) {
|
||||||
Class currentClass = classQueue.removeLast();
|
return matchableConverter;
|
||||||
Map<Class, GenericConverter> converters = getConvertersForSource(currentClass);
|
|
||||||
GenericConverter converter = getConverter(converters, targetType);
|
|
||||||
if (converter != null) {
|
|
||||||
return converter;
|
|
||||||
}
|
|
||||||
Class[] interfaces = currentClass.getInterfaces();
|
|
||||||
for (Class ifc : interfaces) {
|
|
||||||
classQueue.addFirst(ifc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Map<Class, GenericConverter> objectConverters = getConvertersForSource(Object.class);
|
|
||||||
return getConverter(objectConverters, targetType);
|
|
||||||
} else {
|
|
||||||
LinkedList<Class> classQueue = new LinkedList<Class>();
|
|
||||||
classQueue.addFirst(sourceType);
|
|
||||||
while (!classQueue.isEmpty()) {
|
|
||||||
Class currentClass = classQueue.removeLast();
|
|
||||||
Map<Class, GenericConverter> converters = getConvertersForSource(currentClass);
|
|
||||||
GenericConverter converter = getConverter(converters, targetType);
|
|
||||||
if (converter != null) {
|
|
||||||
return converter;
|
|
||||||
}
|
|
||||||
if (currentClass.getSuperclass() != null) {
|
|
||||||
classQueue.addFirst(currentClass.getSuperclass());
|
|
||||||
}
|
|
||||||
Class[] interfaces = currentClass.getInterfaces();
|
|
||||||
for (Class ifc : interfaces) {
|
|
||||||
classQueue.addFirst(ifc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal helpers
|
// internal helpers
|
||||||
|
|
||||||
private void addGenericConverter(Class sourceType, Class targetType, GenericConverter converter) {
|
private void addGenericConverter(GenericConverter converter) {
|
||||||
getSourceMap(sourceType).put(targetType, converter);
|
this.matchableConverters.add(converter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Class> getRequiredTypeInfo(Object converter) {
|
private List<Class> getRequiredTypeInfo(Object converter) {
|
||||||
|
@ -275,6 +252,46 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GenericConverter matchConverterByClassPair(Class sourceType, Class targetType) {
|
||||||
|
if (sourceType.isInterface()) {
|
||||||
|
LinkedList<Class> classQueue = new LinkedList<Class>();
|
||||||
|
classQueue.addFirst(sourceType);
|
||||||
|
while (!classQueue.isEmpty()) {
|
||||||
|
Class currentClass = classQueue.removeLast();
|
||||||
|
Map<Class, GenericConverter> converters = getConvertersForSource(currentClass);
|
||||||
|
GenericConverter converter = getConverter(converters, targetType);
|
||||||
|
if (converter != null) {
|
||||||
|
return converter;
|
||||||
|
}
|
||||||
|
Class[] interfaces = currentClass.getInterfaces();
|
||||||
|
for (Class ifc : interfaces) {
|
||||||
|
classQueue.addFirst(ifc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<Class, GenericConverter> objectConverters = getConvertersForSource(Object.class);
|
||||||
|
return getConverter(objectConverters, targetType);
|
||||||
|
} else {
|
||||||
|
LinkedList<Class> classQueue = new LinkedList<Class>();
|
||||||
|
classQueue.addFirst(sourceType);
|
||||||
|
while (!classQueue.isEmpty()) {
|
||||||
|
Class currentClass = classQueue.removeLast();
|
||||||
|
Map<Class, GenericConverter> converters = getConvertersForSource(currentClass);
|
||||||
|
GenericConverter converter = getConverter(converters, targetType);
|
||||||
|
if (converter != null) {
|
||||||
|
return converter;
|
||||||
|
}
|
||||||
|
if (currentClass.getSuperclass() != null) {
|
||||||
|
classQueue.addFirst(currentClass.getSuperclass());
|
||||||
|
}
|
||||||
|
Class[] interfaces = currentClass.getInterfaces();
|
||||||
|
for (Class ifc : interfaces) {
|
||||||
|
classQueue.addFirst(ifc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Map<Class, GenericConverter> getSourceMap(Class sourceType) {
|
private Map<Class, GenericConverter> getSourceMap(Class sourceType) {
|
||||||
Map<Class, GenericConverter> sourceMap = sourceTypeConverters.get(sourceType);
|
Map<Class, GenericConverter> sourceMap = sourceTypeConverters.get(sourceType);
|
||||||
if (sourceMap == null) {
|
if (sourceMap == null) {
|
||||||
|
@ -292,11 +309,10 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
return converters;
|
return converters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GenericConverter getConverter(Map<Class, GenericConverter> converters, TypeDescriptor targetType) {
|
private GenericConverter getConverter(Map<Class, GenericConverter> converters, Class targetType) {
|
||||||
Class targetClass = targetType.getObjectType();
|
if (targetType.isInterface()) {
|
||||||
if (targetClass.isInterface()) {
|
|
||||||
LinkedList<Class> classQueue = new LinkedList<Class>();
|
LinkedList<Class> classQueue = new LinkedList<Class>();
|
||||||
classQueue.addFirst(targetClass);
|
classQueue.addFirst(targetType);
|
||||||
while (!classQueue.isEmpty()) {
|
while (!classQueue.isEmpty()) {
|
||||||
Class currentClass = classQueue.removeLast();
|
Class currentClass = classQueue.removeLast();
|
||||||
GenericConverter converter = converters.get(currentClass);
|
GenericConverter converter = converters.get(currentClass);
|
||||||
|
@ -311,7 +327,7 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
return converters.get(Object.class);
|
return converters.get(Object.class);
|
||||||
} else {
|
} else {
|
||||||
LinkedList<Class> classQueue = new LinkedList<Class>();
|
LinkedList<Class> classQueue = new LinkedList<Class>();
|
||||||
classQueue.addFirst(targetClass);
|
classQueue.addFirst(targetType);
|
||||||
while (!classQueue.isEmpty()) {
|
while (!classQueue.isEmpty()) {
|
||||||
Class currentClass = classQueue.removeLast();
|
Class currentClass = classQueue.removeLast();
|
||||||
GenericConverter converter = converters.get(currentClass);
|
GenericConverter converter = converters.get(currentClass);
|
||||||
|
@ -338,7 +354,11 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
this.converter = converter;
|
this.converter = converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object convert(Object source, TypeDescriptor type) {
|
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
|
throw new UnsupportedOperationException("Should not be called");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
return converter.convert(source);
|
return converter.convert(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,7 +372,11 @@ public class GenericConversionService implements ConversionService, ConverterReg
|
||||||
this.converterFactory = converterFactory;
|
this.converterFactory = converterFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object convert(Object source, TypeDescriptor targetType) {
|
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
|
throw new UnsupportedOperationException("Should not be called");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
return converterFactory.getConverter(targetType.getObjectType()).convert(source);
|
return converterFactory.getConverter(targetType.getObjectType()).convert(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,9 @@ import org.springframework.core.convert.converter.ConverterFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uniform Converter interface used by GenericConversionService.
|
* Uniform Converter interface used by GenericConversionService.
|
||||||
* This interface is an internal detail of the GenericConversionService implementation.
|
* This interface is primarily an internal detail of the GenericConversionService implementation.
|
||||||
* It should generally not be implemented by application code directly.
|
* It should generally not be implemented by application code directly.
|
||||||
* See {@link Converter} and {@link ConverterFactory} interfaces for public converter SPIs.
|
* See {@link Converter} and {@link ConverterFactory} interfaces for simpler public converter SPIs.
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see Converter
|
* @see Converter
|
||||||
|
@ -31,12 +31,21 @@ import org.springframework.core.convert.converter.ConverterFactory;
|
||||||
*/
|
*/
|
||||||
public interface GenericConverter {
|
public interface GenericConverter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can this converter convert the sourceType to targetType.
|
||||||
|
* @param sourceType context about the sourceType to convert to
|
||||||
|
* @param targetType context about the targetType to convert to
|
||||||
|
* @return true if so, false otherwise
|
||||||
|
*/
|
||||||
|
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert the source to the targetType described by the TypeDescriptor.
|
* Convert the source to the targetType described by the TypeDescriptor.
|
||||||
* @param source the source object to convert (never null)
|
* @param source the source object to convert (never null)
|
||||||
* @param targetType the target type to convert to
|
* @param sourceType context about the source type to convert from
|
||||||
|
* @param targetType context about the target type to convert to
|
||||||
* @return the converted object
|
* @return the converted object
|
||||||
*/
|
*/
|
||||||
Object convert(Object source, TypeDescriptor targetType);
|
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,33 +5,37 @@ import java.util.Map;
|
||||||
import org.springframework.core.CollectionFactory;
|
import org.springframework.core.CollectionFactory;
|
||||||
import org.springframework.core.convert.TypeDescriptor;
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
|
|
||||||
class MapToMapGenericConverter implements GenericConverter {
|
class MapGenericConverter implements GenericConverter {
|
||||||
|
|
||||||
private GenericConversionService conversionService;
|
private GenericConversionService conversionService;
|
||||||
|
|
||||||
public MapToMapGenericConverter(GenericConversionService conversionService) {
|
public MapGenericConverter(GenericConversionService conversionService) {
|
||||||
this.conversionService = conversionService;
|
this.conversionService = conversionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object convert(Object source, TypeDescriptor targetType) {
|
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
|
return sourceType.isMap() && targetType.isMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
|
||||||
Map sourceMap = (Map) source;
|
Map sourceMap = (Map) source;
|
||||||
Class targetKeyType = targetType.getMapKeyType();
|
TypeDescriptor targetKeyType = targetType.getMapKeyTypeDescriptor();
|
||||||
Class targetValueType = targetType.getMapValueType();
|
TypeDescriptor targetValueType = targetType.getMapValueTypeDescriptor();
|
||||||
if (targetKeyType == null && targetValueType == null) {
|
if (targetKeyType == null && targetValueType == null) {
|
||||||
return compatibleMapWithoutEntryConversion(sourceMap, targetType);
|
return compatibleMapWithoutEntryConversion(sourceMap, targetType);
|
||||||
}
|
}
|
||||||
Class[] sourceEntryTypes = getMapEntryTypes(sourceMap);
|
TypeDescriptor[] sourceEntryTypes = getMapEntryTypes(sourceMap);
|
||||||
Class sourceKeyType = sourceEntryTypes[0];
|
TypeDescriptor sourceKeyType = sourceEntryTypes[0];
|
||||||
Class sourceValueType = sourceEntryTypes[1];
|
TypeDescriptor sourceValueType = sourceEntryTypes[1];
|
||||||
if (sourceKeyType == null && sourceValueType == null) {
|
if (sourceKeyType == null && sourceValueType == null) {
|
||||||
return compatibleMapWithoutEntryConversion(sourceMap, targetType);
|
return compatibleMapWithoutEntryConversion(sourceMap, targetType);
|
||||||
}
|
}
|
||||||
boolean keysCompatible = false;
|
boolean keysCompatible = false;
|
||||||
if (targetKeyType != null && sourceKeyType != null && targetKeyType.isAssignableFrom(sourceKeyType)) {
|
if (sourceKeyType != null && targetKeyType != null && sourceKeyType.isAssignableTo(targetKeyType)) {
|
||||||
keysCompatible = true;
|
keysCompatible = true;
|
||||||
}
|
}
|
||||||
boolean valuesCompatible = false;
|
boolean valuesCompatible = false;
|
||||||
if (targetValueType != null && sourceValueType != null && targetValueType.isAssignableFrom(sourceValueType)) {
|
if (sourceValueType != null && targetValueType != null && sourceValueType.isAssignableTo(targetValueType)) {
|
||||||
valuesCompatible = true;
|
valuesCompatible = true;
|
||||||
}
|
}
|
||||||
if (keysCompatible && valuesCompatible) {
|
if (keysCompatible && valuesCompatible) {
|
||||||
|
@ -46,7 +50,7 @@ class MapToMapGenericConverter implements GenericConverter {
|
||||||
return targetMap;
|
return targetMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class[] getMapEntryTypes(Map sourceMap) {
|
private TypeDescriptor[] getMapEntryTypes(Map sourceMap) {
|
||||||
Class keyType = null;
|
Class keyType = null;
|
||||||
Class valueType = null;
|
Class valueType = null;
|
||||||
for (Object entry : sourceMap.entrySet()) {
|
for (Object entry : sourceMap.entrySet()) {
|
||||||
|
@ -63,7 +67,7 @@ class MapToMapGenericConverter implements GenericConverter {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Class[] { keyType, valueType };
|
return new TypeDescriptor[] { TypeDescriptor.valueOf(keyType), TypeDescriptor.valueOf(valueType) };
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map compatibleMapWithoutEntryConversion(Map source, TypeDescriptor targetType) {
|
private Map compatibleMapWithoutEntryConversion(Map source, TypeDescriptor targetType) {
|
||||||
|
@ -82,26 +86,32 @@ class MapToMapGenericConverter implements GenericConverter {
|
||||||
|
|
||||||
private GenericConverter valueConverter;
|
private GenericConverter valueConverter;
|
||||||
|
|
||||||
private TypeDescriptor targetKeyTypeDescriptor;
|
private TypeDescriptor sourceKeyType;
|
||||||
|
|
||||||
private TypeDescriptor targetValueTypeDescriptor;
|
private TypeDescriptor sourceValueType;
|
||||||
|
|
||||||
public MapEntryConverter(Class sourceKeyType, Class sourceValueType, Class targetKeyType,
|
private TypeDescriptor targetKeyType;
|
||||||
Class targetValueType, boolean keysCompatible, boolean valuesCompatible,
|
|
||||||
|
private TypeDescriptor targetValueType;
|
||||||
|
|
||||||
|
public MapEntryConverter(TypeDescriptor sourceKeyType, TypeDescriptor sourceValueType, TypeDescriptor targetKeyType,
|
||||||
|
TypeDescriptor targetValueType, boolean keysCompatible, boolean valuesCompatible,
|
||||||
GenericConversionService conversionService) {
|
GenericConversionService conversionService) {
|
||||||
if (sourceKeyType != null && targetKeyType != null && !keysCompatible) {
|
if (sourceKeyType != TypeDescriptor.NULL && targetKeyType != TypeDescriptor.NULL && !keysCompatible) {
|
||||||
this.targetKeyTypeDescriptor = TypeDescriptor.valueOf(targetKeyType);
|
this.keyConverter = conversionService.getConverter(sourceKeyType, targetKeyType);
|
||||||
this.keyConverter = conversionService.getConverter(sourceKeyType, targetKeyTypeDescriptor);
|
this.sourceKeyType = sourceKeyType;
|
||||||
|
this.targetKeyType = targetKeyType;
|
||||||
}
|
}
|
||||||
if (sourceValueType != null && targetValueType != null && !valuesCompatible) {
|
if (sourceValueType != TypeDescriptor.NULL && targetValueType != TypeDescriptor.NULL && !valuesCompatible) {
|
||||||
this.targetValueTypeDescriptor = TypeDescriptor.valueOf(targetValueType);
|
this.valueConverter = conversionService.getConverter(sourceValueType, targetValueType);
|
||||||
this.valueConverter = conversionService.getConverter(sourceValueType, targetValueTypeDescriptor);
|
this.targetKeyType = targetKeyType;
|
||||||
|
this.targetValueType = targetValueType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object convertKey(Object sourceKey) {
|
public Object convertKey(Object sourceKey) {
|
||||||
if (sourceKey != null && this.keyConverter != null) {
|
if (sourceKey != null && this.keyConverter != null) {
|
||||||
return this.keyConverter.convert(sourceKey, targetKeyTypeDescriptor);
|
return this.keyConverter.convert(sourceKey, sourceKeyType, targetKeyType);
|
||||||
} else {
|
} else {
|
||||||
return sourceKey;
|
return sourceKey;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +119,7 @@ class MapToMapGenericConverter implements GenericConverter {
|
||||||
|
|
||||||
public Object convertValue(Object sourceValue) {
|
public Object convertValue(Object sourceValue) {
|
||||||
if (sourceValue != null && this.valueConverter != null) {
|
if (sourceValue != null && this.valueConverter != null) {
|
||||||
return this.valueConverter.convert(sourceValue, targetValueTypeDescriptor);
|
return this.valueConverter.convert(sourceValue, sourceValueType, targetValueType);
|
||||||
} else {
|
} else {
|
||||||
return sourceValue;
|
return sourceValue;
|
||||||
}
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package org.springframework.core.convert.support;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
|
|
||||||
|
public interface MatchableGenericConverter extends GenericConverter {
|
||||||
|
|
||||||
|
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
|
||||||
|
|
||||||
|
}
|
|
@ -87,17 +87,16 @@ public class GenericConversionServiceTests {
|
||||||
assertNull(converter.convert(null, Integer.class));
|
assertNull(converter.convert(null, Integer.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void convertNullTargetClass() {
|
public void convertNullTargetClass() {
|
||||||
assertEquals("3", converter.convert("3", (Class<?>)null));
|
assertEquals("3", converter.convert("3", (Class<?>) null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void convertNullConversionPointType() {
|
public void convertNullConversionPointType() {
|
||||||
assertEquals(null, converter.convert("3", TypeDescriptor.NULL));
|
assertEquals(null, converter.convert(3, TypeDescriptor.valueOf(String.class), TypeDescriptor.NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void convertWrongTypeArgument() {
|
public void convertWrongTypeArgument() {
|
||||||
converter.addConverterFactory(new StringToNumberConverterFactory());
|
converter.addConverterFactory(new StringToNumberConverterFactory());
|
||||||
|
@ -128,7 +127,6 @@ public class GenericConversionServiceTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void convertArrayToArray() {
|
public void convertArrayToArray() {
|
||||||
converter.addConverterFactory(new StringToNumberConverterFactory());
|
converter.addConverterFactory(new StringToNumberConverterFactory());
|
||||||
Integer[] result = converter.convert(new String[] { "1", "2", "3" }, Integer[].class);
|
Integer[] result = converter.convert(new String[] { "1", "2", "3" }, Integer[].class);
|
||||||
|
@ -138,7 +136,6 @@ public class GenericConversionServiceTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
|
||||||
public void convertArrayToPrimitiveArray() {
|
public void convertArrayToPrimitiveArray() {
|
||||||
converter.addConverterFactory(new StringToNumberConverterFactory());
|
converter.addConverterFactory(new StringToNumberConverterFactory());
|
||||||
int[] result = converter.convert(new String[] { "1", "2", "3" }, int[].class);
|
int[] result = converter.convert(new String[] { "1", "2", "3" }, int[].class);
|
||||||
|
@ -147,6 +144,14 @@ public class GenericConversionServiceTests {
|
||||||
assertEquals(3, result[2]);
|
assertEquals(3, result[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void convertArrayToArrayAssignable() {
|
||||||
|
int[] result = converter.convert(new int[] { 1, 2, 3 }, int[].class);
|
||||||
|
assertEquals(1, result[0]);
|
||||||
|
assertEquals(2, result[1]);
|
||||||
|
assertEquals(3, result[2]);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore
|
@Ignore
|
||||||
public void convertArrayToListInterface() {
|
public void convertArrayToListInterface() {
|
||||||
|
@ -162,7 +167,8 @@ public class GenericConversionServiceTests {
|
||||||
@Ignore
|
@Ignore
|
||||||
public void convertArrayToListGenericTypeConversion() throws Exception {
|
public void convertArrayToListGenericTypeConversion() throws Exception {
|
||||||
converter.addConverterFactory(new StringToNumberConverterFactory());
|
converter.addConverterFactory(new StringToNumberConverterFactory());
|
||||||
List<Integer> result = (List<Integer>) converter.convert(new String[] { "1", "2", "3" }, new TypeDescriptor(getClass().getDeclaredField("genericList")));
|
List<Integer> result = (List<Integer>) converter.convert(new String[] { "1", "2", "3" }, TypeDescriptor
|
||||||
|
.valueOf(String[].class), new TypeDescriptor(getClass().getDeclaredField("genericList")));
|
||||||
assertEquals(new Integer("1"), result.get(0));
|
assertEquals(new Integer("1"), result.get(0));
|
||||||
assertEquals(new Integer("2"), result.get(1));
|
assertEquals(new Integer("2"), result.get(1));
|
||||||
assertEquals(new Integer("3"), result.get(2));
|
assertEquals(new Integer("3"), result.get(2));
|
||||||
|
@ -221,7 +227,8 @@ public class GenericConversionServiceTests {
|
||||||
foo.add("1");
|
foo.add("1");
|
||||||
foo.add("2");
|
foo.add("2");
|
||||||
foo.add("3");
|
foo.add("3");
|
||||||
List<Integer> bar = (List<Integer>)converter.convert(foo, new TypeDescriptor(getClass().getField("genericList")));
|
List<Integer> bar = (List<Integer>) converter.convert(foo, TypeDescriptor.valueOf(List.class),
|
||||||
|
new TypeDescriptor(getClass().getField("genericList")));
|
||||||
assertEquals(new Integer(1), bar.get(0));
|
assertEquals(new Integer(1), bar.get(0));
|
||||||
assertEquals(new Integer(2), bar.get(1));
|
assertEquals(new Integer(2), bar.get(1));
|
||||||
assertEquals(new Integer(3), bar.get(2));
|
assertEquals(new Integer(3), bar.get(2));
|
||||||
|
@ -236,7 +243,8 @@ public class GenericConversionServiceTests {
|
||||||
foo.put("2", "BAZ");
|
foo.put("2", "BAZ");
|
||||||
converter.addConverterFactory(new StringToNumberConverterFactory());
|
converter.addConverterFactory(new StringToNumberConverterFactory());
|
||||||
converter.addConverterFactory(new StringToEnumConverterFactory());
|
converter.addConverterFactory(new StringToEnumConverterFactory());
|
||||||
Map<String, FooEnum> map = (Map<String, FooEnum>) converter.convert(foo, new TypeDescriptor(getClass().getField("genericMap")));
|
Map<String, FooEnum> map = (Map<String, FooEnum>) converter.convert(foo, TypeDescriptor.valueOf(Map.class),
|
||||||
|
new TypeDescriptor(getClass().getField("genericMap")));
|
||||||
assertEquals(map.get(1), FooEnum.BAR);
|
assertEquals(map.get(1), FooEnum.BAR);
|
||||||
assertEquals(map.get(2), FooEnum.BAZ);
|
assertEquals(map.get(2), FooEnum.BAZ);
|
||||||
}
|
}
|
||||||
|
@ -262,7 +270,6 @@ public class GenericConversionServiceTests {
|
||||||
assertEquals(new Integer(3), result[2]);
|
assertEquals(new Integer(3), result[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static enum FooEnum {
|
public static enum FooEnum {
|
||||||
BAR, BAZ
|
BAR, BAZ
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,26 +38,24 @@ import org.springframework.util.Assert;
|
||||||
*/
|
*/
|
||||||
public class StandardTypeConverter implements TypeConverter {
|
public class StandardTypeConverter implements TypeConverter {
|
||||||
|
|
||||||
private final ConversionService typeConverter;
|
private final ConversionService conversionService;
|
||||||
|
|
||||||
|
|
||||||
public StandardTypeConverter() {
|
public StandardTypeConverter() {
|
||||||
this.typeConverter = new DefaultConversionService();
|
this.conversionService = new DefaultConversionService();
|
||||||
}
|
}
|
||||||
|
|
||||||
public StandardTypeConverter(ConversionService typeConverter) {
|
public StandardTypeConverter(ConversionService typeConverter) {
|
||||||
Assert.notNull(typeConverter, "ConversionService must not be null");
|
Assert.notNull(typeConverter, "ConversionService must not be null");
|
||||||
this.typeConverter = typeConverter;
|
this.conversionService = typeConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
||||||
return this.typeConverter.canConvert(sourceType, targetType);
|
return this.conversionService.canConvert(sourceType, targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object convertValue(Object value, TypeDescriptor typeDescriptor) throws EvaluationException {
|
public Object convertValue(Object value, TypeDescriptor typeDescriptor) throws EvaluationException {
|
||||||
try {
|
try {
|
||||||
return this.typeConverter.convert(value, typeDescriptor);
|
return this.conversionService.convert(value, TypeDescriptor.forObject(value), typeDescriptor);
|
||||||
}
|
}
|
||||||
catch (ConverterNotFoundException cenfe) {
|
catch (ConverterNotFoundException cenfe) {
|
||||||
throw new SpelEvaluationException(cenfe, SpelMessage.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString());
|
throw new SpelEvaluationException(cenfe, SpelMessage.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString());
|
||||||
|
|
|
@ -101,21 +101,11 @@ public class ExpressionTestsUsingCoreConversionService extends ExpressionTestCas
|
||||||
private final DefaultConversionService service = new DefaultConversionService();
|
private final DefaultConversionService service = new DefaultConversionService();
|
||||||
|
|
||||||
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
||||||
return this.service.canConvert(sourceType, TypeDescriptor.valueOf(targetType));
|
return this.service.canConvert(sourceType, targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canConvert(Class<?> sourceType, TypeDescriptor typeDescriptor) {
|
|
||||||
return this.service.canConvert(sourceType, typeDescriptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("cast")
|
|
||||||
public <T> T convertValue(Object value, Class<T> targetType) throws EvaluationException {
|
|
||||||
return (T) this.service.convert(value,TypeDescriptor.valueOf(targetType));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public Object convertValue(Object value, TypeDescriptor typeDescriptor) throws EvaluationException {
|
public Object convertValue(Object value, TypeDescriptor typeDescriptor) throws EvaluationException {
|
||||||
return this.service.convert(value, typeDescriptor);
|
return this.service.convert(value, TypeDescriptor.forObject(value), typeDescriptor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue