diff --git a/org.springframework.context/src/main/java/org/springframework/model/binder/support/BindTemplate.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/AbstractBinder.java similarity index 50% rename from org.springframework.context/src/main/java/org/springframework/model/binder/support/BindTemplate.java rename to org.springframework.context/src/main/java/org/springframework/model/binder/support/AbstractBinder.java index d3accdc540..42fa28fc43 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/binder/support/BindTemplate.java +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/AbstractBinder.java @@ -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 implements Binder { + + 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 fieldValues, FieldBinder fieldBinder) { + public final BindingResults bind(Map fieldValues, M model) { + fieldValues = filter(fieldValues, model); checkRequired(fieldValues); + FieldBinder fieldBinder = this.createFieldBinder(model); ArrayListBindingResults results = new ArrayListBindingResults(fieldValues.size()); for (Map.Entry 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 filter(Map fieldValues, M model) { + return fieldValues; + } // internal helpers @@ -77,4 +124,4 @@ public class BindTemplate { } } -} \ No newline at end of file +} diff --git a/org.springframework.context/src/main/java/org/springframework/model/binder/support/BinderSupport.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/BinderSupport.java deleted file mode 100644 index bfc0d1876e..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/model/binder/support/BinderSupport.java +++ /dev/null @@ -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; - } - -} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldBinder.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldBinder.java index 4d079d4316..982fa08339 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldBinder.java +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldBinder.java @@ -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 { diff --git a/org.springframework.context/src/main/java/org/springframework/model/binder/support/GenericBinder.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/GenericBinder.java index 9dc27d7c91..a9c1fbc37c 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/binder/support/GenericBinder.java +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/GenericBinder.java @@ -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 { +public class GenericBinder extends AbstractBinder { private final ExpressionParser parser = new SpelExpressionParser( SpelExpressionParserConfiguration.CreateObjectIfAttemptToReferenceNull | SpelExpressionParserConfiguration.GrowListsOnIndexBeyondSize); - public BindingResults bind(Map 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; diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/support/PresentationModelBinder.java b/org.springframework.context/src/main/java/org/springframework/model/ui/support/PresentationModelBinder.java index da9e6b2f6f..c452b38ffc 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/support/PresentationModelBinder.java +++ b/org.springframework.context/src/main/java/org/springframework/model/ui/support/PresentationModelBinder.java @@ -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 { +public class PresentationModelBinder extends AbstractBinder { - public BindingResults bind(Map 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 filter(Map 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