added new ConverterRegistry operation; polishing

This commit is contained in:
Keith Donald 2011-05-24 03:47:50 +00:00
parent e25fbf2533
commit d02e37a307
5 changed files with 99 additions and 74 deletions

View File

@ -27,16 +27,28 @@ public interface ConverterRegistry {
/** /**
* Add a plain converter to this registry. * Add a plain converter to this registry.
* The convertible sourceType/targetType pair is derived from the Converter's parameterized types.
* @throws IllegalArgumentException if the parameterized types could not be resolved
*/ */
void addConverter(Converter<?, ?> converter); void addConverter(Converter<?, ?> converter);
/**
* Add a plain converter to this registry.
* The convertible sourceType/targetType pair is specified explicitly.
* Allows for a Converter to be reused for multiple distinct pairs without having to create a Converter class for each pair.
* @since 3.1
*/
void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter);
/** /**
* Add a generic converter to this registry. * Add a generic converter to this registry.
*/ */
void addConverter(GenericConverter converter); void addConverter(GenericConverter converter);
/** /**
* Add a ranged converter factory to this registry. * Add a ranged converter factory to this registry.
* The convertible sourceType/rangeType pair is derived from the ConverterFactory's parameterized types.
* @throws IllegalArgumentException if the parameterized types could not be resolved.
*/ */
void addConverterFactory(ConverterFactory<?, ?> converterFactory); void addConverterFactory(ConverterFactory<?, ?> converterFactory);

View File

@ -61,8 +61,7 @@ public abstract class ConversionServiceFactory {
} }
/** /**
* Create a new default ConversionService instance that can be safely modified. * Create a new default GenericConversionService instance that can be safely modified.
*
* @deprecated in Spring 3.1 in favor of {@link DefaultConversionService#DefaultConversionService()} * @deprecated in Spring 3.1 in favor of {@link DefaultConversionService#DefaultConversionService()}
*/ */
public static GenericConversionService createDefaultConversionService() { public static GenericConversionService createDefaultConversionService() {
@ -70,9 +69,8 @@ public abstract class ConversionServiceFactory {
} }
/** /**
* Populate the given ConversionService instance with all applicable default converters. * Populate the given GenericConversionService instance with the set of default converters.
* * @deprecated in Spring 3.1 in favor of {@link DefaultConversionService#addDefaultConverters(ConverterRegistry)}
* @deprecated in Spring 3.1 in favor of {@link DefaultConversionService#addDefaultConverters}
*/ */
public static void addDefaultConverters(GenericConversionService conversionService) { public static void addDefaultConverters(GenericConversionService conversionService) {
DefaultConversionService.addDefaultConverters(conversionService); DefaultConversionService.addDefaultConverters(conversionService);

View File

@ -18,13 +18,16 @@ package org.springframework.core.convert.support;
import java.util.Locale; import java.util.Locale;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.ConverterRegistry;
/** /**
* A specialization of {@link GenericConversionService} configured by default with * A specialization of {@link GenericConversionService} configured by default with
* converters appropriate for most applications. * converters appropriate for most environments.
* *
* <p>Designed for direct instantiation but also exposes the static * <p>Designed for direct instantiation but also exposes the static
* {@link #addDefaultConverters} utility method for ad hoc use against any * {@link #addDefaultConverters(ConverterRegistry)} utility method for ad hoc use against any
* {@code GenericConversionService} instance. * {@code ConverterRegistry} instance.
* *
* @author Chris Beams * @author Chris Beams
* @since 3.1 * @since 3.1
@ -33,62 +36,79 @@ public class DefaultConversionService extends GenericConversionService {
/** /**
* Create a new {@code DefaultConversionService} with the set of * Create a new {@code DefaultConversionService} with the set of
* {@linkplain DefaultConversionService#addDefaultConverters default converters}. * {@linkplain DefaultConversionService#addDefaultConverters(ConverterRegistry) default converters}.
*/ */
public DefaultConversionService() { public DefaultConversionService() {
addDefaultConverters(this); addDefaultConverters(this);
} }
// static utility methods
/** /**
* Add converters appropriate for most environments. * Add converters appropriate for most environments.
* @param conversionService the service to register default formatters against * @param converterRegistry the registry of converters to add to (must also be castable to ConversionService)
* @throws ClassCastException if the converterRegistry could not be cast to a ConversionService
*/ */
public static void addDefaultConverters(GenericConversionService conversionService) { public static void addDefaultConverters(ConverterRegistry converterRegistry) {
conversionService.addConverter(new ArrayToCollectionConverter(conversionService)); addScalarConverters(converterRegistry);
conversionService.addConverter(new CollectionToArrayConverter(conversionService)); addCollectionConverters(converterRegistry);
addFallbackConverters(converterRegistry);
}
// internal helpers
private static void addScalarConverters(ConverterRegistry converterRegistry) {
converterRegistry.addConverter(new StringToBooleanConverter());
converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());
conversionService.addConverter(new ArrayToStringConverter(conversionService)); converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
conversionService.addConverter(new StringToArrayConverter(conversionService)); converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());
conversionService.addConverter(new ArrayToObjectConverter(conversionService)); converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());
conversionService.addConverter(new ObjectToArrayConverter(conversionService));
conversionService.addConverter(new CollectionToStringConverter(conversionService));
conversionService.addConverter(new StringToCollectionConverter(conversionService));
conversionService.addConverter(new CollectionToObjectConverter(conversionService));
conversionService.addConverter(new ObjectToCollectionConverter(conversionService));
conversionService.addConverter(new ArrayToArrayConverter(conversionService));
conversionService.addConverter(new CollectionToCollectionConverter(conversionService));
conversionService.addConverter(new MapToMapConverter(conversionService));
conversionService.addConverter(new PropertiesToStringConverter());
conversionService.addConverter(new StringToPropertiesConverter());
conversionService.addConverter(new StringToBooleanConverter());
conversionService.addConverter(Boolean.class, String.class, new ObjectToStringConverter());
conversionService.addConverter(new StringToCharacterConverter());
conversionService.addConverter(Character.class, String.class, new ObjectToStringConverter());
conversionService.addConverter(new StringToLocaleConverter());
conversionService.addConverter(Locale.class, String.class, new ObjectToStringConverter());
conversionService.addConverterFactory(new StringToNumberConverterFactory()); converterRegistry.addConverter(new StringToCharacterConverter());
conversionService.addConverter(Number.class, String.class, new ObjectToStringConverter()); converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());
conversionService.addConverterFactory(new StringToEnumConverterFactory());
conversionService.addConverter(Enum.class, String.class, new EnumToStringConverter());
conversionService.addConverter(new NumberToCharacterConverter());
conversionService.addConverterFactory(new CharacterToNumberFactory());
conversionService.addConverterFactory(new NumberToNumberConverterFactory()); converterRegistry.addConverter(new NumberToCharacterConverter());
converterRegistry.addConverterFactory(new CharacterToNumberFactory());
converterRegistry.addConverterFactory(new StringToEnumConverterFactory());
converterRegistry.addConverter(Enum.class, String.class, new EnumToStringConverter());
converterRegistry.addConverter(new StringToLocaleConverter());
converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());
conversionService.addConverter(new ObjectToObjectConverter()); converterRegistry.addConverter(new PropertiesToStringConverter());
conversionService.addConverter(new IdToEntityConverter(conversionService)); converterRegistry.addConverter(new StringToPropertiesConverter());
conversionService.addConverter(new FallbackObjectToStringConverter());
} }
} private static void addCollectionConverters(ConverterRegistry converterRegistry) {
ConversionService conversionService = (ConversionService) converterRegistry;
converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));
converterRegistry.addConverter(new MapToMapConverter(conversionService));
converterRegistry.addConverter(new ArrayToStringConverter(conversionService));
converterRegistry.addConverter(new StringToArrayConverter(conversionService));
converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));
converterRegistry.addConverter(new CollectionToStringConverter(conversionService));
converterRegistry.addConverter(new StringToCollectionConverter(conversionService));
converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));
converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));
}
private static void addFallbackConverters(ConverterRegistry converterRegistry) {
ConversionService conversionService = (ConversionService) converterRegistry;
converterRegistry.addConverter(new ObjectToObjectConverter());
converterRegistry.addConverter(new IdToEntityConverter(conversionService));
converterRegistry.addConverter(new FallbackObjectToStringConverter());
}
}

View File

@ -88,17 +88,6 @@ public class GenericConversionService implements ConversionService, ConverterReg
new ConcurrentHashMap<ConverterCacheKey, GenericConverter>(); new ConcurrentHashMap<ConverterCacheKey, GenericConverter>();
/**
* Add a converter to the register indexed under the explicit source and target types.
* Allows for a general converter to be reused for multiple distinct source-to-target convertible pairs without having to create a Converter class for each pair.
* Not yet part of the ConverterRegistry interface.
* @since 3.1
*/
public void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter) {
GenericConverter.ConvertiblePair typeInfo = new GenericConverter.ConvertiblePair(sourceType, targetType);
addConverter(new ConverterAdapter(typeInfo, converter));
}
// implementing ConverterRegistry // implementing ConverterRegistry
public void addConverter(Converter<?, ?> converter) { public void addConverter(Converter<?, ?> converter) {
@ -110,13 +99,9 @@ public class GenericConversionService implements ConversionService, ConverterReg
addConverter(new ConverterAdapter(typeInfo, converter)); addConverter(new ConverterAdapter(typeInfo, converter));
} }
public void addConverterFactory(ConverterFactory<?, ?> converterFactory) { public void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter) {
GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converterFactory, ConverterFactory.class); GenericConverter.ConvertiblePair typeInfo = new GenericConverter.ConvertiblePair(sourceType, targetType);
if (typeInfo == null) { addConverter(new ConverterAdapter(typeInfo, converter));
throw new IllegalArgumentException("Unable to the determine sourceType <S> and targetRangeType R which " +
"your ConverterFactory<S, R> converts between; declare these generic types.");
}
addConverter(new ConverterFactoryAdapter(typeInfo, converterFactory));
} }
public void addConverter(GenericConverter converter) { public void addConverter(GenericConverter converter) {
@ -127,6 +112,15 @@ public class GenericConversionService implements ConversionService, ConverterReg
invalidateCache(); invalidateCache();
} }
public void addConverterFactory(ConverterFactory<?, ?> converterFactory) {
GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converterFactory, ConverterFactory.class);
if (typeInfo == null) {
throw new IllegalArgumentException("Unable to the determine sourceType <S> and targetRangeType R which " +
"your ConverterFactory<S, R> converts between; declare these generic types.");
}
addConverter(new ConverterFactoryAdapter(typeInfo, converterFactory));
}
public void removeConvertible(Class<?> sourceType, Class<?> targetType) { public void removeConvertible(Class<?> sourceType, Class<?> targetType) {
getSourceConverterMap(sourceType).remove(targetType); getSourceConverterMap(sourceType).remove(targetType);
invalidateCache(); invalidateCache();

View File

@ -21,6 +21,7 @@ import java.lang.reflect.Modifier;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter; import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
@ -38,9 +39,9 @@ import org.springframework.util.ReflectionUtils;
*/ */
final class IdToEntityConverter implements ConditionalGenericConverter { final class IdToEntityConverter implements ConditionalGenericConverter {
private final GenericConversionService conversionService; private final ConversionService conversionService;
public IdToEntityConverter(GenericConversionService conversionService) { public IdToEntityConverter(ConversionService conversionService) {
this.conversionService = conversionService; this.conversionService = conversionService;
} }
@ -56,7 +57,7 @@ final class IdToEntityConverter implements ConditionalGenericConverter {
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (source == null) { if (source == null) {
return this.conversionService.convertNullSource(sourceType, targetType); return null;
} }
Method finder = getFinder(targetType.getType()); Method finder = getFinder(targetType.getType());
Object id = this.conversionService.convert( Object id = this.conversionService.convert(