Replaced BinderSupport with a refactored AbstractBinder that delegates to a FieldBinder whose creation is the responsibility of each subclass.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
public BindingResults bind(Map<String, ? extends Object> fieldValues, FieldBinder fieldBinder) {
|
||||
/**
|
||||
* The configured MessageSource that resolves binding result alert messages.
|
||||
*/
|
||||
protected MessageSource getMessageSource() {
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
// Binder implementation
|
||||
|
||||
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 {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user