added web binder
This commit is contained in:
parent
37eb0feb2b
commit
be75a43c62
|
|
@ -25,7 +25,7 @@ public interface Binding {
|
|||
* The formatted value to display in the user interface.
|
||||
*/
|
||||
String getValue();
|
||||
|
||||
|
||||
/**
|
||||
* Set the property associated with this binding to the value provided.
|
||||
* The value may be a formatted String, a formatted String[] if a collection binding, or an Object of a type that can be coersed to the underlying property type.
|
||||
|
|
@ -51,5 +51,6 @@ public interface Binding {
|
|||
* When a collection binding, the formatted values to display in the user interface.
|
||||
*/
|
||||
String[] getCollectionValues();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -55,7 +55,7 @@ import org.springframework.ui.format.Formatter;
|
|||
* Binds user-entered values to properties of a model object.
|
||||
* @author Keith Donald
|
||||
*
|
||||
* @param <T> The type of model object this binder binds to
|
||||
* @param <M> The type of model object this binder binds to
|
||||
* @see #add(BindingConfiguration)
|
||||
* @see #bind(Map)
|
||||
*/
|
||||
|
|
@ -214,12 +214,7 @@ public class GenericBinder<M> implements Binder<M> {
|
|||
}
|
||||
|
||||
public boolean isCollection() {
|
||||
Class type;
|
||||
try {
|
||||
type = getValueType();
|
||||
} catch (EvaluationException e) {
|
||||
throw new IllegalArgumentException("Failed to get property expression value type - this should not happen", e);
|
||||
}
|
||||
Class type = getValueType();
|
||||
TypeDescriptor<?> typeDesc = TypeDescriptor.valueOf(type);
|
||||
return typeDesc.isCollection() || typeDesc.isArray();
|
||||
}
|
||||
|
|
@ -248,7 +243,19 @@ public class GenericBinder<M> implements Binder<M> {
|
|||
}
|
||||
return formattedValues;
|
||||
}
|
||||
|
||||
|
||||
// public impl only
|
||||
|
||||
public Class getValueType() {
|
||||
Class type;
|
||||
try {
|
||||
type = property.getValueType(createEvaluationContext());
|
||||
} catch (EvaluationException e) {
|
||||
throw new IllegalArgumentException("Failed to get property expression value type - this should not happen", e);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// internal helpers
|
||||
|
||||
private BindingResult setStringValue(String formatted) {
|
||||
|
|
@ -303,7 +310,7 @@ public class GenericBinder<M> implements Binder<M> {
|
|||
if (formatter != null) {
|
||||
return formatter;
|
||||
} else {
|
||||
Class<?> type = getValueType();
|
||||
Class<?> type = property.getValueType(createEvaluationContext());
|
||||
Formatter<?> formatter = typeFormatters.get(type);
|
||||
if (formatter != null) {
|
||||
return formatter;
|
||||
|
|
@ -320,9 +327,6 @@ public class GenericBinder<M> implements Binder<M> {
|
|||
}
|
||||
}
|
||||
|
||||
private Class<?> getValueType() throws EvaluationException {
|
||||
return property.getValueType(createEvaluationContext());
|
||||
}
|
||||
|
||||
private Annotation[] getAnnotations() throws EvaluationException {
|
||||
return property.getValueTypeDescriptor(createEvaluationContext()).getAnnotations();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.ui.binding.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.ui.binding.UserValue;
|
||||
|
||||
/**
|
||||
* A binder designed for use in HTTP (web) environments.
|
||||
* Suited for binding user-provided HTTP query parameters to model properties.
|
||||
* @author Keith Donald
|
||||
* @param <M> The type of model object this binder binds to
|
||||
* @see #setFieldDefaultPrefix(String)
|
||||
* @see #setFieldMarkerPrefix(String)
|
||||
*/
|
||||
public class WebBinder<M> extends GenericBinder<M> {
|
||||
|
||||
private String fieldMarkerPrefix = "_";
|
||||
|
||||
private String fieldDefaultPrefix = "!";
|
||||
|
||||
/**
|
||||
* Creates a new web binder for the model object.
|
||||
* @param model the model object containing properties this binder will bind to
|
||||
*/
|
||||
public WebBinder(M model) {
|
||||
super(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the prefix for determining default field values.
|
||||
* Default is '!'.
|
||||
*/
|
||||
public void setFieldDefaultPrefix(String fieldDefaultPrefix) {
|
||||
this.fieldDefaultPrefix = fieldDefaultPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the prefix for determining empty fields.
|
||||
* Default is '_'.
|
||||
*/
|
||||
public void setFieldMarkerPrefix(String fieldMarkerPrefix) {
|
||||
this.fieldMarkerPrefix = fieldMarkerPrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserValue> createUserValues(Map<String, ? extends Object> userMap) {
|
||||
List<UserValue> values = new ArrayList<UserValue>();
|
||||
for (Map.Entry<String, ? extends Object> entry : userMap.entrySet()) {
|
||||
String field = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
if (field.startsWith(fieldDefaultPrefix)) {
|
||||
field = field.substring(fieldDefaultPrefix.length());
|
||||
if (!userMap.containsKey(field)) {
|
||||
values.add(new UserValue(field, value));
|
||||
}
|
||||
} else if (field.startsWith(fieldMarkerPrefix)) {
|
||||
field = field.substring(fieldMarkerPrefix.length());
|
||||
if (!userMap.containsKey(field) && !userMap.containsKey(fieldDefaultPrefix + field)) {
|
||||
value = getEmptyValue((BindingImpl) getBinding(field));
|
||||
values.add(new UserValue(field, value));
|
||||
}
|
||||
} else {
|
||||
values.add(new UserValue(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
protected Object getEmptyValue(BindingImpl binding) {
|
||||
Class<?> type = binding.getValueType();
|
||||
if (boolean.class.equals(type) || Boolean.class.equals(type)) {
|
||||
return Boolean.FALSE;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
package org.springframework.ui.binding.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
import org.springframework.ui.binding.Binder;
|
||||
import org.springframework.ui.binding.BindingConfiguration;
|
||||
import org.springframework.ui.binding.BindingResult;
|
||||
import org.springframework.ui.binding.UserValue;
|
||||
import org.springframework.ui.format.date.DateFormatter;
|
||||
import org.springframework.ui.format.number.CurrencyAnnotationFormatterFactory;
|
||||
import org.springframework.ui.format.number.CurrencyFormat;
|
||||
|
||||
public class WebBinderTests {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
LocaleContextHolder.setLocale(Locale.US);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
LocaleContextHolder.setLocale(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindUserValuesCreatedFromUserMap() throws ParseException {
|
||||
Binder<TestBean> binder = new WebBinder<TestBean>(new TestBean());
|
||||
binder.add(new CurrencyAnnotationFormatterFactory());
|
||||
binder.add(new BindingConfiguration("date", new DateFormatter()));
|
||||
Map<String, String> userMap = new LinkedHashMap<String, String>();
|
||||
userMap.put("string", "test");
|
||||
userMap.put("_integer", "doesn't matter");
|
||||
userMap.put("_bool", "doesn't matter");
|
||||
userMap.put("!date", "2009-06-10");
|
||||
userMap.put("!currency", "$5.00");
|
||||
userMap.put("_currency", "doesn't matter");
|
||||
userMap.put("_addresses", "doesn't matter");
|
||||
List<UserValue> values = binder.createUserValues(userMap);
|
||||
List<BindingResult> results = binder.bind(values);
|
||||
assertEquals(6, results.size());
|
||||
assertEquals("test", results.get(0).getUserValue());
|
||||
assertEquals(null, results.get(1).getUserValue());
|
||||
assertEquals(Boolean.FALSE, results.get(2).getUserValue());
|
||||
assertEquals("2009-06-10", results.get(3).getUserValue());
|
||||
assertEquals("$5.00", results.get(4).getUserValue());
|
||||
assertEquals(null, results.get(5).getUserValue());
|
||||
|
||||
assertEquals("test", binder.getModel().getString());
|
||||
assertEquals(0, binder.getModel().getInteger());
|
||||
assertEquals(new DateFormatter().parse("2009-06-10", Locale.US), binder.getModel().getDate());
|
||||
assertEquals(false, binder.getModel().isBool());
|
||||
assertEquals(new BigDecimal("5.00"), binder.getModel().getCurrency());
|
||||
assertEquals(null, binder.getModel().getAddresses());
|
||||
}
|
||||
|
||||
public static enum FooEnum {
|
||||
BAR, BAZ, BOOP;
|
||||
}
|
||||
|
||||
public static class TestBean {
|
||||
private String string;
|
||||
private int integer;
|
||||
private boolean bool;
|
||||
private Date date;
|
||||
private FooEnum foo;
|
||||
private BigDecimal currency;
|
||||
private List<FooEnum> foos;
|
||||
private List<Address> addresses;
|
||||
|
||||
public String getString() {
|
||||
return string;
|
||||
}
|
||||
|
||||
public void setString(String string) {
|
||||
this.string = string;
|
||||
}
|
||||
|
||||
public int getInteger() {
|
||||
return integer;
|
||||
}
|
||||
|
||||
public void setInteger(int integer) {
|
||||
this.integer = integer;
|
||||
}
|
||||
|
||||
public boolean isBool() {
|
||||
return bool;
|
||||
}
|
||||
|
||||
public void setBool(boolean bool) {
|
||||
this.bool = bool;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public FooEnum getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(FooEnum foo) {
|
||||
this.foo = foo;
|
||||
}
|
||||
|
||||
@CurrencyFormat
|
||||
public BigDecimal getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
|
||||
public void setCurrency(BigDecimal currency) {
|
||||
this.currency = currency;
|
||||
}
|
||||
|
||||
public List<FooEnum> getFoos() {
|
||||
return foos;
|
||||
}
|
||||
|
||||
public void setFoos(List<FooEnum> foos) {
|
||||
this.foos = foos;
|
||||
}
|
||||
|
||||
public List<Address> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public void setAddresses(List<Address> addresses) {
|
||||
this.addresses = addresses;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Address {
|
||||
private String street;
|
||||
private String city;
|
||||
private String state;
|
||||
private String zip;
|
||||
private String country;
|
||||
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getZip() {
|
||||
return zip;
|
||||
}
|
||||
|
||||
public void setZip(String zip) {
|
||||
this.zip = zip;
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return country;
|
||||
}
|
||||
|
||||
public void setCountry(String country) {
|
||||
this.country = country;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue