Skip to content

Commit df0eab5

Browse files
committed
AbstractMvcView validates default binding expression
Issue: SWF-1711
1 parent c777ff8 commit df0eab5

File tree

1 file changed

+50
-0
lines changed

1 file changed

+50
-0
lines changed

spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,19 @@
1818
import java.io.IOException;
1919
import java.io.Serializable;
2020
import java.lang.reflect.Array;
21+
import java.util.ArrayList;
2122
import java.util.HashMap;
2223
import java.util.List;
2324
import java.util.Map;
2425
import java.util.Set;
2526

27+
import javax.lang.model.SourceVersion;
28+
2629
import org.apache.commons.logging.Log;
2730
import org.apache.commons.logging.LogFactory;
31+
32+
import org.springframework.beans.BeanWrapperImpl;
33+
import org.springframework.beans.PropertyAccessorUtils;
2834
import org.springframework.binding.convert.ConversionExecutor;
2935
import org.springframework.binding.convert.ConversionService;
3036
import org.springframework.binding.expression.EvaluationException;
@@ -508,6 +514,7 @@ protected void addEmptyValueMapping(DefaultMapper mapper, String field, Object m
508514
protected void addDefaultMapping(DefaultMapper mapper, String parameter, Object model) {
509515
Expression source = new RequestParameterExpression(parameter);
510516
ParserContext parserContext = new FluentParserContext().evaluate(model.getClass());
517+
validateDataBindingExpression(parameter, model);
511518
Expression target = expressionParser.parseExpression(parameter, parserContext);
512519
DefaultMapping mapping = new DefaultMapping(source, target);
513520
if (logger.isDebugEnabled()) {
@@ -516,6 +523,49 @@ protected void addDefaultMapping(DefaultMapper mapper, String parameter, Object
516523
mapper.addMapping(mapping);
517524
}
518525

526+
/**
527+
* Check that the expression is a property path where each nested property
528+
* is a {@link SourceVersion#isName(CharSequence) valid Java identifier} and
529+
* that the first nested property name at least is a valid readable property
530+
* on the target object.
531+
*/
532+
private void validateDataBindingExpression(String expression, Object model) {
533+
534+
if (expressionParser instanceof BeanWrapperExpressionParser) {
535+
return;
536+
}
537+
538+
String errorMessage = "Invalid data binding expression: '" + expression + "' " +
539+
"for target model class '" + model.getClass() + "'";
540+
541+
List<String> propertyNames = new ArrayList<String>();
542+
while (true) {
543+
int index = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(expression);
544+
String nestedProperty = index != -1 ? expression.substring(0, index) : expression;
545+
nestedProperty = PropertyAccessorUtils.getPropertyName(nestedProperty);
546+
propertyNames.add(nestedProperty);
547+
if (index == -1) {
548+
break;
549+
}
550+
if (expression.length() == index + 1) {
551+
throw new IllegalStateException(errorMessage);
552+
}
553+
expression = expression.substring(index + 1);
554+
}
555+
556+
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(model);
557+
if (!beanWrapper.isReadableProperty(propertyNames.get(0))) {
558+
throw new IllegalStateException(errorMessage);
559+
}
560+
561+
for (int i=0; i < propertyNames.size(); i++) {
562+
if (!SourceVersion.isName(propertyNames.get(i))) {
563+
throw new IllegalStateException(errorMessage);
564+
}
565+
}
566+
567+
}
568+
519569
// package private
520570

521571
/**

0 commit comments

Comments
 (0)