binding rule impl
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1559 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
ee7113a88a
commit
9fb9157f28
|
|
@ -42,7 +42,7 @@ public interface Binding {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this Binding is enabled.
|
* If this Binding is enabled.
|
||||||
* Used to determine if the user can interact with the field.
|
* Used to determine if the user can interact with the field at all.
|
||||||
* A Binding that is not enabled cannot have source values applied and cannot be committed.
|
* A Binding that is not enabled cannot have source values applied and cannot be committed.
|
||||||
*/
|
*/
|
||||||
boolean isEnabled();
|
boolean isEnabled();
|
||||||
|
|
@ -59,7 +59,7 @@ public interface Binding {
|
||||||
* Sets to {@link BindingStatus#DIRTY} if succeeds.
|
* Sets to {@link BindingStatus#DIRTY} if succeeds.
|
||||||
* Sets to {@link BindingStatus#INVALID_SOURCE_VALUE} if fails.
|
* Sets to {@link BindingStatus#INVALID_SOURCE_VALUE} if fails.
|
||||||
* @param sourceValue
|
* @param sourceValue
|
||||||
* @throws IllegalStateException if {@link #isEditable()}
|
* @throws IllegalStateException if not editable or not enabled
|
||||||
*/
|
*/
|
||||||
void applySourceValue(Object sourceValue);
|
void applySourceValue(Object sourceValue);
|
||||||
|
|
||||||
|
|
@ -87,7 +87,7 @@ public interface Binding {
|
||||||
* Commit the buffered value to the model.
|
* Commit the buffered value to the model.
|
||||||
* Sets to {@link BindingStatus#COMMITTED} if succeeds.
|
* Sets to {@link BindingStatus#COMMITTED} if succeeds.
|
||||||
* Sets to {@link BindingStatus#COMMIT_FAILURE} if fails.
|
* Sets to {@link BindingStatus#COMMIT_FAILURE} if fails.
|
||||||
* @throws IllegalStateException if not {@link BindingStatus#DIRTY} or {@link #isEditable()}
|
* @throws IllegalStateException if not editable, not enabled, or not dirty
|
||||||
*/
|
*/
|
||||||
void commit();
|
void commit();
|
||||||
|
|
||||||
|
|
@ -104,10 +104,11 @@ public interface Binding {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a Binding to a nested property value.
|
* Get a Binding to a nested property value.
|
||||||
* @param nestedProperty the nested property name, such as "foo"; should not be a property path like "foo.bar"
|
* @param property the nested property name, such as "foo"; should not be a property path like "foo.bar"
|
||||||
* @return the binding to the nested property
|
* @return the binding to the nested property
|
||||||
|
* @throws IllegalStateException if not a bean
|
||||||
*/
|
*/
|
||||||
Binding getBinding(String nestedProperty);
|
Binding getBinding(String property);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If bound to an indexable Collection, either a {@link java.util.List} or an array.
|
* If bound to an indexable Collection, either a {@link java.util.List} or an array.
|
||||||
|
|
@ -118,6 +119,7 @@ public interface Binding {
|
||||||
* If a List, get a Binding to a element in the List.
|
* If a List, get a Binding to a element in the List.
|
||||||
* @param index the element index
|
* @param index the element index
|
||||||
* @return the indexed binding
|
* @return the indexed binding
|
||||||
|
* @throws IllegalStateException if not a list
|
||||||
*/
|
*/
|
||||||
Binding getListElementBinding(int index);
|
Binding getListElementBinding(int index);
|
||||||
|
|
||||||
|
|
@ -130,6 +132,7 @@ public interface Binding {
|
||||||
* If a Map, get a Binding to a value in the Map.
|
* If a Map, get a Binding to a value in the Map.
|
||||||
* @param key the map key
|
* @param key the map key
|
||||||
* @return the keyed binding
|
* @return the keyed binding
|
||||||
|
* @throws IllegalStateException if not a map
|
||||||
*/
|
*/
|
||||||
Binding getMapValueBinding(Object key);
|
Binding getMapValueBinding(Object key);
|
||||||
|
|
||||||
|
|
@ -160,7 +163,6 @@ public interface Binding {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the model value.
|
* Set the model value.
|
||||||
* @throws IllegalStateException if this binding is read only
|
|
||||||
*/
|
*/
|
||||||
void setValue(Object value);
|
void setValue(Object value);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package org.springframework.ui.binding.config;
|
|
||||||
|
|
||||||
import org.springframework.ui.format.Formatter;
|
|
||||||
|
|
||||||
public interface BindingRule {
|
|
||||||
|
|
||||||
String getPropertyPath();
|
|
||||||
|
|
||||||
Formatter<?> getFormatter();
|
|
||||||
|
|
||||||
boolean isRequired();
|
|
||||||
|
|
||||||
boolean isCollectionBinding();
|
|
||||||
|
|
||||||
Formatter<?> getKeyFormatter();
|
|
||||||
|
|
||||||
Formatter<?> getValueFormatter();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -25,27 +25,31 @@ public interface BindingRuleConfiguration {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the Formatter to use to format bound property values.
|
* Set the Formatter to use to format bound property values.
|
||||||
* If a collection property, this formatter is used to format the Collection as a String.
|
|
||||||
* Default is null.
|
|
||||||
*/
|
*/
|
||||||
BindingRuleConfiguration formatWith(Formatter<?> formatter);
|
BindingRuleConfiguration formatWith(Formatter<?> formatter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a indexable map property, set the Formatter to use to format map key indexes.
|
* If a map property, set the Formatter to use to format map keys.
|
||||||
* Default is null.
|
|
||||||
*/
|
*/
|
||||||
BindingRuleConfiguration formatKeysWith(Formatter<?> formatter);
|
BindingRuleConfiguration formatKeysWith(Formatter<?> formatter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If an indexable list or map property, set the Formatter to use to format indexed elements.
|
* If an list or map property, set the Formatter to use to format indexed elements.
|
||||||
* Default is null.
|
|
||||||
*/
|
*/
|
||||||
BindingRuleConfiguration formatElementsWith(Formatter<?> formatter);
|
BindingRuleConfiguration formatElementsWith(Formatter<?> formatter);
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark the binding as read only.
|
|
||||||
* A read-only binding cannot have source values applied and cannot be committed.
|
|
||||||
*/
|
|
||||||
BindingRuleConfiguration readOnly();
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when the binding is editable.
|
||||||
|
*/
|
||||||
|
BindingRuleConfiguration editableWhen(Condition condition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when the binding is enabled.
|
||||||
|
*/
|
||||||
|
BindingRuleConfiguration enabledWhen(Condition condition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set when the binding is visible.
|
||||||
|
*/
|
||||||
|
BindingRuleConfiguration visibleWhen(Condition condition);
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
package org.springframework.ui.binding.config;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface BindingRules extends List<BindingRule> {
|
|
||||||
|
|
||||||
Class<?> getModelType();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
package org.springframework.ui.binding.config;
|
|
||||||
|
|
||||||
import java.beans.BeanInfo;
|
|
||||||
import java.beans.IntrospectionException;
|
|
||||||
import java.beans.Introspector;
|
|
||||||
import java.beans.PropertyDescriptor;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.springframework.core.GenericCollectionTypeResolver;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builder for constructing the rules for binding to a model.
|
|
||||||
* @author Keith Donald
|
|
||||||
* @param <M> the model type
|
|
||||||
*/
|
|
||||||
public class BindingRulesBuilder {
|
|
||||||
|
|
||||||
private BindingRules bindingRules;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new BindingRuleBuilder.
|
|
||||||
* @param modelType the type of model to build binding rules against
|
|
||||||
*/
|
|
||||||
public BindingRulesBuilder(Class<?> modelType) {
|
|
||||||
Assert.notNull(modelType, "The model type is required");
|
|
||||||
bindingRules = new ArrayListBindingRules(modelType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a rule for binding to the model property.
|
|
||||||
* @param propertyPath the model property path
|
|
||||||
* @return allows additional binding configuration options to be specified fluently
|
|
||||||
* @throws IllegalArgumentException if the property path is invalid given the modelType
|
|
||||||
*/
|
|
||||||
public BindingRuleConfiguration bind(String propertyPath) {
|
|
||||||
boolean collectionBinding = validate(propertyPath);
|
|
||||||
ConfigurableBindingRule rule = new ConfigurableBindingRule(propertyPath);
|
|
||||||
if (collectionBinding) {
|
|
||||||
rule.markCollectionBinding();
|
|
||||||
}
|
|
||||||
bindingRules.add(rule);
|
|
||||||
return rule;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The built list of binding rules.
|
|
||||||
* Call after recording {@link #bind(String)} instructions.
|
|
||||||
*/
|
|
||||||
public BindingRules getBindingRules() {
|
|
||||||
return bindingRules;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean validate(String propertyPath) {
|
|
||||||
boolean collectionBinding = false;
|
|
||||||
String[] props = propertyPath.split("\\.");
|
|
||||||
if (props.length == 0) {
|
|
||||||
props = new String[] { propertyPath };
|
|
||||||
}
|
|
||||||
Class<?> modelType = bindingRules.getModelType();
|
|
||||||
for (int i = 0; i < props.length; i ++) {
|
|
||||||
String prop = props[i];
|
|
||||||
PropertyDescriptor[] propDescs = getBeanInfo(modelType).getPropertyDescriptors();
|
|
||||||
boolean found = false;
|
|
||||||
for (PropertyDescriptor propDesc : propDescs) {
|
|
||||||
if (prop.equals(propDesc.getName())) {
|
|
||||||
found = true;
|
|
||||||
Class<?> propertyType = propDesc.getPropertyType();
|
|
||||||
if (Collection.class.isAssignableFrom(propertyType)) {
|
|
||||||
modelType = GenericCollectionTypeResolver.getCollectionReturnType(propDesc.getReadMethod());
|
|
||||||
if (i == (props.length - 1)) {
|
|
||||||
collectionBinding = true;
|
|
||||||
}
|
|
||||||
} else if (Map.class.isAssignableFrom(propertyType)) {
|
|
||||||
modelType = GenericCollectionTypeResolver.getMapValueReturnType(propDesc.getReadMethod());
|
|
||||||
if (i == (props.length - 1)) {
|
|
||||||
collectionBinding = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
modelType = propertyType;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found) {
|
|
||||||
if (props.length > 1) {
|
|
||||||
throw new IllegalArgumentException("No property named '" + prop + "' found on model class [" + modelType.getName() + "] as part of property path '" + propertyPath + "'");
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException("No property named '" + prop + "' found on model class [" + modelType.getName() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return collectionBinding;
|
|
||||||
}
|
|
||||||
|
|
||||||
private BeanInfo getBeanInfo(Class<?> clazz) {
|
|
||||||
try {
|
|
||||||
return Introspector.getBeanInfo(clazz);
|
|
||||||
} catch (IntrospectionException e) {
|
|
||||||
throw new IllegalStateException("Unable to introspect model type " + clazz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
static class ArrayListBindingRules extends ArrayList<BindingRule> implements BindingRules {
|
|
||||||
|
|
||||||
private Class<?> modelType;
|
|
||||||
|
|
||||||
public ArrayListBindingRules(Class<?> modelType) {
|
|
||||||
this.modelType = modelType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<?> getModelType() {
|
|
||||||
return modelType;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package org.springframework.ui.binding.config;
|
||||||
|
|
||||||
|
public interface Condition {
|
||||||
|
|
||||||
|
boolean isTrue();
|
||||||
|
|
||||||
|
static final Condition ALWAYS_TRUE = new Condition() {
|
||||||
|
public boolean isTrue() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static final Condition ALWAYS_FALSE = new Condition() {
|
||||||
|
public boolean isTrue() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package org.springframework.ui.binding.config;
|
|
||||||
|
|
||||||
import org.springframework.ui.format.Formatter;
|
|
||||||
|
|
||||||
public class ConfigurableBindingRule implements BindingRuleConfiguration, BindingRule {
|
|
||||||
|
|
||||||
private String propertyPath;
|
|
||||||
|
|
||||||
private Formatter<?> formatter;
|
|
||||||
|
|
||||||
private boolean required;
|
|
||||||
|
|
||||||
private boolean collectionBinding;
|
|
||||||
|
|
||||||
private Formatter<?> elementFormatter;
|
|
||||||
|
|
||||||
public ConfigurableBindingRule(String propertyPath) {
|
|
||||||
this.propertyPath = propertyPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// implementing BindingRuleConfiguration
|
|
||||||
|
|
||||||
public BindingRuleConfiguration formatWith(Formatter<?> formatter) {
|
|
||||||
this.formatter = formatter;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BindingRuleConfiguration required() {
|
|
||||||
this.required = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BindingRuleConfiguration formatElementsWith(Formatter<?> formatter) {
|
|
||||||
this.elementFormatter = formatter;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// implementing BindingRule
|
|
||||||
|
|
||||||
public String getPropertyPath() {
|
|
||||||
return propertyPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Formatter<?> getFormatter() {
|
|
||||||
return formatter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRequired() {
|
|
||||||
return required;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isCollectionBinding() {
|
|
||||||
return collectionBinding;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void markCollectionBinding() {
|
|
||||||
this.collectionBinding = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Formatter<?> getValueFormatter() {
|
|
||||||
return elementFormatter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Formatter<?> getKeyFormatter() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<p>
|
||||||
|
Binding configuration SPI.
|
||||||
|
</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.springframework.ui.binding.support;
|
||||||
|
|
||||||
|
import org.springframework.ui.binding.Binding;
|
||||||
|
import org.springframework.ui.binding.config.Condition;
|
||||||
|
import org.springframework.ui.format.Formatter;
|
||||||
|
|
||||||
|
public interface BindingRule {
|
||||||
|
|
||||||
|
Formatter<?> getFormatter();
|
||||||
|
|
||||||
|
Formatter<?> getKeyFormatter();
|
||||||
|
|
||||||
|
Formatter<?> getElementFormatter();
|
||||||
|
|
||||||
|
Condition getEditableCondition();
|
||||||
|
|
||||||
|
Condition getEnabledCondition();
|
||||||
|
|
||||||
|
Condition getVisibleCondition();
|
||||||
|
|
||||||
|
// TODO - does this belong here?
|
||||||
|
Binding getBinding(String property, Object model);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -27,6 +27,8 @@ import org.springframework.ui.binding.BindingResult;
|
||||||
import org.springframework.ui.binding.BindingResults;
|
import org.springframework.ui.binding.BindingResults;
|
||||||
import org.springframework.ui.binding.Binding.BindingStatus;
|
import org.springframework.ui.binding.Binding.BindingStatus;
|
||||||
import org.springframework.ui.binding.config.BindingRuleConfiguration;
|
import org.springframework.ui.binding.config.BindingRuleConfiguration;
|
||||||
|
import org.springframework.ui.binding.config.Condition;
|
||||||
|
import org.springframework.ui.format.Formatter;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -41,8 +43,8 @@ public class GenericBinder implements Binder {
|
||||||
|
|
||||||
private Object model;
|
private Object model;
|
||||||
|
|
||||||
private Map<String, Binding> bindings;
|
private Map<String, GenericBindingRule> bindingRules;
|
||||||
|
|
||||||
private TypeConverter typeConverter;
|
private TypeConverter typeConverter;
|
||||||
|
|
||||||
private MessageSource messageSource;
|
private MessageSource messageSource;
|
||||||
|
|
@ -54,7 +56,7 @@ public class GenericBinder implements Binder {
|
||||||
public GenericBinder(Object model) {
|
public GenericBinder(Object model) {
|
||||||
Assert.notNull(model, "The model to bind to is required");
|
Assert.notNull(model, "The model to bind to is required");
|
||||||
this.model = model;
|
this.model = model;
|
||||||
bindings = new HashMap<String, Binding>();
|
bindingRules = new HashMap<String, GenericBindingRule>();
|
||||||
typeConverter = new DefaultTypeConverter();
|
typeConverter = new DefaultTypeConverter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -80,11 +82,16 @@ public class GenericBinder implements Binder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param propertyPath binding rule property path in format prop.nestedListProp[].nestedMapProp[].nestedProp
|
* @param propertyPath binding rule property path in format prop.nestedProp
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public BindingRuleConfiguration bindingRule(String propertyPath) {
|
public BindingRuleConfiguration bindingRule(String propertyPath) {
|
||||||
return null;
|
PropertyPath path = new PropertyPath(propertyPath);
|
||||||
|
GenericBindingRule rule = getBindingRule(path.getFirstElement().getValue());
|
||||||
|
for (PropertyPathElement element : path.getNestedElements()) {
|
||||||
|
rule = rule.getBindingRule(element.getValue());
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
// implementing Binder
|
// implementing Binder
|
||||||
|
|
@ -95,11 +102,7 @@ public class GenericBinder implements Binder {
|
||||||
|
|
||||||
public Binding getBinding(String property) {
|
public Binding getBinding(String property) {
|
||||||
PropertyPath path = new PropertyPath(property);
|
PropertyPath path = new PropertyPath(property);
|
||||||
Binding binding = bindings.get(path.getFirstElement().getValue());
|
Binding binding = getBindingRule(path.getFirstElement().getValue()).getBinding(model);
|
||||||
if (binding == null) {
|
|
||||||
binding = new PropertyBinding(path.getFirstElement().getValue(), model, typeConverter);
|
|
||||||
bindings.put(path.getFirstElement().getValue(), binding);
|
|
||||||
}
|
|
||||||
for (PropertyPathElement element : path.getNestedElements()) {
|
for (PropertyPathElement element : path.getNestedElements()) {
|
||||||
if (element.isIndex()) {
|
if (element.isIndex()) {
|
||||||
if (binding.isMap()) {
|
if (binding.isMap()) {
|
||||||
|
|
@ -142,11 +145,20 @@ public class GenericBinder implements Binder {
|
||||||
|
|
||||||
// internal helpers
|
// internal helpers
|
||||||
|
|
||||||
|
private GenericBindingRule getBindingRule(String property) {
|
||||||
|
GenericBindingRule rule = bindingRules.get(property);
|
||||||
|
if (rule == null) {
|
||||||
|
rule = new GenericBindingRule(property);
|
||||||
|
bindingRules.put(property, rule);
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
private BindingResult bind(Map.Entry<String, ? extends Object> sourceValue, Binding binding) {
|
private BindingResult bind(Map.Entry<String, ? extends Object> sourceValue, Binding binding) {
|
||||||
String property = sourceValue.getKey();
|
String property = sourceValue.getKey();
|
||||||
Object value = sourceValue.getValue();
|
Object value = sourceValue.getValue();
|
||||||
if (binding.isEditable()) {
|
if (!binding.isEditable()) {
|
||||||
return new PropertyNotWriteableResult(property, value, messageSource);
|
return new PropertyNotEditableResult(property, value, messageSource);
|
||||||
} else {
|
} else {
|
||||||
binding.applySourceValue(value);
|
binding.applySourceValue(value);
|
||||||
if (binding.getStatus() == BindingStatus.DIRTY) {
|
if (binding.getStatus() == BindingStatus.DIRTY) {
|
||||||
|
|
@ -156,4 +168,109 @@ public class GenericBinder implements Binder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
class GenericBindingRule implements BindingRule, BindingRuleConfiguration {
|
||||||
|
|
||||||
|
private String property;
|
||||||
|
|
||||||
|
private Formatter formatter = DefaultFormatter.INSTANCE;
|
||||||
|
|
||||||
|
private Formatter elementFormatter = DefaultFormatter.INSTANCE;
|
||||||
|
|
||||||
|
private Formatter keyFormatter = DefaultFormatter.INSTANCE;
|
||||||
|
|
||||||
|
private Condition editableCondition = Condition.ALWAYS_TRUE;
|
||||||
|
|
||||||
|
private Condition enabledCondition = Condition.ALWAYS_TRUE;
|
||||||
|
|
||||||
|
private Condition visibleCondition = Condition.ALWAYS_TRUE;
|
||||||
|
|
||||||
|
private Map<String, GenericBindingRule> nestedBindingRules;
|
||||||
|
|
||||||
|
private Binding binding;
|
||||||
|
|
||||||
|
public GenericBindingRule(String property) {
|
||||||
|
this.property = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementing BindingRule
|
||||||
|
|
||||||
|
public Binding getBinding(String property, Object model) {
|
||||||
|
return getBindingRule(property).getBinding(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Formatter<?> getFormatter() {
|
||||||
|
return formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Formatter<?> getElementFormatter() {
|
||||||
|
return elementFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Formatter<?> getKeyFormatter() {
|
||||||
|
return keyFormatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Condition getEnabledCondition() {
|
||||||
|
return enabledCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Condition getEditableCondition() {
|
||||||
|
return editableCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Condition getVisibleCondition() {
|
||||||
|
return visibleCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementing BindingRuleConfiguration
|
||||||
|
|
||||||
|
public BindingRuleConfiguration formatWith(Formatter<?> formatter) {
|
||||||
|
this.formatter = formatter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BindingRuleConfiguration formatElementsWith(Formatter<?> formatter) {
|
||||||
|
elementFormatter = formatter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BindingRuleConfiguration formatKeysWith(Formatter<?> formatter) {
|
||||||
|
keyFormatter = formatter;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BindingRuleConfiguration editableWhen(Condition condition) {
|
||||||
|
editableCondition = condition;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BindingRuleConfiguration enabledWhen(Condition condition) {
|
||||||
|
enabledCondition = condition;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BindingRuleConfiguration visibleWhen(Condition condition) {
|
||||||
|
visibleCondition = condition;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericBindingRule getBindingRule(String property) {
|
||||||
|
GenericBindingRule rule = nestedBindingRules.get(property);
|
||||||
|
if (rule == null) {
|
||||||
|
rule = new GenericBindingRule(property);
|
||||||
|
nestedBindingRules.put(property, rule);
|
||||||
|
}
|
||||||
|
return rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
Binding getBinding(Object model) {
|
||||||
|
if (binding == null) {
|
||||||
|
binding = new PropertyBinding(property, model, typeConverter, this);
|
||||||
|
}
|
||||||
|
return binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,16 +36,12 @@ public class PropertyBinding implements Binding {
|
||||||
|
|
||||||
private Object model;
|
private Object model;
|
||||||
|
|
||||||
private Formatter valueFormatter = DefaultFormatter.INSTANCE;
|
|
||||||
|
|
||||||
private Formatter mapKeyFormatter = DefaultFormatter.INSTANCE;
|
|
||||||
|
|
||||||
private Formatter indexedValueFormatter = DefaultFormatter.INSTANCE;
|
|
||||||
|
|
||||||
private PropertyDescriptor propertyDescriptor;
|
|
||||||
|
|
||||||
private TypeConverter typeConverter;
|
private TypeConverter typeConverter;
|
||||||
|
|
||||||
|
private BindingRule bindingRule;
|
||||||
|
|
||||||
|
private PropertyDescriptor propertyDescriptor;
|
||||||
|
|
||||||
private Object sourceValue;
|
private Object sourceValue;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
|
@ -55,11 +51,11 @@ public class PropertyBinding implements Binding {
|
||||||
|
|
||||||
private BindingStatus status;
|
private BindingStatus status;
|
||||||
|
|
||||||
public PropertyBinding(String property, Object model, TypeConverter typeConverter) {
|
public PropertyBinding(String property, Object model, TypeConverter typeConverter, BindingRule bindingRule) {
|
||||||
this.propertyDescriptor = findPropertyDescriptor(property, model);
|
initProperty(property, model);
|
||||||
this.property = property;
|
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.typeConverter = typeConverter;
|
this.typeConverter = typeConverter;
|
||||||
|
this.bindingRule = bindingRule;
|
||||||
this.buffer = new ValueBuffer(getModel());
|
this.buffer = new ValueBuffer(getModel());
|
||||||
status = BindingStatus.CLEAN;
|
status = BindingStatus.CLEAN;
|
||||||
}
|
}
|
||||||
|
|
@ -75,15 +71,15 @@ public class PropertyBinding implements Binding {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEditable() {
|
public boolean isEditable() {
|
||||||
return propertyDescriptor.getWriteMethod() != null || !markedNotEditable();
|
return isWriteableProperty() && bindingRule.getEditableCondition().isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnabled() {
|
public boolean isEnabled() {
|
||||||
return true;
|
return bindingRule.getEnabledCondition().isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVisible() {
|
public boolean isVisible() {
|
||||||
return true;
|
return bindingRule.getVisibleCondition().isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void applySourceValue(Object sourceValue) {
|
public void applySourceValue(Object sourceValue) {
|
||||||
|
|
@ -91,7 +87,7 @@ public class PropertyBinding implements Binding {
|
||||||
assertEnabled();
|
assertEnabled();
|
||||||
if (sourceValue instanceof String) {
|
if (sourceValue instanceof String) {
|
||||||
try {
|
try {
|
||||||
buffer.setValue(valueFormatter.parse((String) sourceValue, getLocale()));
|
buffer.setValue(bindingRule.getFormatter().parse((String) sourceValue, getLocale()));
|
||||||
sourceValue = null;
|
sourceValue = null;
|
||||||
status = BindingStatus.DIRTY;
|
status = BindingStatus.DIRTY;
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
|
|
@ -101,7 +97,7 @@ public class PropertyBinding implements Binding {
|
||||||
}
|
}
|
||||||
} else if (sourceValue instanceof String[]) {
|
} else if (sourceValue instanceof String[]) {
|
||||||
String[] sourceValues = (String[]) sourceValue;
|
String[] sourceValues = (String[]) sourceValue;
|
||||||
Class<?> parsedType = getFormattedObjectType(indexedValueFormatter.getClass());
|
Class<?> parsedType = getFormattedObjectType(bindingRule.getElementFormatter().getClass());
|
||||||
if (parsedType == null) {
|
if (parsedType == null) {
|
||||||
parsedType = String.class;
|
parsedType = String.class;
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +105,7 @@ public class PropertyBinding implements Binding {
|
||||||
for (int i = 0; i < sourceValues.length; i++) {
|
for (int i = 0; i < sourceValues.length; i++) {
|
||||||
Object parsedValue;
|
Object parsedValue;
|
||||||
try {
|
try {
|
||||||
parsedValue = indexedValueFormatter.parse(sourceValues[i], LocaleContextHolder.getLocale());
|
parsedValue = bindingRule.getElementFormatter().parse(sourceValues[i], LocaleContextHolder.getLocale());
|
||||||
Array.set(parsed, i, parsedValue);
|
Array.set(parsed, i, parsedValue);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
this.sourceValue = sourceValue;
|
this.sourceValue = sourceValue;
|
||||||
|
|
@ -242,12 +238,12 @@ public class PropertyBinding implements Binding {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public Binding getBinding(String nestedProperty) {
|
public Binding getBinding(String property) {
|
||||||
assertScalarProperty();
|
assertScalarProperty();
|
||||||
if (getValue() == null) {
|
if (getValue() == null) {
|
||||||
createValue();
|
createValue();
|
||||||
}
|
}
|
||||||
return new PropertyBinding(nestedProperty, getValue(), typeConverter);
|
return bindingRule.getBinding(property, getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isList() {
|
public boolean isList() {
|
||||||
|
|
@ -268,7 +264,7 @@ public class PropertyBinding implements Binding {
|
||||||
assertMapProperty();
|
assertMapProperty();
|
||||||
if (key instanceof String) {
|
if (key instanceof String) {
|
||||||
try {
|
try {
|
||||||
key = mapKeyFormatter.parse((String) key, getLocale());
|
key = bindingRule.getKeyFormatter().parse((String) key, getLocale());
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
throw new IllegalArgumentException("Invald key", e);
|
throw new IllegalArgumentException("Invald key", e);
|
||||||
}
|
}
|
||||||
|
|
@ -280,9 +276,9 @@ public class PropertyBinding implements Binding {
|
||||||
public String formatValue(Object value) {
|
public String formatValue(Object value) {
|
||||||
Formatter formatter;
|
Formatter formatter;
|
||||||
if (isList() || isMap()) {
|
if (isList() || isMap()) {
|
||||||
formatter = indexedValueFormatter;
|
formatter = bindingRule.getElementFormatter();
|
||||||
} else {
|
} else {
|
||||||
formatter = valueFormatter;
|
formatter = bindingRule.getFormatter();
|
||||||
}
|
}
|
||||||
Class<?> formattedType = getFormattedObjectType(formatter.getClass());
|
Class<?> formattedType = getFormattedObjectType(formatter.getClass());
|
||||||
value = typeConverter.convert(value, formattedType);
|
value = typeConverter.convert(value, formattedType);
|
||||||
|
|
@ -291,6 +287,11 @@ public class PropertyBinding implements Binding {
|
||||||
|
|
||||||
// internal helpers
|
// internal helpers
|
||||||
|
|
||||||
|
private void initProperty(String property, Object model) {
|
||||||
|
this.propertyDescriptor = findPropertyDescriptor(property, model);
|
||||||
|
this.property = property;
|
||||||
|
}
|
||||||
|
|
||||||
private PropertyDescriptor findPropertyDescriptor(String property, Object model) {
|
private PropertyDescriptor findPropertyDescriptor(String property, Object model) {
|
||||||
PropertyDescriptor[] propDescs = getBeanInfo(model.getClass()).getPropertyDescriptors();
|
PropertyDescriptor[] propDescs = getBeanInfo(model.getClass()).getPropertyDescriptors();
|
||||||
for (PropertyDescriptor propDesc : propDescs) {
|
for (PropertyDescriptor propDesc : propDescs) {
|
||||||
|
|
@ -395,7 +396,7 @@ public class PropertyBinding implements Binding {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean markedNotEditable() {
|
private boolean isWriteableProperty() {
|
||||||
return false;
|
return propertyDescriptor.getWriteMethod() != null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ import org.springframework.ui.binding.BindingResult;
|
||||||
import org.springframework.ui.message.MessageBuilder;
|
import org.springframework.ui.message.MessageBuilder;
|
||||||
import org.springframework.ui.message.ResolvableArgument;
|
import org.springframework.ui.message.ResolvableArgument;
|
||||||
|
|
||||||
class PropertyNotWriteableResult implements BindingResult {
|
class PropertyNotEditableResult implements BindingResult {
|
||||||
|
|
||||||
private String property;
|
private String property;
|
||||||
|
|
||||||
|
|
@ -19,7 +19,7 @@ class PropertyNotWriteableResult implements BindingResult {
|
||||||
|
|
||||||
private MessageSource messageSource;
|
private MessageSource messageSource;
|
||||||
|
|
||||||
public PropertyNotWriteableResult(String property, Object sourceValue, MessageSource messageSource) {
|
public PropertyNotEditableResult(String property, Object sourceValue, MessageSource messageSource) {
|
||||||
this.property = property;
|
this.property = property;
|
||||||
this.sourceValue = sourceValue;
|
this.sourceValue = sourceValue;
|
||||||
this.messageSource = messageSource;
|
this.messageSource = messageSource;
|
||||||
|
|
@ -5,10 +5,10 @@ package org.springframework.ui.binding.support;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PropertyPath implements Iterable<PropertyPathElement> {
|
||||||
public class PropertyPath {
|
|
||||||
|
|
||||||
private List<PropertyPathElement> elements = new ArrayList<PropertyPathElement>();
|
private List<PropertyPathElement> elements = new ArrayList<PropertyPathElement>();
|
||||||
|
|
||||||
|
|
@ -41,4 +41,8 @@ public class PropertyPath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Iterator<PropertyPathElement> iterator() {
|
||||||
|
return elements.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,314 +0,0 @@
|
||||||
package org.springframework.ui.binding.config;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.springframework.ui.format.Formatter;
|
|
||||||
import org.springframework.ui.format.number.CurrencyFormatter;
|
|
||||||
|
|
||||||
public class BindingRuleBuilderTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Ignore
|
|
||||||
public void createBindingRules() {
|
|
||||||
BindingRulesBuilder builder = new BindingRulesBuilder(TestBean.class);
|
|
||||||
// TODO ability to add nested rules?
|
|
||||||
// TODO ability to format map keys and values?
|
|
||||||
builder.bind("string");
|
|
||||||
builder.bind("integer").required();
|
|
||||||
builder.bind("currency").formatWith(new CurrencyFormatter()).required();
|
|
||||||
builder.bind("addresses").formatWith(new AddressListFormatter()).formatElementsWith(new AddressFormatter()).required();
|
|
||||||
builder.bind("addresses.street");
|
|
||||||
builder.bind("addresses.city");
|
|
||||||
builder.bind("addresses.state");
|
|
||||||
builder.bind("addresses.zip");
|
|
||||||
builder.bind("favoriteFoodsByGroup").formatWith(new FavoriteFoodGroupMapFormatter()).formatElementsWith(new FoodEntryFormatter());
|
|
||||||
builder.bind("favoriteFoodsByGroup.name");
|
|
||||||
List<BindingRule> rules = builder.getBindingRules();
|
|
||||||
assertEquals(10, rules.size());
|
|
||||||
assertEquals("string", rules.get(0).getPropertyPath());
|
|
||||||
assertNull(rules.get(0).getFormatter());
|
|
||||||
assertFalse(rules.get(0).isRequired());
|
|
||||||
assertFalse(rules.get(0).isCollectionBinding());
|
|
||||||
assertNull(rules.get(0).getValueFormatter());
|
|
||||||
assertEquals("integer", rules.get(1).getPropertyPath());
|
|
||||||
assertNull(rules.get(1).getFormatter());
|
|
||||||
assertTrue(rules.get(1).isRequired());
|
|
||||||
assertFalse(rules.get(1).isCollectionBinding());
|
|
||||||
assertNull(rules.get(1).getValueFormatter());
|
|
||||||
assertEquals("currency", rules.get(2).getPropertyPath());
|
|
||||||
assertTrue(rules.get(2).getFormatter() instanceof CurrencyFormatter);
|
|
||||||
assertFalse(rules.get(2).isRequired());
|
|
||||||
assertFalse(rules.get(2).isCollectionBinding());
|
|
||||||
assertNull(rules.get(2).getValueFormatter());
|
|
||||||
assertEquals("addresses", rules.get(3).getPropertyPath());
|
|
||||||
assertTrue(rules.get(3).getFormatter() instanceof AddressListFormatter);
|
|
||||||
assertFalse(rules.get(3).isRequired());
|
|
||||||
assertTrue(rules.get(3).isCollectionBinding());
|
|
||||||
assertTrue(rules.get(3).getValueFormatter() instanceof AddressFormatter);
|
|
||||||
assertTrue(rules.get(8).getFormatter() instanceof FavoriteFoodGroupMapFormatter);
|
|
||||||
assertFalse(rules.get(8).isRequired());
|
|
||||||
assertTrue(rules.get(8).isCollectionBinding());
|
|
||||||
assertTrue(rules.get(8).getValueFormatter() instanceof FoodEntryFormatter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected=IllegalArgumentException.class)
|
|
||||||
public void createBindingRulesInvalidProperty() {
|
|
||||||
BindingRulesBuilder builder = new BindingRulesBuilder(TestBean.class);
|
|
||||||
builder.bind("bogus");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected=IllegalArgumentException.class)
|
|
||||||
public void createBindingRulesInvalidNestedCollectionProperty() {
|
|
||||||
BindingRulesBuilder builder = new BindingRulesBuilder(TestBean.class);
|
|
||||||
builder.bind("addresses.bogus");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected=IllegalArgumentException.class)
|
|
||||||
public void createBindingRulesInvalidNestedMapProperty() {
|
|
||||||
BindingRulesBuilder builder = new BindingRulesBuilder(TestBean.class);
|
|
||||||
builder.bind("favoriteFoodsByGroup.bogus");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static enum FooEnum {
|
|
||||||
BAR, BAZ, BOOP;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static enum FoodGroup {
|
|
||||||
DAIRY, VEG, FRUIT, BREAD, MEAT
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TestBean {
|
|
||||||
private String string;
|
|
||||||
private int integer;
|
|
||||||
private Date date;
|
|
||||||
private FooEnum foo;
|
|
||||||
private BigDecimal currency;
|
|
||||||
private List<FooEnum> foos;
|
|
||||||
private List<Address> addresses;
|
|
||||||
private Map<FoodGroup, Food> favoriteFoodsByGroup;
|
|
||||||
private Address primaryAddress;
|
|
||||||
|
|
||||||
public TestBean() {
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 Map<FoodGroup, Food> getFavoriteFoodsByGroup() {
|
|
||||||
return favoriteFoodsByGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFavoriteFoodsByGroup(Map<FoodGroup, Food> favoriteFoodsByGroup) {
|
|
||||||
this.favoriteFoodsByGroup = favoriteFoodsByGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address getPrimaryAddress() {
|
|
||||||
return primaryAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPrimaryAddress(Address primaryAddress) {
|
|
||||||
this.primaryAddress = primaryAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Food {
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
public Food(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AddressFormatter implements Formatter<Address> {
|
|
||||||
|
|
||||||
public String format(Address address, Locale locale) {
|
|
||||||
return address.getStreet() + ":" + address.getCity() + ":" + address.getState() + ":" + address.getZip();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address parse(String formatted, Locale locale) throws ParseException {
|
|
||||||
Address address = new Address();
|
|
||||||
String[] fields = formatted.split(":");
|
|
||||||
address.setStreet(fields[0]);
|
|
||||||
address.setCity(fields[1]);
|
|
||||||
address.setState(fields[2]);
|
|
||||||
address.setZip(fields[3]);
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AddressListFormatter implements Formatter<List<Address>> {
|
|
||||||
|
|
||||||
public String format(List<Address> addresses, Locale locale) {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
for (Address address : addresses) {
|
|
||||||
builder.append(new AddressFormatter().format(address, locale));
|
|
||||||
builder.append(",");
|
|
||||||
}
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Address> parse(String formatted, Locale locale) throws ParseException {
|
|
||||||
String[] fields = formatted.split(",");
|
|
||||||
List<Address> addresses = new ArrayList<Address>(fields.length);
|
|
||||||
for (String field : fields) {
|
|
||||||
addresses.add(new AddressFormatter().parse(field, locale));
|
|
||||||
}
|
|
||||||
return addresses;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class FavoriteFoodGroupMapFormatter implements Formatter<Map<FoodGroup, Food>> {
|
|
||||||
|
|
||||||
public String format(Map<FoodGroup, Food> map, Locale locale) {
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<FoodGroup, Food> parse(String formatted, Locale locale) throws ParseException {
|
|
||||||
Map<FoodGroup, Food> map = new HashMap<FoodGroup, Food>();
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class FoodEntryFormatter implements Formatter<Map.Entry<FoodGroup, Food>> {
|
|
||||||
|
|
||||||
public String format(Map.Entry<FoodGroup, Food> food, Locale locale) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map.Entry<FoodGroup, Food> parse(String formatted, Locale locale) throws ParseException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -55,6 +55,7 @@ public class GenericBinderTests {
|
||||||
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);
|
||||||
|
System.out.println(results);
|
||||||
assertEquals(3, results.size());
|
assertEquals(3, results.size());
|
||||||
|
|
||||||
assertEquals("string", results.get(0).getProperty());
|
assertEquals("string", results.get(0).getProperty());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue