master
Keith Donald 16 years ago
parent ea9df82d2a
commit 7f6fc4e82e
  1. 6
      org.springframework.core/src/main/java/org/springframework/core/convert/ConversionExecutionException.java
  2. 2
      org.springframework.core/src/main/java/org/springframework/core/convert/ConversionExecutor.java
  3. 5
      org.springframework.core/src/main/java/org/springframework/core/convert/ConversionExecutorNotFoundException.java
  4. 8
      org.springframework.core/src/main/java/org/springframework/core/convert/ConversionService.java
  5. 2
      org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java
  6. 2
      org.springframework.core/src/main/java/org/springframework/core/convert/TypedValue.java
  7. 2
      org.springframework.core/src/main/java/org/springframework/core/convert/service/DefaultConversionService.java
  8. 51
      org.springframework.core/src/main/java/org/springframework/core/convert/service/GenericConversionService.java
  9. 15
      org.springframework.core/src/main/java/org/springframework/core/convert/service/StaticConversionExecutor.java
  10. 2
      org.springframework.core/src/main/java/org/springframework/core/convert/service/StaticSuperConversionExecutor.java
  11. 29
      org.springframework.core/src/main/java/org/springframework/core/convert/service/SuperTwoWayConverterConverter.java
  12. 5
      org.springframework.core/src/test/java/org/springframework/core/convert/service/GenericConversionServiceTests.java

@ -68,7 +68,7 @@ public class ConversionExecutionException extends ConversionException {
}
/**
* Returns the actual value we tried to convert, an instance of {@link #getSourceClass()}.
* Returns the actual value we tried to convert, an instance of {@link #getSourceType()}.
*/
public Object getValue() {
return value;
@ -77,14 +77,14 @@ public class ConversionExecutionException extends ConversionException {
/**
* Returns the source type we tried to convert the value from.
*/
public TypeDescriptor getSourceClass() {
public TypeDescriptor getSourceType() {
return sourceType;
}
/**
* Returns the target type we tried to convert the value to.
*/
public TypeDescriptor getTargetClass() {
public TypeDescriptor getTargetType() {
return targetType;
}

@ -25,7 +25,7 @@ package org.springframework.core.convert;
public interface ConversionExecutor {
/**
* Convert the source to T.
* Convert the source.
* @param source the source to convert
* @throws ConversionExecutionException if an exception occurs during type conversion
*/

@ -18,7 +18,6 @@ package org.springframework.core.convert;
/**
* Thrown when a conversion executor could not be found in a conversion service.
*
* @see ConversionService#getConversionExecutor(Class, Class)
* @author Keith Donald
*/
public class ConversionExecutorNotFoundException extends ConversionException {
@ -40,14 +39,14 @@ public class ConversionExecutorNotFoundException extends ConversionException {
}
/**
* Returns the source type requested to convert from.
* Returns the source type that was requested to convert from.
*/
public TypeDescriptor getSourceType() {
return sourceType;
}
/**
* Returns the target type requested to convert to.
* Returns the target type that was requested to convert to.
*/
public TypeDescriptor getTargetType() {
return targetType;

@ -17,10 +17,12 @@ package org.springframework.core.convert;
/**
* A service interface for type conversion. This is the entry point into the convert system. Call one of the
* {@link #executeConversion(Object, Class) executeConversion} operations to perform a thread-safe type conversion using
* this system. Call one of the {@link #getConversionExecutor(Class, Class) getConversionExecutor} operations to obtain
* <i>executeConversion</i> operations to perform a thread-safe type conversion using
* this system. Call one of the <i>getConversionExecutor</i> operations to obtain
* a thread-safe {@link ConversionExecutor} command for later use.
*
* TODO - is TypeDescriptor/TypedValue needed on source?
*
* @author Keith Donald
*/
public interface ConversionService {
@ -86,7 +88,7 @@ public interface ConversionService {
TypeDescriptor targetType) throws ConversionExecutorNotFoundException;
/**
* Get a type by its name; may be the fully-qualified class name or a registered alias.
* 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
*/
public Class<?> getType(String name);

@ -10,7 +10,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
/**
* Type metadata about a bindable value.
* Type metadata about a bindable target value.
*
* @author Keith Donald
*/

@ -7,6 +7,8 @@ package org.springframework.core.convert;
* It also allows access to field-level or method-level annotations.
* All of this context can be utilized when performing a type conversion as part of a data binding routine.
*
* TODO - is this needed?
*
* @author Keith Donald
*/
public class TypedValue {

@ -79,7 +79,7 @@ public class DefaultConversionService extends GenericConversionService {
addAlias("long", Long.class);
addAlias("float", Float.class);
addAlias("double", Double.class);
addAlias("bigInteger", BigInteger.class);
addAlias("bigInt", BigInteger.class);
addAlias("bigDecimal", BigDecimal.class);
addAlias("locale", Locale.class);
addAlias("enum", Enum.class);

@ -15,12 +15,10 @@
*/
package org.springframework.core.convert.service;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
@ -35,6 +33,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.TypedValue;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterInfo;
import org.springframework.core.convert.converter.SuperConverter;
import org.springframework.core.convert.converter.SuperTwoWayConverter;
import org.springframework.util.Assert;
@ -42,8 +41,6 @@ import org.springframework.util.Assert;
/**
* Base implementation of a conversion service. Initially empty, e.g. no converters are registered by default.
*
* TODO auto-conversion of generic collection elements
*
* @author Keith Donald
*/
@SuppressWarnings("unchecked")
@ -137,9 +134,6 @@ public class GenericConversionService implements ConversionService {
/**
* 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.
*
* TODO - I think this is going to force indexing on a getSourceClass/getTargetclass prop instead generic args
*
* @param sourceClass 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 converter the super two way converter
@ -147,12 +141,12 @@ public class GenericConversionService implements ConversionService {
*/
public static <S, T> Converter<S, T> converterFor(Class<S> sourceClass, Class<T> targetClass,
SuperTwoWayConverter converter) {
return new SuperTwoWayConverterConverter<S, T>(converter, sourceClass, targetClass);
return new SuperTwoWayConverterConverter(converter, sourceClass, targetClass);
}
/**
* Add a convenient alias for the target type. {@link #getType(String)} can then be used to lookup the type
* given the alias.
* Add a convenient alias for the target type. {@link #getType(String)} can then be used to lookup the type given
* the alias.
* @see #getType(String)
*/
public void addAlias(String alias, Class targetType) {
@ -164,9 +158,9 @@ public class GenericConversionService implements ConversionService {
public boolean canConvert(TypedValue source, TypeDescriptor targetType) {
return false;
}
public Object executeConversion(TypedValue source, TypeDescriptor targetType) throws ConversionExecutorNotFoundException,
ConversionException {
public Object executeConversion(TypedValue source, TypeDescriptor targetType)
throws ConversionExecutorNotFoundException, ConversionException {
Assert.notNull(source, "The source to convert from is required");
if (source.isNull()) {
return null;
@ -179,7 +173,7 @@ public class GenericConversionService implements ConversionService {
Assert.notNull(source, "The source to convert from is required");
if (source.isNull()) {
return null;
}
}
return getConversionExecutor(converterId, source.getTypeDescriptor(), targetType).execute(source.getValue());
}
@ -204,14 +198,14 @@ public class GenericConversionService implements ConversionService {
if (sourceType.isCollection()) {
return new CollectionToArray(sourceType, targetType, this);
} else {
throw new UnsupportedOperationException("Object to Array not yet supported");
throw new UnsupportedOperationException("Object to Array conversion not yet supported");
}
}
if (sourceType.isCollection()) {
if (targetType.isCollection()) {
return new CollectionToCollection(sourceType, targetType, this);
} else {
throw new UnsupportedOperationException("Object to collection not yet supported");
throw new UnsupportedOperationException("Object to Collection conversion not yet supported");
}
}
Converter converter = findRegisteredConverter(sourceType, targetType);
@ -257,18 +251,22 @@ public class GenericConversionService implements ConversionService {
private List getRequiredTypeInfo(Object converter) {
List typeInfo = new ArrayList(2);
if (converter instanceof ConverterInfo) {
ConverterInfo info = (ConverterInfo) converter;
typeInfo.add(info.getSourceType());
typeInfo.add(info.getTargetType());
return typeInfo;
}
Class classToIntrospect = converter.getClass();
while (classToIntrospect != null) {
Type[] genericInterfaces = classToIntrospect.getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType parameterizedInterface = (ParameterizedType) genericInterface;
if (Converter.class.equals(parameterizedInterface.getRawType())
|| SuperConverter.class.isAssignableFrom((Class) parameterizedInterface.getRawType())) {
Class s = getParameterClass(parameterizedInterface.getActualTypeArguments()[0], converter
.getClass());
Class t = getParameterClass(parameterizedInterface.getActualTypeArguments()[1], converter
.getClass());
ParameterizedType pInterface = (ParameterizedType) genericInterface;
if (Converter.class.equals(pInterface.getRawType())
|| SuperConverter.class.isAssignableFrom((Class) pInterface.getRawType())) {
Class s = getParameterClass(pInterface.getActualTypeArguments()[0], converter.getClass());
Class t = getParameterClass(pInterface.getActualTypeArguments()[1], converter.getClass());
typeInfo.add(getParameterClass(s, converter.getClass()));
typeInfo.add(getParameterClass(t, converter.getClass()));
break;
@ -315,7 +313,7 @@ public class GenericConversionService implements ConversionService {
private Converter findRegisteredConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
Class<?> sourceClass = sourceType.getWrapperTypeIfPrimitive();
Class<?> targetClass = targetType.getWrapperTypeIfPrimitive();
Class<?> targetClass = targetType.getWrapperTypeIfPrimitive();
if (sourceClass.isInterface()) {
LinkedList classQueue = new LinkedList();
classQueue.addFirst(sourceClass);
@ -366,7 +364,7 @@ public class GenericConversionService implements ConversionService {
private SuperConverter findRegisteredSuperConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
Class<?> sourceClass = sourceType.getWrapperTypeIfPrimitive();
Class<?> targetClass = targetType.getWrapperTypeIfPrimitive();
Class<?> targetClass = targetType.getWrapperTypeIfPrimitive();
if (sourceClass.isInterface()) {
LinkedList classQueue = new LinkedList();
classQueue.addFirst(sourceClass);
@ -452,7 +450,8 @@ public class GenericConversionService implements ConversionService {
}
public ConversionExecutor getElementConverter(Class<?> sourceElementType, Class<?> targetElementType) {
return getConversionExecutor(TypeDescriptor.valueOf(sourceElementType), TypeDescriptor.valueOf(targetElementType));
return getConversionExecutor(TypeDescriptor.valueOf(sourceElementType), TypeDescriptor
.valueOf(targetElementType));
}
}

@ -21,6 +21,7 @@ import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.style.ToStringCreator;
@SuppressWarnings("unchecked")
class StaticConversionExecutor implements ConversionExecutor {
private final TypeDescriptor sourceType;
@ -35,26 +36,18 @@ class StaticConversionExecutor implements ConversionExecutor {
this.converter = converter;
}
public TypeDescriptor getSourceType() {
return sourceType;
}
public TypeDescriptor getTargetType() {
return targetType;
}
public Object execute(Object source) throws ConversionExecutionException {
if (source == null) {
return null;
}
if (sourceType != null && !sourceType.isInstance(source)) {
throw new ConversionExecutionException(source, getSourceType(), getTargetType(), "Source object "
+ source + " to convert is expected to be an instance of [" + getSourceType().getName() + "]");
throw new ConversionExecutionException(source, sourceType, targetType, "Source object "
+ source + " to convert is expected to be an instance of [" + sourceType.getName() + "]");
}
try {
return converter.convert(source);
} catch (Exception e) {
throw new ConversionExecutionException(source, getSourceType(), getTargetType(), e);
throw new ConversionExecutionException(source, sourceType, targetType, e);
}
}

@ -20,8 +20,8 @@ import org.springframework.core.convert.ConversionExecutor;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.SuperConverter;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
@SuppressWarnings("unchecked")
class StaticSuperConversionExecutor implements ConversionExecutor {
private final TypeDescriptor sourceType;

@ -1,6 +1,7 @@
package org.springframework.core.convert.service;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterInfo;
import org.springframework.core.convert.converter.SuperConverter;
import org.springframework.core.convert.converter.SuperTwoWayConverter;
@ -9,26 +10,34 @@ import org.springframework.core.convert.converter.SuperTwoWayConverter;
* for applying more general {@link SuperConverter} logic to a specific source/target class pair.
*/
@SuppressWarnings("unchecked")
class SuperTwoWayConverterConverter<S, T> implements Converter<S, T> {
class SuperTwoWayConverterConverter implements Converter, ConverterInfo {
private SuperTwoWayConverter superConverter;
private Class sourceClass;
private Class sourceType;
private Class targetClass;
private Class targetType;
public SuperTwoWayConverterConverter(SuperTwoWayConverter superConverter, Class sourceClass, Class targetClass) {
public SuperTwoWayConverterConverter(SuperTwoWayConverter superConverter, Class sourceType, Class targetType) {
this.superConverter = superConverter;
this.sourceClass = sourceClass;
this.targetClass = targetClass;
this.sourceType = sourceType;
this.targetType = targetType;
}
public Class getSourceType() {
return sourceType;
}
public Class getTargetType() {
return targetType;
}
public T convert(S source) throws Exception {
return (T) superConverter.convert(source, targetClass);
public Object convert(Object source) throws Exception {
return superConverter.convert(source, targetType);
}
public S convertBack(T target) throws Exception {
return (S) superConverter.convertBack(target, sourceClass);
public Object convertBack(Object target) throws Exception {
return superConverter.convertBack(target, sourceType);
}
}

@ -575,9 +575,8 @@ public class GenericConversionServiceTests extends TestCase {
}
public void testSuperTwoWayConverterConverterAdaption() {
// this fails at the moment
//service.addConverter(GenericConversionService.converterFor(String.class, FooEnum.class, new StringToEnum()));
//assertEquals(FooEnum.BAR, service.executeConversion("BAR", FooEnum.class));
service.addConverter(GenericConversionService.converterFor(String.class, FooEnum.class, new StringToEnum()));
assertEquals(FooEnum.BAR, service.executeConversion(value("BAR"), type(FooEnum.class)));
}
private TypedValue value(Object obj) {

Loading…
Cancel
Save