Skip to content

Commit

Permalink
DATACMNS-1264 - MapDataBinder now rejects improper property expressions.
Browse files Browse the repository at this point in the history
We now make sure that type expressions cannot be used in SpEL expressions handled by MapDataBinder. They're gonna be rejected by considering the property not writable. SpEL expression evaluation errors are now forwarded as NotWritablePropertyException to make sure the failure gets handled as if the property referred to doesn't exist.
  • Loading branch information
odrotbohm committed Feb 26, 2018
1 parent 3dff7ea commit 613cf08
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 2 deletions.
11 changes: 10 additions & 1 deletion src/main/java/org/springframework/data/web/MapDataBinder.java
Expand Up @@ -43,6 +43,8 @@
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.SpelParserConfiguration; import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext;
Expand Down Expand Up @@ -177,6 +179,9 @@ public void setPropertyValue(String propertyName, @Nullable Object value) throws
StandardEvaluationContext context = new StandardEvaluationContext(); StandardEvaluationContext context = new StandardEvaluationContext();
context.addPropertyAccessor(new PropertyTraversingMapAccessor(type, conversionService)); context.addPropertyAccessor(new PropertyTraversingMapAccessor(type, conversionService));
context.setTypeConverter(new StandardTypeConverter(conversionService)); context.setTypeConverter(new StandardTypeConverter(conversionService));
context.setTypeLocator(typeName -> {
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
});
context.setRootObject(map); context.setRootObject(map);


Expression expression = PARSER.parseExpression(propertyName); Expression expression = PARSER.parseExpression(propertyName);
Expand Down Expand Up @@ -208,7 +213,11 @@ public void setPropertyValue(String propertyName, @Nullable Object value) throws
value = conversionService.convert(value, TypeDescriptor.forObject(value), typeDescriptor); value = conversionService.convert(value, TypeDescriptor.forObject(value), typeDescriptor);
} }


expression.setValue(context, value); try {
expression.setValue(context, value);
} catch (SpelEvaluationException o_O) {
throw new NotWritablePropertyException(type, propertyName, "Could not write property!", o_O);
}
} }


private boolean conversionRequired(@Nullable Object source, Class<?> targetType) { private boolean conversionRequired(@Nullable Object source, Class<?> targetType) {
Expand Down
Expand Up @@ -28,8 +28,11 @@
import java.util.Map; import java.util.Map;


import org.junit.Test; import org.junit.Test;
import org.springframework.beans.ConfigurablePropertyAccessor;
import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.NotWritablePropertyException;
import org.springframework.beans.PropertyValues; import org.springframework.beans.PropertyValues;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO; import org.springframework.format.annotation.DateTimeFormat.ISO;
import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.format.support.DefaultFormattingConversionService;
Expand Down Expand Up @@ -91,7 +94,29 @@ public void skipsPropertyNotExposedByTheTypeHierarchy() {
MutablePropertyValues values = new MutablePropertyValues(); MutablePropertyValues values = new MutablePropertyValues();
values.add("somethingWeird", "Value"); values.add("somethingWeird", "Value");


assertThat(bind(values)).isEqualTo(Collections.<String, Object> emptyMap()); assertThat(bind(values)).isEqualTo(Collections.emptyMap());
}

@Test // DATACMNS-1264
public void dropsMapExpressionsForCollectionReferences() {

ConfigurablePropertyAccessor accessor = new MapDataBinder(Bar.class, new DefaultFormattingConversionService())
.getPropertyAccessor();

assertThatExceptionOfType(NotWritablePropertyException.class) //
.isThrownBy(() -> accessor.setPropertyValue("fooBar['foo']", null)) //
.withCauseInstanceOf(SpelEvaluationException.class);
}

@Test // DATACMNS-1264
public void rejectsExpressionContainingTypeExpression() {

ConfigurablePropertyAccessor accessor = new MapDataBinder(Bar.class, new DefaultFormattingConversionService())
.getPropertyAccessor();

assertThatExceptionOfType(NotWritablePropertyException.class) //
.isThrownBy(() -> accessor.setPropertyValue("fooBar[T(java.lang.String)]", null)) //
.withCauseInstanceOf(SpelEvaluationException.class);
} }


private static Map<String, Object> bind(PropertyValues values) { private static Map<String, Object> bind(PropertyValues values) {
Expand Down

0 comments on commit 613cf08

Please sign in to comment.