Browse Source

Replaced BinderSupport with a refactored AbstractBinder that delegates to a FieldBinder whose creation is the responsibility of each subclass.

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1639 50f2f4bb-b051-0410-bef5-90022cba6387
pull/1/head
Mark Fisher 17 years ago
parent
commit
0d609cead2
  1. 59
      org.springframework.context/src/main/java/org/springframework/model/binder/support/AbstractBinder.java
  2. 83
      org.springframework.context/src/main/java/org/springframework/model/binder/support/BinderSupport.java
  3. 4
      org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldBinder.java
  4. 12
      org.springframework.context/src/main/java/org/springframework/model/binder/support/GenericBinder.java
  5. 31
      org.springframework.context/src/main/java/org/springframework/model/ui/support/PresentationModelBinder.java

59
org.springframework.context/src/main/java/org/springframework/model/binder/support/BindTemplate.java → 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.List;
import java.util.Map; 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.BindingResults;
import org.springframework.model.binder.MissingFieldException; 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 * @author Keith Donald
* @since 3.0 * @since 3.0
* @see #setRequiredFields(String[]) * @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; private String[] requiredFields;
@ -42,10 +51,28 @@ public class BindTemplate {
this.requiredFields = fieldNames; 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); checkRequired(fieldValues);
FieldBinder fieldBinder = this.createFieldBinder(model);
ArrayListBindingResults results = new ArrayListBindingResults(fieldValues.size()); ArrayListBindingResults results = new ArrayListBindingResults(fieldValues.size());
for (Map.Entry<String, ? extends Object> fieldValue : fieldValues.entrySet()) { for (Map.Entry<String, ? extends Object> fieldValue : fieldValues.entrySet()) {
results.add(fieldBinder.bind(fieldValue.getKey(), fieldValue.getValue())); results.add(fieldBinder.bind(fieldValue.getKey(), fieldValue.getValue()));
@ -53,6 +80,26 @@ public class BindTemplate {
return results; 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 // internal helpers
@ -77,4 +124,4 @@ public class BindTemplate {
} }
} }
} }

83
org.springframework.context/src/main/java/org/springframework/model/binder/support/BinderSupport.java

@ -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;
}
}

4
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; 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 * @author Keith Donald
* @see BindTemplate#bind(java.util.Map, BindCallback) * @see AbstractBinder#createFieldBinder(Object)
*/ */
public interface FieldBinder { public interface FieldBinder {

12
org.springframework.context/src/main/java/org/springframework/model/binder/support/GenericBinder.java

@ -15,8 +15,6 @@
*/ */
package org.springframework.model.binder.support; package org.springframework.model.binder.support;
import java.util.Map;
import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression; 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.alert.Severity;
import org.springframework.model.binder.Binder; import org.springframework.model.binder.Binder;
import org.springframework.model.binder.BindingResult; import org.springframework.model.binder.BindingResult;
import org.springframework.model.binder.BindingResults;
/** /**
* A {@link Binder} implementation that accepts any target object and uses * A {@link Binder} implementation that accepts any target object and uses
@ -38,19 +35,20 @@ import org.springframework.model.binder.BindingResults;
* @author Mark Fisher * @author Mark Fisher
* @since 3.0 * @since 3.0
*/ */
public class GenericBinder extends BinderSupport implements Binder<Object> { public class GenericBinder extends AbstractBinder<Object> {
private final ExpressionParser parser = new SpelExpressionParser( private final ExpressionParser parser = new SpelExpressionParser(
SpelExpressionParserConfiguration.CreateObjectIfAttemptToReferenceNull SpelExpressionParserConfiguration.CreateObjectIfAttemptToReferenceNull
| SpelExpressionParserConfiguration.GrowListsOnIndexBeyondSize); | SpelExpressionParserConfiguration.GrowListsOnIndexBeyondSize);
public BindingResults bind(Map<String, ? extends Object> fieldValues, Object model) { @Override
protected FieldBinder createFieldBinder(Object model) {
StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.setRootObject(model); evaluationContext.setRootObject(model);
FieldBinder fieldBinder = new EvaluationContextFieldBinder(parser, evaluationContext); return new EvaluationContextFieldBinder(parser, evaluationContext);
return getBindTemplate().bind(fieldValues, fieldBinder);
} }
private static class EvaluationContextFieldBinder implements FieldBinder { private static class EvaluationContextFieldBinder implements FieldBinder {
private final ExpressionParser parser; private final ExpressionParser parser;

31
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 java.util.Map;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.model.binder.Binder;
import org.springframework.model.binder.BindingResult; 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.AlertBindingResult;
import org.springframework.model.binder.support.BinderSupport;
import org.springframework.model.binder.support.FieldBinder; import org.springframework.model.binder.support.FieldBinder;
import org.springframework.model.binder.support.FieldNotEditableResult; import org.springframework.model.binder.support.FieldNotEditableResult;
import org.springframework.model.binder.support.FieldNotFoundResult; import org.springframework.model.binder.support.FieldNotFoundResult;
@ -39,28 +37,15 @@ import org.springframework.model.ui.PresentationModel;
* @see #setRequiredFields(String[]) * @see #setRequiredFields(String[])
* @see #bind(Map, PresentationModel) * @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 // subclassing hooks
/** @Override
* Filter the fields to bind. protected FieldBinder createFieldBinder(PresentationModel model) {
* Allows for pre-processing the fieldValues Map before any binding occurs. return new FieldModelBinder(model, getMessageSource());
* 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;
} }
// internal helpers // internal helpers
private static class FieldModelBinder implements FieldBinder { private static class FieldModelBinder implements FieldBinder {
@ -93,4 +78,4 @@ public class PresentationModelBinder extends BinderSupport implements Binder<Pre
} }
} }
} }

Loading…
Cancel
Save