SpEL performs String->String type conversion even within concatenated String

Issue: SPR-11215
This commit is contained in:
Juergen Hoeller 2013-12-17 21:35:14 +01:00
parent 63d300ac86
commit 67abeb4722
2 changed files with 36 additions and 21 deletions

View File

@ -23,10 +23,8 @@ import java.util.Properties;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import static org.junit.Assert.*;
import org.junit.Test; import org.junit.Test;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
@ -38,13 +36,18 @@ import org.springframework.beans.factory.support.AutowireCandidateQualifier;
import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.tests.Assume;
import org.springframework.tests.TestGroup;
import org.springframework.context.annotation.AnnotationConfigUtils; import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.tests.Assume;
import org.springframework.tests.TestGroup;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.SerializationTestUtils; import org.springframework.util.SerializationTestUtils;
import org.springframework.util.StopWatch; import org.springframework.util.StopWatch;
import static org.junit.Assert.*;
/** /**
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 3.0 * @since 3.0
@ -190,27 +193,35 @@ public class ApplicationContextExpressionTests {
public void prototypeCreationReevaluatesExpressions() { public void prototypeCreationReevaluatesExpressions() {
GenericApplicationContext ac = new GenericApplicationContext(); GenericApplicationContext ac = new GenericApplicationContext();
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac); AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
GenericConversionService cs = new GenericConversionService();
cs.addConverter(String.class, String.class, new Converter<String, String>() {
@Override
public String convert(String source) {
return source.trim();
}
});
ac.getBeanFactory().registerSingleton(GenericApplicationContext.CONVERSION_SERVICE_BEAN_NAME, cs);
RootBeanDefinition rbd = new RootBeanDefinition(PrototypeTestBean.class); RootBeanDefinition rbd = new RootBeanDefinition(PrototypeTestBean.class);
rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
rbd.getPropertyValues().add("country", "#{systemProperties.country}"); rbd.getPropertyValues().add("country", "#{systemProperties.country}");
rbd.getPropertyValues().add("country2", new TypedStringValue("#{systemProperties.country}")); rbd.getPropertyValues().add("country2", new TypedStringValue("-#{systemProperties.country}-"));
ac.registerBeanDefinition("test", rbd); ac.registerBeanDefinition("test", rbd);
ac.refresh(); ac.refresh();
try { try {
System.getProperties().put("name", "juergen1"); System.getProperties().put("name", "juergen1");
System.getProperties().put("country", "UK1"); System.getProperties().put("country", " UK1 ");
PrototypeTestBean tb = (PrototypeTestBean) ac.getBean("test"); PrototypeTestBean tb = (PrototypeTestBean) ac.getBean("test");
assertEquals("juergen1", tb.getName()); assertEquals("juergen1", tb.getName());
assertEquals("UK1", tb.getCountry()); assertEquals("UK1", tb.getCountry());
assertEquals("UK1", tb.getCountry2()); assertEquals("-UK1-", tb.getCountry2());
System.getProperties().put("name", "juergen2"); System.getProperties().put("name", "juergen2");
System.getProperties().put("country", "UK2"); System.getProperties().put("country", " UK2 ");
tb = (PrototypeTestBean) ac.getBean("test"); tb = (PrototypeTestBean) ac.getBean("test");
assertEquals("juergen2", tb.getName()); assertEquals("juergen2", tb.getName());
assertEquals("UK2", tb.getCountry()); assertEquals("UK2", tb.getCountry());
assertEquals("UK2", tb.getCountry2()); assertEquals("-UK2-", tb.getCountry2());
} }
finally { finally {
System.getProperties().remove("name"); System.getProperties().remove("name");

View File

@ -41,7 +41,7 @@ public abstract class ExpressionUtils {
* @param targetType the type to attempt conversion to * @param targetType the type to attempt conversion to
* @return the converted value * @return the converted value
* @throws EvaluationException if there is a problem during conversion or conversion * @throws EvaluationException if there is a problem during conversion or conversion
* of the value to the specified type is not supported * of the value to the specified type is not supported
* @deprecated use {@link #convertTypedValue(EvaluationContext, TypedValue, Class)} * @deprecated use {@link #convertTypedValue(EvaluationContext, TypedValue, Class)}
*/ */
@Deprecated @Deprecated
@ -58,16 +58,20 @@ public abstract class ExpressionUtils {
* @param targetType the type to attempt conversion to * @param targetType the type to attempt conversion to
* @return the converted value * @return the converted value
* @throws EvaluationException if there is a problem during conversion or conversion * @throws EvaluationException if there is a problem during conversion or conversion
* of the value to the specified type is not supported * of the value to the specified type is not supported
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T convertTypedValue(EvaluationContext context, TypedValue typedValue, Class<T> targetType) { public static <T> T convertTypedValue(EvaluationContext context, TypedValue typedValue, Class<T> targetType) {
Object value = typedValue.getValue(); Object value = typedValue.getValue();
if ((targetType == null) || (value != null && ClassUtils.isAssignableValue(targetType, value))) { if (targetType == null) {
return (T) value; return (T) value;
} }
if (context != null) { if (context != null) {
return (T) context.getTypeConverter().convertValue(value, typedValue.getTypeDescriptor(), TypeDescriptor.valueOf(targetType)); return (T) context.getTypeConverter().convertValue(
value, typedValue.getTypeDescriptor(), TypeDescriptor.valueOf(targetType));
}
if (ClassUtils.isAssignableValue(targetType, value)) {
return (T) value;
} }
throw new EvaluationException("Cannot convert value '" + value + "' to type '" + targetType.getName() + "'"); throw new EvaluationException("Cannot convert value '" + value + "' to type '" + targetType.getName() + "'");
} }
@ -100,8 +104,8 @@ public abstract class ExpressionUtils {
* Attempt to convert a typed value to a long using the supplied type converter. * Attempt to convert a typed value to a long using the supplied type converter.
*/ */
public static long toLong(TypeConverter typeConverter, TypedValue typedValue) { public static long toLong(TypeConverter typeConverter, TypedValue typedValue) {
return (Long) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(), TypeDescriptor return (Long) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
.valueOf(Long.class)); TypeDescriptor.valueOf(Long.class));
} }
/** /**
@ -116,24 +120,24 @@ public abstract class ExpressionUtils {
* Attempt to convert a typed value to a short using the supplied type converter. * Attempt to convert a typed value to a short using the supplied type converter.
*/ */
public static short toShort(TypeConverter typeConverter, TypedValue typedValue) { public static short toShort(TypeConverter typeConverter, TypedValue typedValue) {
return (Short) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(), TypeDescriptor return (Short) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
.valueOf(Short.class)); TypeDescriptor.valueOf(Short.class));
} }
/** /**
* Attempt to convert a typed value to a float using the supplied type converter. * Attempt to convert a typed value to a float using the supplied type converter.
*/ */
public static float toFloat(TypeConverter typeConverter, TypedValue typedValue) { public static float toFloat(TypeConverter typeConverter, TypedValue typedValue) {
return (Float) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(), TypeDescriptor return (Float) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
.valueOf(Float.class)); TypeDescriptor.valueOf(Float.class));
} }
/** /**
* Attempt to convert a typed value to a byte using the supplied type converter. * Attempt to convert a typed value to a byte using the supplied type converter.
*/ */
public static byte toByte(TypeConverter typeConverter, TypedValue typedValue) { public static byte toByte(TypeConverter typeConverter, TypedValue typedValue) {
return (Byte) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(), TypeDescriptor return (Byte) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
.valueOf(Byte.class)); TypeDescriptor.valueOf(Byte.class));
} }
} }