提交 fa167646 编写于 作者: M Mark Fisher

Replaced BinderSupport with a refactored AbstractBinder that delegates to a...

Replaced BinderSupport with a refactored AbstractBinder that delegates to a FieldBinder whose creation is the responsibility of each subclass.
上级 1eabe2b4
......@@ -19,17 +19,26 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.context.MessageSource;
import org.springframework.model.binder.Binder;
import org.springframework.model.binder.BindingResult;
import org.springframework.model.binder.BindingResults;
import org.springframework.model.binder.MissingFieldException;
import org.springframework.util.Assert;
/**
* A template that encapsulates the general bulk-binding algorithm.
* Base Binder implementation that defines common structural elements.
* Subclasses should be parameterized & implement {@link #bind(Map, Object)}.
* @author Keith Donald
* @since 3.0
* @see #setRequiredFields(String[])
* @see #bind(Map, FieldBinder)
* @see #setMessageSource(MessageSource)
* @see #createFieldBinder()
* @see #bind(Map, Object)
*/
public class BindTemplate {
public abstract class AbstractBinder<M> implements Binder<M> {
private MessageSource messageSource;
private String[] requiredFields;
......@@ -42,10 +51,28 @@ public class BindTemplate {
this.requiredFields = fieldNames;
}
// implementing Binder
/**
* Configure the MessageSource that resolves localized {@link BindingResult} alert messages.
* @param messageSource the message source
*/
public void setMessageSource(MessageSource messageSource) {
Assert.notNull(messageSource, "The MessageSource is required");
this.messageSource = messageSource;
}
/**
* The configured MessageSource that resolves binding result alert messages.
*/
protected MessageSource getMessageSource() {
return messageSource;
}
// Binder implementation
public BindingResults bind(Map<String, ? extends Object> fieldValues, FieldBinder fieldBinder) {
public final BindingResults bind(Map<String, ? extends Object> fieldValues, M model) {
fieldValues = filter(fieldValues, model);
checkRequired(fieldValues);
FieldBinder fieldBinder = this.createFieldBinder(model);
ArrayListBindingResults results = new ArrayListBindingResults(fieldValues.size());
for (Map.Entry<String, ? extends Object> fieldValue : fieldValues.entrySet()) {
results.add(fieldBinder.bind(fieldValue.getKey(), fieldValue.getValue()));
......@@ -53,6 +80,26 @@ public class BindTemplate {
return results;
}
// subclass hooks
/**
* Subclasses must implement this method to create the {@link FieldBinder}
* instance for the given model.
*/
protected abstract FieldBinder createFieldBinder(M model);
/**
* Filter the fields to bind.
* Allows for pre-processing the fieldValues Map before any binding occurs.
* For example, you might insert empty or default values for fields that are not present.
* As another example, you might collapse multiple fields into a single field.
* Default implementation simply returns the fieldValues Map unchanged.
* @param fieldValues the original fieldValues Map provided by the caller
* @return the filtered fieldValues Map that will be used to bind
*/
protected Map<String, ? extends Object> filter(Map<String, ? extends Object> fieldValues, M model) {
return fieldValues;
}
// internal helpers
......@@ -77,4 +124,4 @@ public class BindTemplate {
}
}
}
\ No newline at end of file
}
/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.model.binder.support;
import org.springframework.context.MessageSource;
import org.springframework.model.binder.BindingResult;
import org.springframework.model.binder.MissingFieldException;
import org.springframework.util.Assert;
/**
* Binder implementation support class that defines common structural elements.
* @author Keith Donald
* @since 3.0
* @see #setRequiredFields(String[])
* @see #setMessageSource(MessageSource)
* @see #createBindTemplate()
*/
public abstract class BinderSupport {
private BindTemplate bindTemplate;
private MessageSource messageSource;
public BinderSupport() {
bindTemplate = createBindTemplate();
}
/**
* Configure the fields for which values must be present in each bind attempt.
* @param fieldNames the required field names
* @see MissingFieldException
*/
public void setRequiredFields(String[] fieldNames) {
bindTemplate.setRequiredFields(fieldNames);
}
/**
* Configure the MessageSource that resolves localized {@link BindingResult} alert messages.
* @param messageSource the message source
*/
public void setMessageSource(MessageSource messageSource) {
Assert.notNull(messageSource, "The MessageSource is required");
this.messageSource = messageSource;
}
// subclass hooks
/**
* Create the template defining the bulk-binding algorithm.
* Subclasses may override to customize the algorithm.
*/
protected BindTemplate createBindTemplate() {
return new BindTemplate();
}
/**
* The template defining the bulk-binding algorithm.
*/
protected BindTemplate getBindTemplate() {
return bindTemplate;
}
/**
* The configured MessageSource that resolves binding result alert messages.
*/
protected MessageSource getMessageSource() {
return messageSource;
}
}
\ No newline at end of file
......@@ -18,9 +18,9 @@ package org.springframework.model.binder.support;
import org.springframework.model.binder.BindingResult;
/**
* BindTemplate callback interface for binding a single field value.
* Binder callback interface for binding a single field value.
* @author Keith Donald
* @see BindTemplate#bind(java.util.Map, BindCallback)
* @see AbstractBinder#createFieldBinder(Object)
*/
public interface FieldBinder {
......
......@@ -15,8 +15,6 @@
*/
package org.springframework.model.binder.support;
import java.util.Map;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
......@@ -29,7 +27,6 @@ import org.springframework.model.alert.Alert;
import org.springframework.model.alert.Severity;
import org.springframework.model.binder.Binder;
import org.springframework.model.binder.BindingResult;
import org.springframework.model.binder.BindingResults;
/**
* A {@link Binder} implementation that accepts any target object and uses
......@@ -38,19 +35,20 @@ import org.springframework.model.binder.BindingResults;
* @author Mark Fisher
* @since 3.0
*/
public class GenericBinder extends BinderSupport implements Binder<Object> {
public class GenericBinder extends AbstractBinder<Object> {
private final ExpressionParser parser = new SpelExpressionParser(
SpelExpressionParserConfiguration.CreateObjectIfAttemptToReferenceNull
| SpelExpressionParserConfiguration.GrowListsOnIndexBeyondSize);
public BindingResults bind(Map<String, ? extends Object> fieldValues, Object model) {
@Override
protected FieldBinder createFieldBinder(Object model) {
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setRootObject(model);
FieldBinder fieldBinder = new EvaluationContextFieldBinder(parser, evaluationContext);
return getBindTemplate().bind(fieldValues, fieldBinder);
return new EvaluationContextFieldBinder(parser, evaluationContext);
}
private static class EvaluationContextFieldBinder implements FieldBinder {
private final ExpressionParser parser;
......
......@@ -18,11 +18,9 @@ package org.springframework.model.ui.support;
import java.util.Map;
import org.springframework.context.MessageSource;
import org.springframework.model.binder.Binder;
import org.springframework.model.binder.BindingResult;
import org.springframework.model.binder.BindingResults;
import org.springframework.model.binder.support.AbstractBinder;
import org.springframework.model.binder.support.AlertBindingResult;
import org.springframework.model.binder.support.BinderSupport;
import org.springframework.model.binder.support.FieldBinder;
import org.springframework.model.binder.support.FieldNotEditableResult;
import org.springframework.model.binder.support.FieldNotFoundResult;
......@@ -39,28 +37,15 @@ import org.springframework.model.ui.PresentationModel;
* @see #setRequiredFields(String[])
* @see #bind(Map, PresentationModel)
*/
public class PresentationModelBinder extends BinderSupport implements Binder<PresentationModel> {
public class PresentationModelBinder extends AbstractBinder<PresentationModel> {
public BindingResults bind(Map<String, ? extends Object> fieldValues, PresentationModel model) {
fieldValues = filter(fieldValues, model);
return getBindTemplate().bind(fieldValues, new FieldModelBinder(model, getMessageSource()));
}
// subclassing hooks
/**
* Filter the fields to bind.
* Allows for pre-processing the fieldValues Map before any binding occurs.
* For example, you might insert empty or default values for fields that are not present.
* As another example, you might collapse multiple fields into a single field.
* Default implementation simply returns the fieldValues Map unchanged.
* @param fieldValues the original fieldValues Map provided by the caller
* @return the filtered fieldValues Map that will be used to bind
*/
protected Map<String, ? extends Object> filter(Map<String, ? extends Object> fieldValues, PresentationModel model) {
return fieldValues;
@Override
protected FieldBinder createFieldBinder(PresentationModel model) {
return new FieldModelBinder(model, getMessageSource());
}
// internal helpers
private static class FieldModelBinder implements FieldBinder {
......@@ -93,4 +78,4 @@ public class PresentationModelBinder extends BinderSupport implements Binder<Pre
}
}
}
\ No newline at end of file
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册