SpEL performs String->String type conversion even within concatenated String
Issue: SPR-11215
This commit is contained in:
		
							parent
							
								
									63d300ac86
								
							
						
					
					
						commit
						67abeb4722
					
				|  | @ -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"); | ||||||
|  |  | ||||||
|  | @ -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)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue