SWF-1218 Add protected methods in AbstractMvcView and MvcViewFactoryCreator.
This commit is contained in:
@@ -184,7 +184,11 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon
|
|||||||
return viewFactory;
|
return viewFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractMvcViewFactory createMvcViewFactory(Expression viewId, ExpressionParser expressionParser,
|
/**
|
||||||
|
* Creates a concrete instance of an AbstractMvcViewFactory according to the runtime environment (Servlet or
|
||||||
|
* Portlet).
|
||||||
|
*/
|
||||||
|
protected AbstractMvcViewFactory createMvcViewFactory(Expression viewId, ExpressionParser expressionParser,
|
||||||
ConversionService conversionService, BinderConfiguration binderConfiguration) {
|
ConversionService conversionService, BinderConfiguration binderConfiguration) {
|
||||||
if (environment == MvcEnvironment.SERVLET) {
|
if (environment == MvcEnvironment.SERVLET) {
|
||||||
return new ServletMvcViewFactory(viewId, flowViewResolver, expressionParser, conversionService,
|
return new ServletMvcViewFactory(viewId, flowViewResolver, expressionParser, conversionService,
|
||||||
|
|||||||
@@ -307,6 +307,30 @@ public abstract class AbstractMvcView implements View {
|
|||||||
return mappingResults;
|
return mappingResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the binding configuration that defines how to connect properties of the model to UI elements.
|
||||||
|
* @return an instance of {@link BinderConfiguration} or null.
|
||||||
|
*/
|
||||||
|
protected BinderConfiguration getBinderConfiguration() {
|
||||||
|
return binderConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the EL parser to be used for data binding purposes.
|
||||||
|
* @return an instance of {@link ExpressionParser}.
|
||||||
|
*/
|
||||||
|
protected ExpressionParser getExpressionParser() {
|
||||||
|
return expressionParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the prefix that can be used for parameters that mark potentially empty fields.
|
||||||
|
* @return the prefix value.
|
||||||
|
*/
|
||||||
|
protected String getFieldMarkerPrefix() {
|
||||||
|
return fieldMarkerPrefix;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the user event from the current flow request. The default implementation returns the value of the request
|
* Obtain the user event from the current flow request. The default implementation returns the value of the request
|
||||||
* parameter with name {@link #setEventIdParameterName(String) eventIdParameterName}. Subclasses may override.
|
* parameter with name {@link #setEventIdParameterName(String) eventIdParameterName}. Subclasses may override.
|
||||||
@@ -317,6 +341,158 @@ public abstract class AbstractMvcView implements View {
|
|||||||
return WebUtils.findParameterValue(context.getRequestParameters().asMap(), eventIdParameterName);
|
return WebUtils.findParameterValue(context.getRequestParameters().asMap(), eventIdParameterName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Causes the model to be populated from information contained in request parameters.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* If a view has binding configuration then only model fields specified in the binding configuration will be
|
||||||
|
* considered. In the absence of binding configuration all request parameters will be used to update matching fields
|
||||||
|
* on the model.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param model the model to be updated
|
||||||
|
* @return an instance of MappingResults with information about the results of the binding.
|
||||||
|
*/
|
||||||
|
protected MappingResults bind(Object model) {
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Binding to model");
|
||||||
|
}
|
||||||
|
DefaultMapper mapper = new DefaultMapper();
|
||||||
|
ParameterMap requestParameters = requestContext.getRequestParameters();
|
||||||
|
if (binderConfiguration != null) {
|
||||||
|
addModelBindings(mapper, requestParameters.asMap().keySet(), model);
|
||||||
|
} else {
|
||||||
|
addDefaultMappings(mapper, requestParameters.asMap().keySet(), model);
|
||||||
|
}
|
||||||
|
return mapper.map(requestParameters, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Adds a {@link DefaultMapping} for every configured view {@link Binding} for which there is an incoming request
|
||||||
|
* parameter. If there is no matching incoming request parameter, a special mapping is created that will set the
|
||||||
|
* target field on the model to an empty value (typically null).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param mapper the mapper to which mappings will be added
|
||||||
|
* @param parameterNames the request parameters
|
||||||
|
* @param model the model
|
||||||
|
*/
|
||||||
|
protected void addModelBindings(DefaultMapper mapper, Set parameterNames, Object model) {
|
||||||
|
Iterator it = binderConfiguration.getBindings().iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
Binding binding = (Binding) it.next();
|
||||||
|
String parameterName = binding.getProperty();
|
||||||
|
if (parameterNames.contains(parameterName)) {
|
||||||
|
addMapping(mapper, binding, model);
|
||||||
|
} else {
|
||||||
|
if (fieldMarkerPrefix != null && parameterNames.contains(fieldMarkerPrefix + parameterName)) {
|
||||||
|
addEmptyValueMapping(mapper, parameterName, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Creates and adds a {@link DefaultMapping} for the given {@link Binding}. Information such as the model field
|
||||||
|
* name, if the field is required, and whether type conversion is needed will be passed on from the binding to the
|
||||||
|
* mapping.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* <b>Note:</b> with Spring 3 type conversion and formatting now in use in Web Flow, it is no longer necessary to
|
||||||
|
* use named converters on binding elements. The preferred approach is to register Spring 3 formatters. Named
|
||||||
|
* converters are supported for backwards compatibility only and will not result in use of the Spring 3 type
|
||||||
|
* conversion system at runtime.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param mapper the mapper to add the mapping to
|
||||||
|
* @param binding the binding element
|
||||||
|
* @param model the model
|
||||||
|
*/
|
||||||
|
protected void addMapping(DefaultMapper mapper, Binding binding, Object model) {
|
||||||
|
Expression source = new RequestParameterExpression(binding.getProperty());
|
||||||
|
ParserContext parserContext = new FluentParserContext().evaluate(model.getClass());
|
||||||
|
Expression target = expressionParser.parseExpression(binding.getProperty(), parserContext);
|
||||||
|
DefaultMapping mapping = new DefaultMapping(source, target);
|
||||||
|
mapping.setRequired(binding.getRequired());
|
||||||
|
if (binding.getConverter() != null) {
|
||||||
|
Assert.notNull(conversionService,
|
||||||
|
"A ConversionService must be configured to use resolve custom converters to use during binding");
|
||||||
|
ConversionExecutor conversionExecutor = conversionService.getConversionExecutor(binding.getConverter(),
|
||||||
|
String.class, target.getValueType(model));
|
||||||
|
mapping.setTypeConverter(conversionExecutor);
|
||||||
|
}
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Adding mapping for parameter '" + binding.getProperty() + "'");
|
||||||
|
}
|
||||||
|
mapper.addMapping(mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a {@link DefaultMapping} instance for all incoming request parameters except those having a special field
|
||||||
|
* marker prefix. This method is used when binding configuration was not specified on the view.
|
||||||
|
*
|
||||||
|
* @param mapper the mapper to add mappings to
|
||||||
|
* @param parameterNames the request parameter names
|
||||||
|
* @param model the model
|
||||||
|
*/
|
||||||
|
protected void addDefaultMappings(DefaultMapper mapper, Set parameterNames, Object model) {
|
||||||
|
for (Iterator it = parameterNames.iterator(); it.hasNext();) {
|
||||||
|
String parameterName = (String) it.next();
|
||||||
|
if (fieldMarkerPrefix != null && parameterName.startsWith(fieldMarkerPrefix)) {
|
||||||
|
String field = parameterName.substring(fieldMarkerPrefix.length());
|
||||||
|
if (!parameterNames.contains(field)) {
|
||||||
|
addEmptyValueMapping(mapper, field, model);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
addDefaultMapping(mapper, parameterName, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a special {@link DefaultMapping} that results in setting the target field on the model to an empty value
|
||||||
|
* (typically null).
|
||||||
|
*
|
||||||
|
* @param mapper the mapper to add the mapping to
|
||||||
|
* @param field the field for which a mapping is to be added
|
||||||
|
* @param model the model
|
||||||
|
*/
|
||||||
|
protected void addEmptyValueMapping(DefaultMapper mapper, String field, Object model) {
|
||||||
|
ParserContext parserContext = new FluentParserContext().evaluate(model.getClass());
|
||||||
|
Expression target = expressionParser.parseExpression(field, parserContext);
|
||||||
|
try {
|
||||||
|
Class propertyType = target.getValueType(model);
|
||||||
|
Expression source = new StaticExpression(getEmptyValue(propertyType));
|
||||||
|
DefaultMapping mapping = new DefaultMapping(source, target);
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Adding empty value mapping for parameter '" + field + "'");
|
||||||
|
}
|
||||||
|
mapper.addMapping(mapping);
|
||||||
|
} catch (EvaluationException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a {@link DefaultMapping} between the given request parameter name and a matching model field.
|
||||||
|
*
|
||||||
|
* @param mapper the mapper to add the mapping to
|
||||||
|
* @param parameter the request parameter name
|
||||||
|
* @param model the model
|
||||||
|
*/
|
||||||
|
protected void addDefaultMapping(DefaultMapper mapper, String parameter, Object model) {
|
||||||
|
Expression source = new RequestParameterExpression(parameter);
|
||||||
|
ParserContext parserContext = new FluentParserContext().evaluate(model.getClass());
|
||||||
|
Expression target = expressionParser.parseExpression(parameter, parserContext);
|
||||||
|
DefaultMapping mapping = new DefaultMapping(source, target);
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Adding default mapping for parameter '" + parameter + "'");
|
||||||
|
}
|
||||||
|
mapper.addMapping(mapping);
|
||||||
|
}
|
||||||
|
|
||||||
// package private
|
// package private
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -395,84 +571,6 @@ public abstract class AbstractMvcView implements View {
|
|||||||
return (Expression) requestContext.getCurrentState().getAttributes().get("model");
|
return (Expression) requestContext.getCurrentState().getAttributes().get("model");
|
||||||
}
|
}
|
||||||
|
|
||||||
private MappingResults bind(Object model) {
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Binding to model");
|
|
||||||
}
|
|
||||||
DefaultMapper mapper = new DefaultMapper();
|
|
||||||
ParameterMap requestParameters = requestContext.getRequestParameters();
|
|
||||||
if (binderConfiguration != null) {
|
|
||||||
addModelBindings(mapper, requestParameters.asMap().keySet(), model);
|
|
||||||
} else {
|
|
||||||
addDefaultMappings(mapper, requestParameters.asMap().keySet(), model);
|
|
||||||
}
|
|
||||||
return mapper.map(requestParameters, model);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addModelBindings(DefaultMapper mapper, Set parameterNames, Object model) {
|
|
||||||
Iterator it = binderConfiguration.getBindings().iterator();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
Binding binding = (Binding) it.next();
|
|
||||||
String parameterName = binding.getProperty();
|
|
||||||
if (parameterNames.contains(parameterName)) {
|
|
||||||
addMapping(mapper, binding, model);
|
|
||||||
} else {
|
|
||||||
if (fieldMarkerPrefix != null && parameterNames.contains(fieldMarkerPrefix + parameterName)) {
|
|
||||||
addEmptyValueMapping(mapper, parameterName, model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addMapping(DefaultMapper mapper, Binding binding, Object model) {
|
|
||||||
Expression source = new RequestParameterExpression(binding.getProperty());
|
|
||||||
ParserContext parserContext = new FluentParserContext().evaluate(model.getClass());
|
|
||||||
Expression target = expressionParser.parseExpression(binding.getProperty(), parserContext);
|
|
||||||
DefaultMapping mapping = new DefaultMapping(source, target);
|
|
||||||
mapping.setRequired(binding.getRequired());
|
|
||||||
if (binding.getConverter() != null) {
|
|
||||||
Assert.notNull(conversionService,
|
|
||||||
"A ConversionService must be configured to use resolve custom converters to use during binding");
|
|
||||||
ConversionExecutor conversionExecutor = conversionService.getConversionExecutor(binding.getConverter(),
|
|
||||||
String.class, target.getValueType(model));
|
|
||||||
mapping.setTypeConverter(conversionExecutor);
|
|
||||||
}
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Adding mapping for parameter '" + binding.getProperty() + "'");
|
|
||||||
}
|
|
||||||
mapper.addMapping(mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addDefaultMappings(DefaultMapper mapper, Set parameterNames, Object model) {
|
|
||||||
for (Iterator it = parameterNames.iterator(); it.hasNext();) {
|
|
||||||
String parameterName = (String) it.next();
|
|
||||||
if (fieldMarkerPrefix != null && parameterName.startsWith(fieldMarkerPrefix)) {
|
|
||||||
String field = parameterName.substring(fieldMarkerPrefix.length());
|
|
||||||
if (!parameterNames.contains(field)) {
|
|
||||||
addEmptyValueMapping(mapper, field, model);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
addDefaultMapping(mapper, parameterName, model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addEmptyValueMapping(DefaultMapper mapper, String field, Object model) {
|
|
||||||
ParserContext parserContext = new FluentParserContext().evaluate(model.getClass());
|
|
||||||
Expression target = expressionParser.parseExpression(field, parserContext);
|
|
||||||
try {
|
|
||||||
Class propertyType = target.getValueType(model);
|
|
||||||
Expression source = new StaticExpression(getEmptyValue(propertyType));
|
|
||||||
DefaultMapping mapping = new DefaultMapping(source, target);
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Adding empty value mapping for parameter '" + field + "'");
|
|
||||||
}
|
|
||||||
mapper.addMapping(mapping);
|
|
||||||
} catch (EvaluationException e) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object getEmptyValue(Class fieldType) {
|
private Object getEmptyValue(Class fieldType) {
|
||||||
if (fieldType != null && boolean.class.equals(fieldType) || Boolean.class.equals(fieldType)) {
|
if (fieldType != null && boolean.class.equals(fieldType) || Boolean.class.equals(fieldType)) {
|
||||||
// Special handling of boolean property.
|
// Special handling of boolean property.
|
||||||
@@ -486,17 +584,6 @@ public abstract class AbstractMvcView implements View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDefaultMapping(DefaultMapper mapper, String parameter, Object model) {
|
|
||||||
Expression source = new RequestParameterExpression(parameter);
|
|
||||||
ParserContext parserContext = new FluentParserContext().evaluate(model.getClass());
|
|
||||||
Expression target = expressionParser.parseExpression(parameter, parserContext);
|
|
||||||
DefaultMapping mapping = new DefaultMapping(source, target);
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug("Adding default mapping for parameter '" + parameter + "'");
|
|
||||||
}
|
|
||||||
mapper.addMapping(mapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasErrors(MappingResults results) {
|
private boolean hasErrors(MappingResults results) {
|
||||||
return results.hasErrorResults() && !onlyPropertyNotFoundErrorsPresent(results);
|
return results.hasErrorResults() && !onlyPropertyNotFoundErrorsPresent(results);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user