added symmetry to ToString converters: SPR-8306

This commit is contained in:
Keith Donald 2011-05-23 23:00:43 +00:00
parent e11d7c328f
commit e25fbf2533
8 changed files with 132 additions and 44 deletions

View File

@ -16,6 +16,8 @@
package org.springframework.core.convert.support;
import java.util.Locale;
/**
* A specialization of {@link GenericConversionService} configured by default with
* converters appropriate for most applications.
@ -65,19 +67,28 @@ public class DefaultConversionService extends GenericConversionService {
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());
conversionService.addConverter(Number.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());
conversionService.addConverter(new ObjectToStringConverter());
conversionService.addConverter(new ObjectToObjectConverter());
conversionService.addConverter(new IdToEntityConverter(conversionService));
conversionService.addConverter(new FallbackObjectToStringConverter());
}
}

View File

@ -0,0 +1,32 @@
/*
* 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 org.springframework.core.convert.converter.Converter;
/**
* Simply calls {@link Enum#name()} to convert a source Enum to a String.
* @author Keith Donald
* @since 3.0
*/
final class EnumToStringConverter implements Converter<Enum<?>, String> {
public String convert(Enum<?> source) {
return source.name();
}
}

View File

@ -0,0 +1,52 @@
/*
* 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.io.StringWriter;
import java.util.Collections;
import java.util.Set;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
/**
* Simply calls {@link Object#toString()} to convert any supported Object to a String.
* Supports CharSequence, StringWriter, and any class with a String constructor or <code>valueOf(String)</code> method.
*
* <p>Used by the default ConversionService as a fallback if there are no other explicit
* to-String converters registered.
*
* @author Keith Donald
* @author Juergen Hoeller
* @since 3.0
*/
final class FallbackObjectToStringConverter implements ConditionalGenericConverter {
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(Object.class, String.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
Class<?> sourceClass = sourceType.getObjectType();
return CharSequence.class.isAssignableFrom(sourceClass) || StringWriter.class.isAssignableFrom(sourceClass) ||
ObjectToObjectConverter.hasValueOfMethodOrConstructor(sourceClass, String.class);
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return (source != null ? source.toString() : null);
}
}

View File

@ -88,6 +88,17 @@ public class GenericConversionService implements ConversionService, ConverterReg
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
public void addConverter(Converter<?, ?> converter) {

View File

@ -43,16 +43,16 @@ import org.springframework.util.ReflectionUtils;
*/
final class ObjectToObjectConverter implements ConditionalGenericConverter {
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(Object.class, Object.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
Class<?> source = sourceType.getObjectType();
Class<?> target = targetType.getObjectType();
return (!source.equals(target) && hasValueOfMethodOrConstructor(target, source));
}
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(Object.class, Object.class));
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
Class<?> sourceClass = sourceType.getObjectType();
Class<?> targetClass = targetType.getObjectType();

View File

@ -16,40 +16,17 @@
package org.springframework.core.convert.support;
import java.io.StringWriter;
import java.util.Collections;
import java.util.Set;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.core.convert.converter.Converter;
/**
* Simply calls {@link Object#toString()} to convert any supported Object to a String.
* Supports Number, Boolean, Character, CharSequence, StringWriter, any enum,
* and any class with a String constructor or <code>valueOf(String)</code> method.
*
* <p>Used by the default ConversionService as a fallback if there are no other explicit
* to-String converters registered.
*
* Simply calls {@link Object#toString()} to convert a source Object to a String.
* @author Keith Donald
* @author Juergen Hoeller
* @since 3.0
*/
final class ObjectToStringConverter implements ConditionalGenericConverter {
final class ObjectToStringConverter implements Converter<Object, String> {
public Set<ConvertiblePair> getConvertibleTypes() {
return Collections.singleton(new ConvertiblePair(Object.class, String.class));
}
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
Class<?> sourceClass = sourceType.getObjectType();
return CharSequence.class.isAssignableFrom(sourceClass) || Number.class.isAssignableFrom(sourceClass) ||
Boolean.class.equals(sourceClass) || Character.class.equals(sourceClass) || StringWriter.class.isAssignableFrom(sourceClass) ||
sourceClass.isEnum() || ObjectToObjectConverter.hasValueOfMethodOrConstructor(sourceClass, String.class);
}
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
return (source != null ? source.toString() : null);
public String convert(Object source) {
return source.toString();
}
}

View File

@ -36,15 +36,13 @@ final class StringToBooleanConverter implements Converter<String, Boolean> {
static {
trueValues.add("true");
falseValues.add("false");
trueValues.add("on");
falseValues.add("off");
trueValues.add("yes");
falseValues.add("no");
trueValues.add("1");
falseValues.add("false");
falseValues.add("off");
falseValues.add("no");
falseValues.add("0");
}
@ -53,7 +51,8 @@ final class StringToBooleanConverter implements Converter<String, Boolean> {
if (value.length() == 0) {
return null;
}
else if (trueValues.contains(value)) {
value = value.toLowerCase();
if (trueValues.contains(value)) {
return Boolean.TRUE;
}
else if (falseValues.contains(value)) {

View File

@ -79,6 +79,9 @@ public class DefaultConversionTests {
assertEquals(Boolean.valueOf(true), conversionService.convert("on", Boolean.class));
assertEquals(Boolean.valueOf(true), conversionService.convert("yes", Boolean.class));
assertEquals(Boolean.valueOf(true), conversionService.convert("1", Boolean.class));
assertEquals(Boolean.valueOf(true), conversionService.convert("TRUE", Boolean.class));
assertEquals(Boolean.valueOf(true), conversionService.convert("ON", Boolean.class));
assertEquals(Boolean.valueOf(true), conversionService.convert("YES", Boolean.class));
}
@Test
@ -87,6 +90,9 @@ public class DefaultConversionTests {
assertEquals(Boolean.valueOf(false), conversionService.convert("off", Boolean.class));
assertEquals(Boolean.valueOf(false), conversionService.convert("no", Boolean.class));
assertEquals(Boolean.valueOf(false), conversionService.convert("0", Boolean.class));
assertEquals(Boolean.valueOf(false), conversionService.convert("FALSE", Boolean.class));
assertEquals(Boolean.valueOf(false), conversionService.convert("OFF", Boolean.class));
assertEquals(Boolean.valueOf(false), conversionService.convert("NO", Boolean.class));
}
@Test