From 990d446c84fc08e3505125e49b2aac89ad6ad624 Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Sat, 25 Jul 2009 04:40:31 +0000 Subject: [PATCH] polish --- .../support/AbstractBinder.java} | 69 +++++----------- .../support/AlertBindingResult.java} | 20 ++--- .../support}/ArrayListBindingResults.java | 2 +- .../support}/FieldNotEditableResult.java | 16 ++-- .../support}/FieldNotFoundResult.java | 16 ++-- .../model/ui/FieldNotFoundException.java | 1 + .../model/ui/PresentationModel.java | 1 + .../model/ui/binder/package-info.java | 5 -- .../ui/{binder => config}/BinderExecutor.java | 3 +- .../ui/support/PresentationModelBinder.java | 81 +++++++++++++++++++ .../ui/{binder => support}/WebBinder.java | 2 +- .../model/ui/binder/GenericBinderTests.java | 2 +- .../model/ui/binder/WebBinderTests.java | 2 +- 13 files changed, 135 insertions(+), 85 deletions(-) rename org.springframework.context/src/main/java/org/springframework/model/{ui/binder/PresentationModelBinder.java => binder/support/AbstractBinder.java} (66%) rename org.springframework.context/src/main/java/org/springframework/model/{ui/binder/BindingStatusResult.java => binder/support/AlertBindingResult.java} (71%) rename org.springframework.context/src/main/java/org/springframework/model/{ui/binder => binder/support}/ArrayListBindingResults.java (97%) rename org.springframework.context/src/main/java/org/springframework/model/{ui/binder => binder/support}/FieldNotEditableResult.java (83%) rename org.springframework.context/src/main/java/org/springframework/model/{ui/binder => binder/support}/FieldNotFoundResult.java (83%) delete mode 100644 org.springframework.context/src/main/java/org/springframework/model/ui/binder/package-info.java rename org.springframework.context/src/main/java/org/springframework/model/ui/{binder => config}/BinderExecutor.java (93%) create mode 100644 org.springframework.context/src/main/java/org/springframework/model/ui/support/PresentationModelBinder.java rename org.springframework.context/src/main/java/org/springframework/model/ui/{binder => support}/WebBinder.java (98%) diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/PresentationModelBinder.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/AbstractBinder.java similarity index 66% rename from org.springframework.context/src/main/java/org/springframework/model/ui/binder/PresentationModelBinder.java rename to org.springframework.context/src/main/java/org/springframework/model/binder/support/AbstractBinder.java index 861461bb26..fd746109c2 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/PresentationModelBinder.java +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/AbstractBinder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.model.ui.binder; +package org.springframework.model.binder.support; import java.util.ArrayList; import java.util.List; @@ -24,32 +24,21 @@ 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.model.ui.BindingStatus; -import org.springframework.model.ui.FieldModel; -import org.springframework.model.ui.FieldNotFoundException; -import org.springframework.model.ui.PresentationModel; import org.springframework.util.Assert; /** - * A generic {@link Binder binder} suitable for use in most environments. + * A base {@link Binder binder} implementation designed for subclassing. * @author Keith Donald * @since 3.0 * @see #setMessageSource(MessageSource) * @see #setRequiredFields(String[]) * @see #bind(Map) */ -public class PresentationModelBinder implements Binder { +public abstract class AbstractBinder implements Binder { - private PresentationModel presentationModel; - private String[] requiredFields; - - private MessageSource messageSource; - public PresentationModelBinder(PresentationModel presentationModel) { - Assert.notNull(presentationModel, "The PresentationModel is required"); - this.presentationModel = presentationModel; - } + private MessageSource messageSource; /** * Configure the MessageSource that resolves localized {@link BindingResult} alert messages. @@ -59,7 +48,7 @@ public class PresentationModelBinder implements Binder { Assert.notNull(messageSource, "The MessageSource is required"); this.messageSource = messageSource; } - + /** * Configure the fields for which values must be present in each bind attempt. * @param fieldNames the field names @@ -68,18 +57,6 @@ public class PresentationModelBinder implements Binder { public void setRequiredFields(String[] fieldNames) { this.requiredFields = fieldNames; } - - // subclassing hooks - - /** - * Get the model for the field. - * @param fieldName - * @return the field model - * @throws NoSuchFieldException if no such field exists - */ - protected FieldModel getFieldModel(String fieldName) { - return presentationModel.getFieldModel(fieldName); - } // implementing Binder @@ -88,18 +65,14 @@ public class PresentationModelBinder implements Binder { checkRequired(fieldValues); ArrayListBindingResults results = new ArrayListBindingResults(fieldValues.size()); for (Map.Entry fieldValue : fieldValues.entrySet()) { - try { - FieldModel field = getFieldModel(fieldValue.getKey()); - results.add(bind(fieldValue, field)); - } catch (FieldNotFoundException e) { - results.add(new FieldNotFoundResult(fieldValue.getKey(), fieldValue.getValue(), messageSource)); - } + results.add(bind(fieldValue)); } return results; } // subclassing hooks + /** * Hook subclasses may use to filter the source values to bind. * This hook allows the binder to pre-process the field values before binding occurs. @@ -112,6 +85,20 @@ public class PresentationModelBinder implements Binder { return fieldValues; } + /** + * The configured MessageSource that resolves binding result alert messages. + */ + protected MessageSource getMessageSource() { + return messageSource; + } + + /** + * Hook method subclasses should override to perform a single binding. + * @param fieldValue the field value to bind + * @return the binding result + */ + protected abstract BindingResult bind(Map.Entry fieldValue); + // internal helpers private void checkRequired(Map fieldValues) { @@ -135,18 +122,4 @@ public class PresentationModelBinder implements Binder { } } - private BindingResult bind(Map.Entry fieldValue, FieldModel field) { - String fieldName = fieldValue.getKey(); - Object value = fieldValue.getValue(); - if (!field.isEditable()) { - return new FieldNotEditableResult(fieldName, value, messageSource); - } else { - field.applySubmittedValue(value); - if (field.getBindingStatus() == BindingStatus.DIRTY) { - field.commit(); - } - return new BindingStatusResult(fieldName, value, field.getStatusAlert()); - } - } - } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/BindingStatusResult.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/AlertBindingResult.java similarity index 71% rename from org.springframework.context/src/main/java/org/springframework/model/ui/binder/BindingStatusResult.java rename to org.springframework.context/src/main/java/org/springframework/model/binder/support/AlertBindingResult.java index 4e36ae05a7..b04909a205 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/BindingStatusResult.java +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/AlertBindingResult.java @@ -13,24 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.model.ui.binder; +package org.springframework.model.binder.support; import org.springframework.model.alert.Alert; import org.springframework.model.alert.Severity; import org.springframework.model.binder.BindingResult; -class BindingStatusResult implements BindingResult { +public class AlertBindingResult implements BindingResult { private String fieldName; - private Object sourceValue; + private Object submittedValue; - private Alert bindingStatusAlert; + private Alert alert; - public BindingStatusResult(String fieldName, Object sourceValue, Alert alert) { + public AlertBindingResult(String fieldName, Object sourceValue, Alert alert) { this.fieldName = fieldName; - this.sourceValue = sourceValue; - this.bindingStatusAlert = alert; + this.submittedValue = sourceValue; + this.alert = alert; } public String getFieldName() { @@ -38,15 +38,15 @@ class BindingStatusResult implements BindingResult { } public Object getSubmittedValue() { - return sourceValue; + return submittedValue; } public boolean isFailure() { - return bindingStatusAlert.getSeverity().compareTo(Severity.INFO) > 1; + return alert.getSeverity().compareTo(Severity.INFO) > 1; } public Alert getAlert() { - return bindingStatusAlert; + return alert; } public String toString() { diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/ArrayListBindingResults.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/ArrayListBindingResults.java similarity index 97% rename from org.springframework.context/src/main/java/org/springframework/model/ui/binder/ArrayListBindingResults.java rename to org.springframework.context/src/main/java/org/springframework/model/binder/support/ArrayListBindingResults.java index 72721a599f..217ebd58a7 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/ArrayListBindingResults.java +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/ArrayListBindingResults.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.model.ui.binder; +package org.springframework.model.binder.support; import java.util.ArrayList; import java.util.Iterator; diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/FieldNotEditableResult.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotEditableResult.java similarity index 83% rename from org.springframework.context/src/main/java/org/springframework/model/ui/binder/FieldNotEditableResult.java rename to org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotEditableResult.java index b10fc5bfb4..16cfb82ef5 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/FieldNotEditableResult.java +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotEditableResult.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.model.ui.binder; +package org.springframework.model.binder.support; import org.springframework.context.MessageSource; import org.springframework.core.style.StylerUtils; @@ -23,17 +23,17 @@ import org.springframework.model.binder.BindingResult; import org.springframework.model.message.MessageBuilder; import org.springframework.model.message.ResolvableArgument; -class FieldNotEditableResult implements BindingResult { +public class FieldNotEditableResult implements BindingResult { private String property; - private Object sourceValue; + private Object submittedValue; private MessageSource messageSource; - public FieldNotEditableResult(String property, Object sourceValue, MessageSource messageSource) { + public FieldNotEditableResult(String property, Object submittedValue, MessageSource messageSource) { this.property = property; - this.sourceValue = sourceValue; + this.submittedValue = submittedValue; this.messageSource = messageSource; } @@ -42,7 +42,7 @@ class FieldNotEditableResult implements BindingResult { } public Object getSubmittedValue() { - return sourceValue; + return submittedValue; } public boolean isFailure() { @@ -63,9 +63,9 @@ class FieldNotEditableResult implements BindingResult { MessageBuilder builder = new MessageBuilder(messageSource); builder.code("bindSuccess"); builder.arg("label", new ResolvableArgument(property)); - builder.arg("value", sourceValue); + builder.arg("value", submittedValue); // TODO lazily create default message - builder.defaultMessage("Successfully bound user value " + StylerUtils.style(sourceValue) + builder.defaultMessage("Successfully bound user value " + StylerUtils.style(submittedValue) + " to property '" + property + "'"); return builder.build(); } diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/FieldNotFoundResult.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotFoundResult.java similarity index 83% rename from org.springframework.context/src/main/java/org/springframework/model/ui/binder/FieldNotFoundResult.java rename to org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotFoundResult.java index 18511d3555..5cd278d2f3 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/FieldNotFoundResult.java +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotFoundResult.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.model.ui.binder; +package org.springframework.model.binder.support; import org.springframework.context.MessageSource; import org.springframework.core.style.StylerUtils; @@ -23,17 +23,17 @@ import org.springframework.model.binder.BindingResult; import org.springframework.model.message.MessageBuilder; import org.springframework.model.message.ResolvableArgument; -class FieldNotFoundResult implements BindingResult { +public class FieldNotFoundResult implements BindingResult { private String property; - private Object sourceValue; + private Object submittedValue; private MessageSource messageSource; - public FieldNotFoundResult(String property, Object sourceValue, MessageSource messageSource) { + public FieldNotFoundResult(String property, Object submittedValue, MessageSource messageSource) { this.property = property; - this.sourceValue = sourceValue; + this.submittedValue = submittedValue; this.messageSource = messageSource; } @@ -42,7 +42,7 @@ class FieldNotFoundResult implements BindingResult { } public Object getSubmittedValue() { - return sourceValue; + return submittedValue; } public boolean isFailure() { @@ -63,9 +63,9 @@ class FieldNotFoundResult implements BindingResult { MessageBuilder builder = new MessageBuilder(messageSource); builder.code("bindSuccess"); builder.arg("label", new ResolvableArgument(property)); - builder.arg("value", sourceValue); + builder.arg("value", submittedValue); // TODO lazily create default message - builder.defaultMessage("Successfully bound user value " + StylerUtils.style(sourceValue) + builder.defaultMessage("Successfully bound user value " + StylerUtils.style(submittedValue) + " to property '" + property + "'"); return builder.build(); } diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/FieldNotFoundException.java b/org.springframework.context/src/main/java/org/springframework/model/ui/FieldNotFoundException.java index 1182d7016c..b809cda4a8 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/FieldNotFoundException.java +++ b/org.springframework.context/src/main/java/org/springframework/model/ui/FieldNotFoundException.java @@ -15,6 +15,7 @@ */ package org.springframework.model.ui; + /** * Thrown when a PresentationModel field cannot be found. * @author Keith Donald diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/PresentationModel.java b/org.springframework.context/src/main/java/org/springframework/model/ui/PresentationModel.java index f893073444..9cf33a15af 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/PresentationModel.java +++ b/org.springframework.context/src/main/java/org/springframework/model/ui/PresentationModel.java @@ -15,6 +15,7 @@ */ package org.springframework.model.ui; + /** * Represents the state and behavior of a presentation independently of the GUI controls used in the interface. * Pulls the state and behavior of a view out into a model class that is part of the presentation. diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/package-info.java b/org.springframework.context/src/main/java/org/springframework/model/ui/binder/package-info.java deleted file mode 100644 index 76001f2c20..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Binder implementation that binds to PresentationModels. - */ -package org.springframework.model.ui.binder; - diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/BinderExecutor.java b/org.springframework.context/src/main/java/org/springframework/model/ui/config/BinderExecutor.java similarity index 93% rename from org.springframework.context/src/main/java/org/springframework/model/ui/binder/BinderExecutor.java rename to org.springframework.context/src/main/java/org/springframework/model/ui/config/BinderExecutor.java index 6456d6b5aa..df65534cb8 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/BinderExecutor.java +++ b/org.springframework.context/src/main/java/org/springframework/model/ui/config/BinderExecutor.java @@ -13,11 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.model.ui.binder; +package org.springframework.model.ui.config; import org.springframework.model.binder.Binder; import org.springframework.model.binder.BindingResults; -import org.springframework.model.ui.config.FieldModelConfiguration; /** * A SPI interface that lets you configure a {@link Binder}, then execute it. 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 new file mode 100644 index 0000000000..ed2947b3b7 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/model/ui/support/PresentationModelBinder.java @@ -0,0 +1,81 @@ +/* + * 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.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.support.AbstractBinder; +import org.springframework.model.binder.support.AlertBindingResult; +import org.springframework.model.binder.support.FieldNotEditableResult; +import org.springframework.model.binder.support.FieldNotFoundResult; +import org.springframework.model.ui.BindingStatus; +import org.springframework.model.ui.FieldModel; +import org.springframework.model.ui.FieldNotFoundException; +import org.springframework.model.ui.PresentationModel; +import org.springframework.util.Assert; + +/** + * A generic {@link Binder binder} suitable for use in most environments. + * @author Keith Donald + * @since 3.0 + * @see #setMessageSource(MessageSource) + * @see #setRequiredFields(String[]) + * @see #bind(Map) + */ +public class PresentationModelBinder extends AbstractBinder { + + private PresentationModel presentationModel; + + public PresentationModelBinder(PresentationModel presentationModel) { + Assert.notNull(presentationModel, "The PresentationModel is required"); + this.presentationModel = presentationModel; + } + + // subclassing hooks + + /** + * Get the model for the field. + * @param fieldName + * @return the field model + * @throws NoSuchFieldException if no such field exists + */ + protected FieldModel getFieldModel(String fieldName) { + return presentationModel.getFieldModel(fieldName); + } + + protected BindingResult bind(Map.Entry fieldValue) { + String fieldName = fieldValue.getKey(); + Object value = fieldValue.getValue(); + FieldModel field; + try { + field = getFieldModel(fieldName); + } catch (FieldNotFoundException e) { + return new FieldNotFoundResult(fieldName, value, getMessageSource()); + } + if (!field.isEditable()) { + return new FieldNotEditableResult(fieldName, value, getMessageSource()); + } else { + field.applySubmittedValue(value); + if (field.getBindingStatus() == BindingStatus.DIRTY) { + field.commit(); + } + return new AlertBindingResult(fieldName, value, field.getStatusAlert()); + } + } +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/WebBinder.java b/org.springframework.context/src/main/java/org/springframework/model/ui/support/WebBinder.java similarity index 98% rename from org.springframework.context/src/main/java/org/springframework/model/ui/binder/WebBinder.java rename to org.springframework.context/src/main/java/org/springframework/model/ui/support/WebBinder.java index 21a053debd..0883537b24 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/binder/WebBinder.java +++ b/org.springframework.context/src/main/java/org/springframework/model/ui/support/WebBinder.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.model.ui.binder; +package org.springframework.model.ui.support; import java.util.LinkedHashMap; import java.util.Map; diff --git a/org.springframework.context/src/test/java/org/springframework/model/ui/binder/GenericBinderTests.java b/org.springframework.context/src/test/java/org/springframework/model/ui/binder/GenericBinderTests.java index 3bf30a1826..fe0ccbd952 100644 --- a/org.springframework.context/src/test/java/org/springframework/model/ui/binder/GenericBinderTests.java +++ b/org.springframework.context/src/test/java/org/springframework/model/ui/binder/GenericBinderTests.java @@ -27,7 +27,6 @@ import org.springframework.model.binder.MissingFieldException; import org.springframework.model.message.MockMessageSource; import org.springframework.model.ui.BindingStatus; import org.springframework.model.ui.FieldModel; -import org.springframework.model.ui.binder.PresentationModelBinder; import org.springframework.model.ui.format.AnnotationFormatterFactory; import org.springframework.model.ui.format.Formatted; import org.springframework.model.ui.format.Formatter; @@ -38,6 +37,7 @@ import org.springframework.model.ui.format.number.IntegerFormatter; import org.springframework.model.ui.support.CollectionTypeDescriptor; import org.springframework.model.ui.support.DefaultPresentationModel; import org.springframework.model.ui.support.GenericFormatterRegistry; +import org.springframework.model.ui.support.PresentationModelBinder; public class GenericBinderTests { diff --git a/org.springframework.context/src/test/java/org/springframework/model/ui/binder/WebBinderTests.java b/org.springframework.context/src/test/java/org/springframework/model/ui/binder/WebBinderTests.java index 33b404a4f5..b2c4615af0 100644 --- a/org.springframework.context/src/test/java/org/springframework/model/ui/binder/WebBinderTests.java +++ b/org.springframework.context/src/test/java/org/springframework/model/ui/binder/WebBinderTests.java @@ -15,12 +15,12 @@ import org.junit.Before; import org.junit.Test; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.model.binder.BindingResults; -import org.springframework.model.ui.binder.WebBinder; import org.springframework.model.ui.format.date.DateFormatter; import org.springframework.model.ui.format.number.CurrencyFormat; import org.springframework.model.ui.format.number.CurrencyFormatter; import org.springframework.model.ui.support.DefaultPresentationModel; import org.springframework.model.ui.support.GenericFormatterRegistry; +import org.springframework.model.ui.support.WebBinder; public class WebBinderTests {