added bind template / field binder
This commit is contained in:
parent
ccb0a30169
commit
a66aa8c320
|
|
@ -22,15 +22,17 @@ import java.util.Map;
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see #bind(Map)
|
* @see #bind(Map)
|
||||||
|
* @param <M> The type of model this binder binds to
|
||||||
*/
|
*/
|
||||||
public interface Binder {
|
public interface Binder<M> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind submitted field values.
|
* Bind submitted field values.
|
||||||
* @param fieldValues the field values to bind
|
* @param fieldValues the field values to bind
|
||||||
|
* @param model the model to bind to
|
||||||
* @return the results of the binding operation
|
* @return the results of the binding operation
|
||||||
* @throws MissingFieldException when the fieldValues Map is missing required fields
|
* @throws MissingFieldException when the fieldValues Map is missing required fields
|
||||||
*/
|
*/
|
||||||
BindingResults bind(Map<String, ? extends Object> fieldValues);
|
BindingResults bind(Map<String, ? extends Object> fieldValues, M model);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -15,8 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.model.binder.support;
|
package org.springframework.model.binder.support;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.context.MessageSource;
|
import org.springframework.context.MessageSource;
|
||||||
|
|
@ -27,26 +25,32 @@ import org.springframework.model.binder.MissingFieldException;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base {@link Binder binder} implementation designed for subclassing.
|
* Base Binder implementation that defines common structural elements.
|
||||||
|
* Subclasses should 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 #setMessageSource(MessageSource)
|
* @see #setMessageSource(MessageSource)
|
||||||
* @see #bind(Map)
|
* @see #bind(Map, Object)
|
||||||
|
* @see #createBindTemplate()
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractBinder implements Binder {
|
public abstract class AbstractBinder<M> implements Binder<M> {
|
||||||
|
|
||||||
private String[] requiredFields;
|
private BindTemplate bindTemplate;
|
||||||
|
|
||||||
private MessageSource messageSource;
|
private MessageSource messageSource;
|
||||||
|
|
||||||
|
public AbstractBinder() {
|
||||||
|
bindTemplate = createBindTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the fields for which values must be present in each bind attempt.
|
* Configure the fields for which values must be present in each bind attempt.
|
||||||
* @param fieldNames the required field names
|
* @param fieldNames the required field names
|
||||||
* @see MissingFieldException
|
* @see MissingFieldException
|
||||||
*/
|
*/
|
||||||
public void setRequiredFields(String[] fieldNames) {
|
public void setRequiredFields(String[] fieldNames) {
|
||||||
this.requiredFields = fieldNames;
|
bindTemplate.setRequiredFields(fieldNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -58,31 +62,23 @@ public abstract class AbstractBinder implements Binder {
|
||||||
this.messageSource = messageSource;
|
this.messageSource = messageSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
// implementing Binder
|
public abstract BindingResults bind(Map<String, ? extends Object> fieldValues, M model);
|
||||||
|
|
||||||
public BindingResults bind(Map<String, ? extends Object> fieldValues) {
|
// subclass hooks
|
||||||
fieldValues = filter(fieldValues);
|
|
||||||
checkRequired(fieldValues);
|
|
||||||
ArrayListBindingResults results = new ArrayListBindingResults(fieldValues.size());
|
|
||||||
for (Map.Entry<String, ? extends Object> fieldValue : fieldValues.entrySet()) {
|
|
||||||
results.add(bindField(fieldValue.getKey(), fieldValue.getValue()));
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
// subclassing hooks
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook subclasses may use to filter the source values to bind.
|
* Create the template defining the bulk-binding algorithm.
|
||||||
* This hook allows the binder to pre-process the field values before binding occurs.
|
* Subclasses may override to customize the algorithm.
|
||||||
* For example, a Binder might insert empty or default values for fields that are not present.
|
|
||||||
* As another example, a Binder might collapse multiple source values into a single source value.
|
|
||||||
* 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) {
|
protected BindTemplate createBindTemplate() {
|
||||||
return fieldValues;
|
return new BindTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The template defining the bulk-binding algorithm.
|
||||||
|
*/
|
||||||
|
protected BindTemplate getBindTemplate() {
|
||||||
|
return bindTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -92,35 +88,4 @@ public abstract class AbstractBinder implements Binder {
|
||||||
return messageSource;
|
return messageSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook method subclasses override to perform a single field binding.
|
|
||||||
* @param name the field name
|
|
||||||
* @param value the field value
|
|
||||||
* @return the binding result
|
|
||||||
*/
|
|
||||||
protected abstract BindingResult bindField(String name, Object value);
|
|
||||||
|
|
||||||
// internal helpers
|
|
||||||
|
|
||||||
private void checkRequired(Map<String, ? extends Object> fieldValues) {
|
|
||||||
if (requiredFields == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<String> missingRequired = new ArrayList<String>();
|
|
||||||
for (String required : requiredFields) {
|
|
||||||
boolean found = false;
|
|
||||||
for (String property : fieldValues.keySet()) {
|
|
||||||
if (property.equals(required)) {
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
missingRequired.add(required);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!missingRequired.isEmpty()) {
|
|
||||||
throw new MissingFieldException(missingRequired, fieldValues);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* 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 java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.springframework.model.binder.BindingResults;
|
||||||
|
import org.springframework.model.binder.MissingFieldException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A template that encapsulates the general bulk-binding algorithm.
|
||||||
|
* @author Keith Donald
|
||||||
|
* @since 3.0
|
||||||
|
* @see #setRequiredFields(String[])
|
||||||
|
* @see #bind(Map)
|
||||||
|
*/
|
||||||
|
public class BindTemplate {
|
||||||
|
|
||||||
|
private String[] requiredFields;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
this.requiredFields = fieldNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementing Binder
|
||||||
|
|
||||||
|
public BindingResults bind(Map<String, ? extends Object> fieldValues, FieldBinder fieldBinder) {
|
||||||
|
checkRequired(fieldValues);
|
||||||
|
ArrayListBindingResults results = new ArrayListBindingResults(fieldValues.size());
|
||||||
|
for (Map.Entry<String, ? extends Object> fieldValue : fieldValues.entrySet()) {
|
||||||
|
results.add(fieldBinder.bind(fieldValue.getKey(), fieldValue.getValue()));
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// internal helpers
|
||||||
|
|
||||||
|
private void checkRequired(Map<String, ? extends Object> fieldValues) {
|
||||||
|
if (requiredFields == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<String> missingRequired = new ArrayList<String>();
|
||||||
|
for (String required : requiredFields) {
|
||||||
|
boolean found = false;
|
||||||
|
for (String property : fieldValues.keySet()) {
|
||||||
|
if (property.equals(required)) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
missingRequired.add(required);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!missingRequired.isEmpty()) {
|
||||||
|
throw new MissingFieldException(missingRequired, fieldValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* 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.model.binder.BindingResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BindTemplate callback interface for binding a single field value.
|
||||||
|
* @author Keith Donald
|
||||||
|
* @see BindTemplate#bind(java.util.Map, BindCallback)
|
||||||
|
*/
|
||||||
|
public interface FieldBinder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind a single field.
|
||||||
|
* @param fieldName the field name
|
||||||
|
* @param value the field value
|
||||||
|
* @return the binding result
|
||||||
|
*/
|
||||||
|
BindingResult bind(String fieldName, Object value);
|
||||||
|
}
|
||||||
|
|
@ -18,62 +18,78 @@ 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.AbstractBinder;
|
||||||
import org.springframework.model.binder.support.AlertBindingResult;
|
import org.springframework.model.binder.support.AlertBindingResult;
|
||||||
|
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;
|
||||||
import org.springframework.model.ui.BindingStatus;
|
import org.springframework.model.ui.BindingStatus;
|
||||||
import org.springframework.model.ui.FieldModel;
|
import org.springframework.model.ui.FieldModel;
|
||||||
import org.springframework.model.ui.FieldNotFoundException;
|
import org.springframework.model.ui.FieldNotFoundException;
|
||||||
import org.springframework.model.ui.PresentationModel;
|
import org.springframework.model.ui.PresentationModel;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A generic {@link Binder binder} suitable for use in most environments.
|
* Binds field values to PresentationModel objects.
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see #setMessageSource(MessageSource)
|
* @see #setMessageSource(MessageSource)
|
||||||
* @see #setRequiredFields(String[])
|
* @see #setRequiredFields(String[])
|
||||||
* @see #bind(Map)
|
* @see #bind(Map, PresentationModel)
|
||||||
*/
|
*/
|
||||||
public class PresentationModelBinder extends AbstractBinder {
|
public class PresentationModelBinder extends AbstractBinder<PresentationModel> {
|
||||||
|
|
||||||
private PresentationModel presentationModel;
|
public BindingResults bind(Map<String, ? extends Object> fieldValues, PresentationModel model) {
|
||||||
|
fieldValues = filter(fieldValues, model);
|
||||||
public PresentationModelBinder(PresentationModel presentationModel) {
|
return getBindTemplate().bind(fieldValues, new FieldModelBinder(model, getMessageSource()));
|
||||||
Assert.notNull(presentationModel, "The PresentationModel is required");
|
|
||||||
this.presentationModel = presentationModel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// subclassing hooks
|
// subclassing hooks
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the model for the field.
|
* Filter the fields to bind.
|
||||||
* @param fieldName
|
* Allows for pre-processing the fieldValues Map before any binding occurs.
|
||||||
* @return the field model
|
* For example, you might insert empty or default values for fields that are not present.
|
||||||
* @throws NoSuchFieldException if no such field exists
|
* 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 FieldModel getFieldModel(String fieldName) {
|
protected Map<String, ? extends Object> filter(Map<String, ? extends Object> fieldValues, PresentationModel model) {
|
||||||
return presentationModel.getFieldModel(fieldName);
|
return fieldValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BindingResult bindField(String name, Object value) {
|
// internal helpers
|
||||||
|
|
||||||
|
private static class FieldModelBinder implements FieldBinder {
|
||||||
|
|
||||||
|
private PresentationModel presentationModel;
|
||||||
|
|
||||||
|
private MessageSource messageSource;
|
||||||
|
|
||||||
|
public FieldModelBinder(PresentationModel presentationModel, MessageSource messageSource) {
|
||||||
|
this.presentationModel = presentationModel;
|
||||||
|
this.messageSource = messageSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BindingResult bind(String fieldName, Object value) {
|
||||||
FieldModel field;
|
FieldModel field;
|
||||||
try {
|
try {
|
||||||
field = getFieldModel(name);
|
field = presentationModel.getFieldModel(fieldName);
|
||||||
} catch (FieldNotFoundException e) {
|
} catch (FieldNotFoundException e) {
|
||||||
return new FieldNotFoundResult(name, value, getMessageSource());
|
return new FieldNotFoundResult(fieldName, value, messageSource);
|
||||||
}
|
}
|
||||||
if (!field.isEditable()) {
|
if (!field.isEditable()) {
|
||||||
return new FieldNotEditableResult(name, value, getMessageSource());
|
return new FieldNotEditableResult(fieldName, value, messageSource);
|
||||||
} else {
|
} else {
|
||||||
field.applySubmittedValue(value);
|
field.applySubmittedValue(value);
|
||||||
if (field.getBindingStatus() == BindingStatus.DIRTY) {
|
if (field.getBindingStatus() == BindingStatus.DIRTY) {
|
||||||
field.commit();
|
field.commit();
|
||||||
}
|
}
|
||||||
return new AlertBindingResult(name, value, field.getStatusAlert());
|
return new AlertBindingResult(fieldName, value, field.getStatusAlert());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -28,6 +28,7 @@ import org.springframework.model.ui.PresentationModel;
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see #setDefaultPrefix(String)
|
* @see #setDefaultPrefix(String)
|
||||||
* @see #setPresentPrefix(String)
|
* @see #setPresentPrefix(String)
|
||||||
|
* @see #filter(Map, PresentationModel)
|
||||||
*/
|
*/
|
||||||
public class WebBinder extends PresentationModelBinder {
|
public class WebBinder extends PresentationModelBinder {
|
||||||
|
|
||||||
|
|
@ -35,14 +36,6 @@ public class WebBinder extends PresentationModelBinder {
|
||||||
|
|
||||||
private String presentPrefix = "_";
|
private String presentPrefix = "_";
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new web binder for the model object.
|
|
||||||
* @param model the model object containing properties this binder will bind to
|
|
||||||
*/
|
|
||||||
public WebBinder(PresentationModel bindingFactory) {
|
|
||||||
super(bindingFactory);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the prefix used to detect the default value for a field when no value is submitted.
|
* Configure the prefix used to detect the default value for a field when no value is submitted.
|
||||||
* Default is '!'.
|
* Default is '!'.
|
||||||
|
|
@ -61,7 +54,7 @@ public class WebBinder extends PresentationModelBinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Map<String, ? extends Object> filter(Map<String, ? extends Object> fieldValues) {
|
protected Map<String, ? extends Object> filter(Map<String, ? extends Object> fieldValues, PresentationModel model) {
|
||||||
LinkedHashMap<String, Object> filteredValues = new LinkedHashMap<String, Object>();
|
LinkedHashMap<String, Object> filteredValues = new LinkedHashMap<String, Object>();
|
||||||
for (Map.Entry<String, ? extends Object> entry : fieldValues.entrySet()) {
|
for (Map.Entry<String, ? extends Object> entry : fieldValues.entrySet()) {
|
||||||
String field = entry.getKey();
|
String field = entry.getKey();
|
||||||
|
|
@ -74,7 +67,7 @@ public class WebBinder extends PresentationModelBinder {
|
||||||
} else if (field.startsWith(presentPrefix)) {
|
} else if (field.startsWith(presentPrefix)) {
|
||||||
field = field.substring(presentPrefix.length());
|
field = field.substring(presentPrefix.length());
|
||||||
if (!fieldValues.containsKey(field) && !fieldValues.containsKey(defaultPrefix + field)) {
|
if (!fieldValues.containsKey(field) && !fieldValues.containsKey(defaultPrefix + field)) {
|
||||||
value = getEmptyValue(getFieldModel(field));
|
value = getEmptyValue(model.getFieldModel(field));
|
||||||
filteredValues.put(field, value);
|
filteredValues.put(field, value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public class PresentationModelBinderTests {
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
bean = new TestBean();
|
bean = new TestBean();
|
||||||
presentationModel = new DefaultPresentationModel(bean);
|
presentationModel = new DefaultPresentationModel(bean);
|
||||||
binder = new PresentationModelBinder(presentationModel);
|
binder = new PresentationModelBinder();
|
||||||
LocaleContextHolder.setLocale(Locale.US);
|
LocaleContextHolder.setLocale(Locale.US);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,7 +62,7 @@ public class PresentationModelBinderTests {
|
||||||
values.put("string", "test");
|
values.put("string", "test");
|
||||||
values.put("integer", "3");
|
values.put("integer", "3");
|
||||||
values.put("foo", "BAR");
|
values.put("foo", "BAR");
|
||||||
BindingResults results = binder.bind(values);
|
BindingResults results = binder.bind(values, presentationModel);
|
||||||
assertEquals(3, results.size());
|
assertEquals(3, results.size());
|
||||||
|
|
||||||
assertEquals("string", results.get(0).getFieldName());
|
assertEquals("string", results.get(0).getFieldName());
|
||||||
|
|
@ -89,7 +89,7 @@ public class PresentationModelBinderTests {
|
||||||
// bad value
|
// bad value
|
||||||
values.put("integer", "bogus");
|
values.put("integer", "bogus");
|
||||||
values.put("foo", "BAR");
|
values.put("foo", "BAR");
|
||||||
BindingResults results = binder.bind(values);
|
BindingResults results = binder.bind(values, presentationModel);
|
||||||
assertEquals(3, results.size());
|
assertEquals(3, results.size());
|
||||||
assertTrue(results.get(1).isFailure());
|
assertTrue(results.get(1).isFailure());
|
||||||
assertEquals("typeMismatch", results.get(1).getAlert().getCode());
|
assertEquals("typeMismatch", results.get(1).getAlert().getCode());
|
||||||
|
|
@ -98,14 +98,14 @@ public class PresentationModelBinderTests {
|
||||||
@Test
|
@Test
|
||||||
public void bindSingleValuePropertyFormatter() throws ParseException {
|
public void bindSingleValuePropertyFormatter() throws ParseException {
|
||||||
presentationModel.field("date").formatWith(new DateFormatter());
|
presentationModel.field("date").formatWith(new DateFormatter());
|
||||||
binder.bind(Collections.singletonMap("date", "2009-06-01"));
|
binder.bind(Collections.singletonMap("date", "2009-06-01"), presentationModel);
|
||||||
assertEquals(new DateFormatter().parse("2009-06-01", Locale.US), bean.getDate());
|
assertEquals(new DateFormatter().parse("2009-06-01", Locale.US), bean.getDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void bindSingleValuePropertyFormatterParseException() {
|
public void bindSingleValuePropertyFormatterParseException() {
|
||||||
presentationModel.field("date").formatWith(new DateFormatter());
|
presentationModel.field("date").formatWith(new DateFormatter());
|
||||||
BindingResults results = binder.bind(Collections.singletonMap("date", "bogus"));
|
BindingResults results = binder.bind(Collections.singletonMap("date", "bogus"), presentationModel);
|
||||||
assertEquals(1, results.size());
|
assertEquals(1, results.size());
|
||||||
assertTrue(results.get(0).isFailure());
|
assertTrue(results.get(0).isFailure());
|
||||||
assertEquals("typeMismatch", results.get(0).getAlert().getCode());
|
assertEquals("typeMismatch", results.get(0).getAlert().getCode());
|
||||||
|
|
@ -117,7 +117,7 @@ public class PresentationModelBinderTests {
|
||||||
formatterRegistry.add(Date.class, new DateFormatter());
|
formatterRegistry.add(Date.class, new DateFormatter());
|
||||||
presentationModel.setFormatterRegistry(formatterRegistry);
|
presentationModel.setFormatterRegistry(formatterRegistry);
|
||||||
|
|
||||||
binder.bind(Collections.singletonMap("date", "2009-06-01"));
|
binder.bind(Collections.singletonMap("date", "2009-06-01"), presentationModel);
|
||||||
assertEquals(new DateFormatter().parse("2009-06-01", Locale.US), bean.getDate());
|
assertEquals(new DateFormatter().parse("2009-06-01", Locale.US), bean.getDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,13 +127,13 @@ public class PresentationModelBinderTests {
|
||||||
formatterRegistry.add(new CurrencyAnnotationFormatterFactory());
|
formatterRegistry.add(new CurrencyAnnotationFormatterFactory());
|
||||||
presentationModel.setFormatterRegistry(formatterRegistry);
|
presentationModel.setFormatterRegistry(formatterRegistry);
|
||||||
|
|
||||||
binder.bind(Collections.singletonMap("currency", "$23.56"));
|
binder.bind(Collections.singletonMap("currency", "$23.56"), presentationModel);
|
||||||
assertEquals(new BigDecimal("23.56"), bean.getCurrency());
|
assertEquals(new BigDecimal("23.56"), bean.getCurrency());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void bindSingleValuePropertyNotFound() throws ParseException {
|
public void bindSingleValuePropertyNotFound() throws ParseException {
|
||||||
BindingResults results = binder.bind(Collections.singletonMap("bogus", "2009-06-01"));
|
BindingResults results = binder.bind(Collections.singletonMap("bogus", "2009-06-01"), presentationModel);
|
||||||
assertEquals("bogus", results.get(0).getFieldName());
|
assertEquals("bogus", results.get(0).getFieldName());
|
||||||
assertTrue(results.get(0).isFailure());
|
assertTrue(results.get(0).isFailure());
|
||||||
assertEquals("fieldNotFound", results.get(0).getAlert().getCode());
|
assertEquals("fieldNotFound", results.get(0).getAlert().getCode());
|
||||||
|
|
@ -143,7 +143,7 @@ public class PresentationModelBinderTests {
|
||||||
public void bindMissingRequiredSourceValue() {
|
public void bindMissingRequiredSourceValue() {
|
||||||
binder.setRequiredFields(new String[] { "integer" });
|
binder.setRequiredFields(new String[] { "integer" });
|
||||||
// missing "integer" - violated bind contract
|
// missing "integer" - violated bind contract
|
||||||
binder.bind(Collections.singletonMap("string", "test"));
|
binder.bind(Collections.singletonMap("string", "test"), presentationModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -236,7 +236,7 @@ public class PresentationModelBinderTests {
|
||||||
Map<String, String[]> values = new LinkedHashMap<String, String[]>();
|
Map<String, String[]> values = new LinkedHashMap<String, String[]>();
|
||||||
values.put("addresses", new String[] { "4655 Macy Lane:Melbourne:FL:35452",
|
values.put("addresses", new String[] { "4655 Macy Lane:Melbourne:FL:35452",
|
||||||
"1234 Rostock Circle:Palm Bay:FL:32901", "1977 Bel Aire Estates:Coker:AL:12345" });
|
"1234 Rostock Circle:Palm Bay:FL:32901", "1977 Bel Aire Estates:Coker:AL:12345" });
|
||||||
binder.bind(values);
|
binder.bind(values, presentationModel);
|
||||||
assertEquals(3, bean.addresses.size());
|
assertEquals(3, bean.addresses.size());
|
||||||
assertEquals("4655 Macy Lane", bean.addresses.get(0).street);
|
assertEquals("4655 Macy Lane", bean.addresses.get(0).street);
|
||||||
assertEquals("Melbourne", bean.addresses.get(0).city);
|
assertEquals("Melbourne", bean.addresses.get(0).city);
|
||||||
|
|
@ -250,7 +250,7 @@ public class PresentationModelBinderTests {
|
||||||
values.put("addresses[0]", "4655 Macy Lane:Melbourne:FL:35452");
|
values.put("addresses[0]", "4655 Macy Lane:Melbourne:FL:35452");
|
||||||
values.put("addresses[1]", "1234 Rostock Circle:Palm Bay:FL:32901");
|
values.put("addresses[1]", "1234 Rostock Circle:Palm Bay:FL:32901");
|
||||||
values.put("addresses[5]", "1977 Bel Aire Estates:Coker:AL:12345");
|
values.put("addresses[5]", "1977 Bel Aire Estates:Coker:AL:12345");
|
||||||
binder.bind(values);
|
binder.bind(values, presentationModel);
|
||||||
Assert.assertEquals(6, bean.addresses.size());
|
Assert.assertEquals(6, bean.addresses.size());
|
||||||
assertEquals("4655 Macy Lane", bean.addresses.get(0).street);
|
assertEquals("4655 Macy Lane", bean.addresses.get(0).street);
|
||||||
assertEquals("Melbourne", bean.addresses.get(0).city);
|
assertEquals("Melbourne", bean.addresses.get(0).city);
|
||||||
|
|
@ -267,7 +267,7 @@ public class PresentationModelBinderTests {
|
||||||
values
|
values
|
||||||
.put("addresses",
|
.put("addresses",
|
||||||
"4655 Macy Lane:Melbourne:FL:35452,1234 Rostock Circle:Palm Bay:FL:32901,1977 Bel Aire Estates:Coker:AL:12345");
|
"4655 Macy Lane:Melbourne:FL:35452,1234 Rostock Circle:Palm Bay:FL:32901,1977 Bel Aire Estates:Coker:AL:12345");
|
||||||
binder.bind(values);
|
binder.bind(values, presentationModel);
|
||||||
Assert.assertEquals(3, bean.addresses.size());
|
Assert.assertEquals(3, bean.addresses.size());
|
||||||
assertEquals("4655 Macy Lane", bean.addresses.get(0).street);
|
assertEquals("4655 Macy Lane", bean.addresses.get(0).street);
|
||||||
assertEquals("Melbourne", bean.addresses.get(0).city);
|
assertEquals("Melbourne", bean.addresses.get(0).city);
|
||||||
|
|
@ -289,7 +289,7 @@ public class PresentationModelBinderTests {
|
||||||
values
|
values
|
||||||
.put("addresses",
|
.put("addresses",
|
||||||
"4655 Macy Lane:Melbourne:FL:35452,1234 Rostock Circle:Palm Bay:FL:32901,1977 Bel Aire Estates:Coker:AL:12345");
|
"4655 Macy Lane:Melbourne:FL:35452,1234 Rostock Circle:Palm Bay:FL:32901,1977 Bel Aire Estates:Coker:AL:12345");
|
||||||
binder.bind(values);
|
binder.bind(values, presentationModel);
|
||||||
Assert.assertEquals(3, bean.addresses.size());
|
Assert.assertEquals(3, bean.addresses.size());
|
||||||
assertEquals("4655 Macy Lane", bean.addresses.get(0).street);
|
assertEquals("4655 Macy Lane", bean.addresses.get(0).street);
|
||||||
assertEquals("Melbourne", bean.addresses.get(0).city);
|
assertEquals("Melbourne", bean.addresses.get(0).city);
|
||||||
|
|
@ -371,7 +371,7 @@ public class PresentationModelBinderTests {
|
||||||
values.put("addresses[5].state", "FL");
|
values.put("addresses[5].state", "FL");
|
||||||
values.put("addresses[5].zip", "32901");
|
values.put("addresses[5].zip", "32901");
|
||||||
|
|
||||||
BindingResults results = binder.bind(values);
|
BindingResults results = binder.bind(values, presentationModel);
|
||||||
Assert.assertEquals(6, bean.addresses.size());
|
Assert.assertEquals(6, bean.addresses.size());
|
||||||
Assert.assertEquals("Palm Bay", bean.addresses.get(1).city);
|
Assert.assertEquals("Palm Bay", bean.addresses.get(1).city);
|
||||||
Assert.assertNotNull(bean.addresses.get(2));
|
Assert.assertNotNull(bean.addresses.get(2));
|
||||||
|
|
@ -382,7 +382,7 @@ public class PresentationModelBinderTests {
|
||||||
public void bindToMap() {
|
public void bindToMap() {
|
||||||
Map<String, String[]> values = new LinkedHashMap<String, String[]>();
|
Map<String, String[]> values = new LinkedHashMap<String, String[]>();
|
||||||
values.put("favoriteFoodsByGroup", new String[] { "DAIRY=Milk", "FRUIT=Peaches", "MEAT=Ham" });
|
values.put("favoriteFoodsByGroup", new String[] { "DAIRY=Milk", "FRUIT=Peaches", "MEAT=Ham" });
|
||||||
binder.bind(values);
|
binder.bind(values, presentationModel);
|
||||||
Assert.assertEquals(3, bean.favoriteFoodsByGroup.size());
|
Assert.assertEquals(3, bean.favoriteFoodsByGroup.size());
|
||||||
assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY));
|
assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY));
|
||||||
assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT));
|
assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT));
|
||||||
|
|
@ -395,7 +395,7 @@ public class PresentationModelBinderTests {
|
||||||
values.put("favoriteFoodsByGroup[DAIRY]", "Milk");
|
values.put("favoriteFoodsByGroup[DAIRY]", "Milk");
|
||||||
values.put("favoriteFoodsByGroup[FRUIT]", "Peaches");
|
values.put("favoriteFoodsByGroup[FRUIT]", "Peaches");
|
||||||
values.put("favoriteFoodsByGroup[MEAT]", "Ham");
|
values.put("favoriteFoodsByGroup[MEAT]", "Ham");
|
||||||
binder.bind(values);
|
binder.bind(values, presentationModel);
|
||||||
Assert.assertEquals(3, bean.favoriteFoodsByGroup.size());
|
Assert.assertEquals(3, bean.favoriteFoodsByGroup.size());
|
||||||
assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY));
|
assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY));
|
||||||
assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT));
|
assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT));
|
||||||
|
|
@ -406,7 +406,7 @@ public class PresentationModelBinderTests {
|
||||||
public void bindToMapSingleString() {
|
public void bindToMapSingleString() {
|
||||||
Map<String, String> values = new LinkedHashMap<String, String>();
|
Map<String, String> values = new LinkedHashMap<String, String>();
|
||||||
values.put("favoriteFoodsByGroup", "DAIRY=Milk FRUIT=Peaches MEAT=Ham");
|
values.put("favoriteFoodsByGroup", "DAIRY=Milk FRUIT=Peaches MEAT=Ham");
|
||||||
binder.bind(values);
|
binder.bind(values, presentationModel);
|
||||||
Assert.assertEquals(3, bean.favoriteFoodsByGroup.size());
|
Assert.assertEquals(3, bean.favoriteFoodsByGroup.size());
|
||||||
assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY));
|
assertEquals("Milk", bean.favoriteFoodsByGroup.get(FoodGroup.DAIRY));
|
||||||
assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT));
|
assertEquals("Peaches", bean.favoriteFoodsByGroup.get(FoodGroup.FRUIT));
|
||||||
|
|
@ -429,7 +429,7 @@ public class PresentationModelBinderTests {
|
||||||
public void bindToNullObjectPath() {
|
public void bindToNullObjectPath() {
|
||||||
Map<String, String> values = new LinkedHashMap<String, String>();
|
Map<String, String> values = new LinkedHashMap<String, String>();
|
||||||
values.put("primaryAddress.city", "Melbourne");
|
values.put("primaryAddress.city", "Melbourne");
|
||||||
binder.bind(values);
|
binder.bind(values, presentationModel);
|
||||||
Assert.assertEquals("Melbourne", bean.primaryAddress.city);
|
Assert.assertEquals("Melbourne", bean.primaryAddress.city);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ public class WebBinderTests {
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
LocaleContextHolder.setLocale(Locale.US);
|
LocaleContextHolder.setLocale(Locale.US);
|
||||||
presentationModel = new DefaultPresentationModel(bean);
|
presentationModel = new DefaultPresentationModel(bean);
|
||||||
binder = new WebBinder(presentationModel);
|
binder = new WebBinder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
@ -56,7 +56,7 @@ public class WebBinderTests {
|
||||||
userMap.put("!currency", "$5.00");
|
userMap.put("!currency", "$5.00");
|
||||||
userMap.put("_currency", "doesn't matter");
|
userMap.put("_currency", "doesn't matter");
|
||||||
userMap.put("_addresses", "doesn't matter");
|
userMap.put("_addresses", "doesn't matter");
|
||||||
BindingResults results = binder.bind(userMap);
|
BindingResults results = binder.bind(userMap, presentationModel);
|
||||||
assertEquals(6, results.size());
|
assertEquals(6, results.size());
|
||||||
assertEquals("test", results.get(0).getSubmittedValue());
|
assertEquals("test", results.get(0).getSubmittedValue());
|
||||||
assertEquals(null, results.get(1).getSubmittedValue());
|
assertEquals(null, results.get(1).getSubmittedValue());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue