Skip to content

Commit 67abeb4

Browse files
committed
SpEL performs String->String type conversion even within concatenated String
Issue: SPR-11215
1 parent 63d300a commit 67abeb4

File tree

2 files changed

+36
-21
lines changed

2 files changed

+36
-21
lines changed

spring-context/src/test/java/org/springframework/context/expression/ApplicationContextExpressionTests.java

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@
2323

2424
import org.apache.commons.logging.Log;
2525
import org.apache.commons.logging.LogFactory;
26-
import static org.junit.Assert.*;
2726
import org.junit.Test;
2827

29-
import org.springframework.tests.sample.beans.TestBean;
3028
import org.springframework.beans.factory.ObjectFactory;
3129
import org.springframework.beans.factory.annotation.Autowired;
3230
import org.springframework.beans.factory.annotation.Qualifier;
@@ -38,13 +36,18 @@
3836
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
3937
import org.springframework.beans.factory.support.GenericBeanDefinition;
4038
import org.springframework.beans.factory.support.RootBeanDefinition;
41-
import org.springframework.tests.Assume;
42-
import org.springframework.tests.TestGroup;
4339
import org.springframework.context.annotation.AnnotationConfigUtils;
4440
import org.springframework.context.support.GenericApplicationContext;
41+
import org.springframework.core.convert.converter.Converter;
42+
import org.springframework.core.convert.support.GenericConversionService;
43+
import org.springframework.tests.Assume;
44+
import org.springframework.tests.TestGroup;
45+
import org.springframework.tests.sample.beans.TestBean;
4546
import org.springframework.util.SerializationTestUtils;
4647
import org.springframework.util.StopWatch;
4748

49+
import static org.junit.Assert.*;
50+
4851
/**
4952
* @author Juergen Hoeller
5053
* @since 3.0
@@ -190,27 +193,35 @@ public String getConversationId() {
190193
public void prototypeCreationReevaluatesExpressions() {
191194
GenericApplicationContext ac = new GenericApplicationContext();
192195
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
196+
GenericConversionService cs = new GenericConversionService();
197+
cs.addConverter(String.class, String.class, new Converter<String, String>() {
198+
@Override
199+
public String convert(String source) {
200+
return source.trim();
201+
}
202+
});
203+
ac.getBeanFactory().registerSingleton(GenericApplicationContext.CONVERSION_SERVICE_BEAN_NAME, cs);
193204
RootBeanDefinition rbd = new RootBeanDefinition(PrototypeTestBean.class);
194205
rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
195206
rbd.getPropertyValues().add("country", "#{systemProperties.country}");
196-
rbd.getPropertyValues().add("country2", new TypedStringValue("#{systemProperties.country}"));
207+
rbd.getPropertyValues().add("country2", new TypedStringValue("-#{systemProperties.country}-"));
197208
ac.registerBeanDefinition("test", rbd);
198209
ac.refresh();
199210

200211
try {
201212
System.getProperties().put("name", "juergen1");
202-
System.getProperties().put("country", "UK1");
213+
System.getProperties().put("country", " UK1 ");
203214
PrototypeTestBean tb = (PrototypeTestBean) ac.getBean("test");
204215
assertEquals("juergen1", tb.getName());
205216
assertEquals("UK1", tb.getCountry());
206-
assertEquals("UK1", tb.getCountry2());
217+
assertEquals("-UK1-", tb.getCountry2());
207218

208219
System.getProperties().put("name", "juergen2");
209-
System.getProperties().put("country", "UK2");
220+
System.getProperties().put("country", " UK2 ");
210221
tb = (PrototypeTestBean) ac.getBean("test");
211222
assertEquals("juergen2", tb.getName());
212223
assertEquals("UK2", tb.getCountry());
213-
assertEquals("UK2", tb.getCountry2());
224+
assertEquals("-UK2-", tb.getCountry2());
214225
}
215226
finally {
216227
System.getProperties().remove("name");

spring-expression/src/main/java/org/springframework/expression/common/ExpressionUtils.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public abstract class ExpressionUtils {
4141
* @param targetType the type to attempt conversion to
4242
* @return the converted value
4343
* @throws EvaluationException if there is a problem during conversion or conversion
44-
* of the value to the specified type is not supported
44+
* of the value to the specified type is not supported
4545
* @deprecated use {@link #convertTypedValue(EvaluationContext, TypedValue, Class)}
4646
*/
4747
@Deprecated
@@ -58,16 +58,20 @@ public static <T> T convert(EvaluationContext context, Object value, Class<T> ta
5858
* @param targetType the type to attempt conversion to
5959
* @return the converted value
6060
* @throws EvaluationException if there is a problem during conversion or conversion
61-
* of the value to the specified type is not supported
61+
* of the value to the specified type is not supported
6262
*/
6363
@SuppressWarnings("unchecked")
6464
public static <T> T convertTypedValue(EvaluationContext context, TypedValue typedValue, Class<T> targetType) {
6565
Object value = typedValue.getValue();
66-
if ((targetType == null) || (value != null && ClassUtils.isAssignableValue(targetType, value))) {
66+
if (targetType == null) {
6767
return (T) value;
6868
}
6969
if (context != null) {
70-
return (T) context.getTypeConverter().convertValue(value, typedValue.getTypeDescriptor(), TypeDescriptor.valueOf(targetType));
70+
return (T) context.getTypeConverter().convertValue(
71+
value, typedValue.getTypeDescriptor(), TypeDescriptor.valueOf(targetType));
72+
}
73+
if (ClassUtils.isAssignableValue(targetType, value)) {
74+
return (T) value;
7175
}
7276
throw new EvaluationException("Cannot convert value '" + value + "' to type '" + targetType.getName() + "'");
7377
}
@@ -100,8 +104,8 @@ public static double toDouble(TypeConverter typeConverter, TypedValue typedValue
100104
* Attempt to convert a typed value to a long using the supplied type converter.
101105
*/
102106
public static long toLong(TypeConverter typeConverter, TypedValue typedValue) {
103-
return (Long) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(), TypeDescriptor
104-
.valueOf(Long.class));
107+
return (Long) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
108+
TypeDescriptor.valueOf(Long.class));
105109
}
106110

107111
/**
@@ -116,24 +120,24 @@ public static char toChar(TypeConverter typeConverter, TypedValue typedValue) {
116120
* Attempt to convert a typed value to a short using the supplied type converter.
117121
*/
118122
public static short toShort(TypeConverter typeConverter, TypedValue typedValue) {
119-
return (Short) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(), TypeDescriptor
120-
.valueOf(Short.class));
123+
return (Short) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
124+
TypeDescriptor.valueOf(Short.class));
121125
}
122126

123127
/**
124128
* Attempt to convert a typed value to a float using the supplied type converter.
125129
*/
126130
public static float toFloat(TypeConverter typeConverter, TypedValue typedValue) {
127-
return (Float) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(), TypeDescriptor
128-
.valueOf(Float.class));
131+
return (Float) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
132+
TypeDescriptor.valueOf(Float.class));
129133
}
130134

131135
/**
132136
* Attempt to convert a typed value to a byte using the supplied type converter.
133137
*/
134138
public static byte toByte(TypeConverter typeConverter, TypedValue typedValue) {
135-
return (Byte) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(), TypeDescriptor
136-
.valueOf(Byte.class));
139+
return (Byte) typeConverter.convertValue(typedValue.getValue(), typedValue.getTypeDescriptor(),
140+
TypeDescriptor.valueOf(Byte.class));
137141
}
138142

139143
}

0 commit comments

Comments
 (0)