提交 3cd3cddb 编写于 作者: K Keith Donald

type formatters

上级 b2c723a7
package org.springframework.ui.binding.support; package org.springframework.ui.binding.support;
import org.springframework.ui.binding.Binding;
import org.springframework.ui.binding.config.Condition; import org.springframework.ui.binding.config.Condition;
import org.springframework.ui.format.Formatter; import org.springframework.ui.format.Formatter;
...@@ -17,8 +16,5 @@ public interface BindingRule { ...@@ -17,8 +16,5 @@ public interface BindingRule {
Condition getEnabledCondition(); Condition getEnabledCondition();
Condition getVisibleCondition(); Condition getVisibleCondition();
// TODO - does this belong here?
Binding getBinding(String property, Object model);
} }
\ No newline at end of file
...@@ -37,4 +37,8 @@ class BindingStatusResult implements BindingResult { ...@@ -37,4 +37,8 @@ class BindingStatusResult implements BindingResult {
return bindingStatusAlert; return bindingStatusAlert;
} }
public String toString() {
return getAlert().toString();
}
} }
\ No newline at end of file
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
*/ */
package org.springframework.ui.binding.support; package org.springframework.ui.binding.support;
import org.springframework.core.convert.TypeDescriptor; import java.beans.PropertyDescriptor;
import org.springframework.ui.format.AnnotationFormatterFactory; import org.springframework.ui.format.AnnotationFormatterFactory;
import org.springframework.ui.format.Formatter; import org.springframework.ui.format.Formatter;
...@@ -28,13 +29,14 @@ import org.springframework.ui.format.Formatter; ...@@ -28,13 +29,14 @@ import org.springframework.ui.format.Formatter;
*/ */
public interface FormatterRegistry { public interface FormatterRegistry {
Formatter<?> getFormatter(PropertyDescriptor property);
/** /**
* Get the Formatter for the property type. * Get the Formatter for the type.
* @param propertyType the property type descriptor, which provides additional property metadata.
* @return the Formatter, or <code>null</code> if none is registered * @return the Formatter, or <code>null</code> if none is registered
*/ */
Formatter<?> getFormatter(TypeDescriptor<?> propertyType); Formatter<?> getFormatter(Class<?> type);
/** /**
* Adds a Formatter that will format the values of properties of the provided type. * Adds a Formatter that will format the values of properties of the provided type.
* The type should generally be a concrete class for a scalar value, such as BigDecimal, and not a collection value. * The type should generally be a concrete class for a scalar value, such as BigDecimal, and not a collection value.
......
...@@ -15,11 +15,17 @@ ...@@ -15,11 +15,17 @@
*/ */
package org.springframework.ui.binding.support; package org.springframework.ui.binding.support;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.springframework.context.MessageSource; import org.springframework.context.MessageSource;
import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.convert.TypeConverter; import org.springframework.core.convert.TypeConverter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.DefaultTypeConverter; import org.springframework.core.convert.support.DefaultTypeConverter;
import org.springframework.ui.binding.Binder; import org.springframework.ui.binding.Binder;
import org.springframework.ui.binding.Binding; import org.springframework.ui.binding.Binding;
...@@ -45,6 +51,8 @@ public class GenericBinder implements Binder { ...@@ -45,6 +51,8 @@ public class GenericBinder implements Binder {
private Map<String, GenericBindingRule> bindingRules; private Map<String, GenericBindingRule> bindingRules;
private FormatterRegistry formatterRegistry;
private TypeConverter typeConverter; private TypeConverter typeConverter;
private MessageSource messageSource; private MessageSource messageSource;
...@@ -57,9 +65,20 @@ public class GenericBinder implements Binder { ...@@ -57,9 +65,20 @@ public class GenericBinder implements Binder {
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;
bindingRules = new HashMap<String, GenericBindingRule>(); bindingRules = new HashMap<String, GenericBindingRule>();
formatterRegistry = new GenericFormatterRegistry();
typeConverter = new DefaultTypeConverter(); typeConverter = new DefaultTypeConverter();
} }
/**
* Configures the registry of Formatters to query when no explicit Formatter has been registered for a Binding.
* Allows Formatters to be applied by property type and by property annotation.
* @param registry the formatter registry
*/
public void setFormatterRegistry(FormatterRegistry formatterRegistry) {
Assert.notNull(formatterRegistry, "The FormatterRegistry is required");
this.formatterRegistry = formatterRegistry;
}
/** /**
* Configure the MessageSource that resolves localized {@link BindingResult} alert messages. * Configure the MessageSource that resolves localized {@link BindingResult} alert messages.
* @param messageSource the message source * @param messageSource the message source
...@@ -148,7 +167,7 @@ public class GenericBinder implements Binder { ...@@ -148,7 +167,7 @@ public class GenericBinder implements Binder {
private GenericBindingRule getBindingRule(String property) { private GenericBindingRule getBindingRule(String property) {
GenericBindingRule rule = bindingRules.get(property); GenericBindingRule rule = bindingRules.get(property);
if (rule == null) { if (rule == null) {
rule = new GenericBindingRule(property); rule = new GenericBindingRule(property, model.getClass());
bindingRules.put(property, rule); bindingRules.put(property, rule);
} }
return rule; return rule;
...@@ -169,15 +188,17 @@ public class GenericBinder implements Binder { ...@@ -169,15 +188,17 @@ public class GenericBinder implements Binder {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
class GenericBindingRule implements BindingRule, BindingRuleConfiguration { class GenericBindingRule implements BindingRuleConfiguration, BindingContext {
private String property; private Class<?> modelClass;
private PropertyDescriptor property;
private Formatter formatter = DefaultFormatter.INSTANCE; private Formatter formatter;
private Formatter elementFormatter = DefaultFormatter.INSTANCE; private Formatter elementFormatter;
private Formatter keyFormatter = DefaultFormatter.INSTANCE; private Formatter keyFormatter;
private Condition editableCondition = Condition.ALWAYS_TRUE; private Condition editableCondition = Condition.ALWAYS_TRUE;
...@@ -189,26 +210,39 @@ public class GenericBinder implements Binder { ...@@ -189,26 +210,39 @@ public class GenericBinder implements Binder {
private Binding binding; private Binding binding;
public GenericBindingRule(String property) { public GenericBindingRule(String property, Class modelClass) {
this.property = property; this.modelClass = modelClass;
this.property = findPropertyDescriptor(property);
} }
// implementing BindingRule // implementing BindingContext
public Binding getBinding(String property, Object model) {
return getBindingRule(property).getBinding(model);
}
public TypeConverter getTypeConverter() {
return typeConverter;
}
public Formatter<?> getFormatter() { public Formatter<?> getFormatter() {
return formatter; if (formatter != null) {
return formatter;
} else {
return formatterRegistry.getFormatter(property);
}
} }
public Formatter<?> getElementFormatter() { public Formatter<?> getElementFormatter() {
return elementFormatter; if (elementFormatter != null) {
return formatter;
} else {
return formatterRegistry.getFormatter(getElementType());
}
} }
public Formatter<?> getKeyFormatter() { public Formatter<?> getKeyFormatter() {
return keyFormatter; if (keyFormatter != null) {
return keyFormatter;
} else {
return formatterRegistry.getFormatter(getKeyType());
}
} }
public Condition getEnabledCondition() { public Condition getEnabledCondition() {
...@@ -223,8 +257,12 @@ public class GenericBinder implements Binder { ...@@ -223,8 +257,12 @@ public class GenericBinder implements Binder {
return visibleCondition; return visibleCondition;
} }
public Binding getBinding(String property, Object model) {
return getBindingRule(property).getBinding(model);
}
// implementing BindingRuleConfiguration // implementing BindingRuleConfiguration
public BindingRuleConfiguration formatWith(Formatter<?> formatter) { public BindingRuleConfiguration formatWith(Formatter<?> formatter) {
this.formatter = formatter; this.formatter = formatter;
return this; return this;
...@@ -255,10 +293,20 @@ public class GenericBinder implements Binder { ...@@ -255,10 +293,20 @@ public class GenericBinder implements Binder {
return this; return this;
} }
// internal helpers
private Class<?> getElementType() {
return GenericCollectionTypeResolver.getCollectionReturnType(property.getReadMethod());
}
private Class<?> getKeyType() {
return GenericCollectionTypeResolver.getMapKeyReturnType(property.getReadMethod());
}
GenericBindingRule getBindingRule(String property) { GenericBindingRule getBindingRule(String property) {
GenericBindingRule rule = nestedBindingRules.get(property); GenericBindingRule rule = nestedBindingRules.get(property);
if (rule == null) { if (rule == null) {
rule = new GenericBindingRule(property); rule = new GenericBindingRule(property, this.property.getPropertyType());
nestedBindingRules.put(property, rule); nestedBindingRules.put(property, rule);
} }
return rule; return rule;
...@@ -266,11 +314,52 @@ public class GenericBinder implements Binder { ...@@ -266,11 +314,52 @@ public class GenericBinder implements Binder {
Binding getBinding(Object model) { Binding getBinding(Object model) {
if (binding == null) { if (binding == null) {
binding = new PropertyBinding(property, model, typeConverter, this); binding = new PropertyBinding(property, model, this);
} }
return binding; return binding;
} }
private PropertyDescriptor findPropertyDescriptor(String property) {
PropertyDescriptor[] propDescs = getBeanInfo(modelClass).getPropertyDescriptors();
for (PropertyDescriptor propDesc : propDescs) {
if (propDesc.getName().equals(property)) {
return propDesc;
}
}
throw new IllegalArgumentException("No property '" + property + "' found on model ["
+ modelClass.getName() + "]");
}
private BeanInfo getBeanInfo(Class<?> clazz) {
try {
return Introspector.getBeanInfo(clazz);
} catch (IntrospectionException e) {
throw new IllegalStateException("Unable to introspect model type " + clazz);
}
}
}
public interface BindingContext {
TypeConverter getTypeConverter();
Condition getEditableCondition();
Condition getEnabledCondition();
Condition getVisibleCondition();
Binding getBinding(String property, Object model);
@SuppressWarnings("unchecked")
Formatter getFormatter();
@SuppressWarnings("unchecked")
Formatter getElementFormatter();
@SuppressWarnings("unchecked")
Formatter getKeyFormatter();
} }
} }
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
package org.springframework.ui.binding.support; package org.springframework.ui.binding.support;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
...@@ -24,6 +25,7 @@ import java.util.Map; ...@@ -24,6 +25,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.springframework.core.GenericTypeResolver; import org.springframework.core.GenericTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.ui.format.AnnotationFormatterFactory; import org.springframework.ui.format.AnnotationFormatterFactory;
...@@ -46,7 +48,8 @@ public class GenericFormatterRegistry implements FormatterRegistry { ...@@ -46,7 +48,8 @@ public class GenericFormatterRegistry implements FormatterRegistry {
private Map<Class, AnnotationFormatterFactory> annotationFormatters = new HashMap<Class, AnnotationFormatterFactory>(); private Map<Class, AnnotationFormatterFactory> annotationFormatters = new HashMap<Class, AnnotationFormatterFactory>();
public Formatter<?> getFormatter(TypeDescriptor<?> propertyType) { public Formatter<?> getFormatter(PropertyDescriptor property) {
TypeDescriptor<?> propertyType = new TypeDescriptor(new MethodParameter(property.getReadMethod(), -1));
Annotation[] annotations = propertyType.getAnnotations(); Annotation[] annotations = propertyType.getAnnotations();
for (Annotation a : annotations) { for (Annotation a : annotations) {
AnnotationFormatterFactory factory = annotationFormatters.get(a.annotationType()); AnnotationFormatterFactory factory = annotationFormatters.get(a.annotationType());
...@@ -66,7 +69,11 @@ public class GenericFormatterRegistry implements FormatterRegistry { ...@@ -66,7 +69,11 @@ public class GenericFormatterRegistry implements FormatterRegistry {
} else { } else {
type = propertyType.getType(); type = propertyType.getType();
} }
formatter = typeFormatters.get(type); return getFormatter(type);
}
public Formatter<?> getFormatter(Class<?> type) {
Formatter formatter = typeFormatters.get(type);
if (formatter != null) { if (formatter != null) {
return formatter; return formatter;
} else { } else {
...@@ -84,11 +91,12 @@ public class GenericFormatterRegistry implements FormatterRegistry { ...@@ -84,11 +91,12 @@ public class GenericFormatterRegistry implements FormatterRegistry {
typeFormatters.put(type, formatter); typeFormatters.put(type, formatter);
return formatter; return formatter;
} else { } else {
return null; return DefaultFormatter.INSTANCE;
} }
} }
} }
public void add(Class<?> propertyType, Formatter<?> formatter) { public void add(Class<?> propertyType, Formatter<?> formatter) {
if (propertyType.isAnnotation()) { if (propertyType.isAnnotation()) {
annotationFormatters.put(propertyType, new SimpleAnnotationFormatterFactory(formatter)); annotationFormatters.put(propertyType, new SimpleAnnotationFormatterFactory(formatter));
......
...@@ -3,9 +3,6 @@ ...@@ -3,9 +3,6 @@
*/ */
package org.springframework.ui.binding.support; package org.springframework.ui.binding.support;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
...@@ -26,36 +23,32 @@ import org.springframework.core.convert.TypeDescriptor; ...@@ -26,36 +23,32 @@ import org.springframework.core.convert.TypeDescriptor;
import org.springframework.ui.alert.Alert; import org.springframework.ui.alert.Alert;
import org.springframework.ui.alert.Severity; import org.springframework.ui.alert.Severity;
import org.springframework.ui.binding.Binding; import org.springframework.ui.binding.Binding;
import org.springframework.ui.binding.support.GenericBinder.BindingContext;
import org.springframework.ui.format.Formatter; import org.springframework.ui.format.Formatter;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class PropertyBinding implements Binding { public class PropertyBinding implements Binding {
private String property; private PropertyDescriptor property;
private Object model; private Object object;
private TypeConverter typeConverter; private BindingContext bindingContext;
private BindingRule bindingRule;
private PropertyDescriptor propertyDescriptor;
private Object sourceValue; private Object sourceValue;
@SuppressWarnings("unused") @SuppressWarnings("unused")
private ParseException sourceValueParseException; private ParseException sourceValueParseException;
private ValueBuffer buffer; private ValueBuffer buffer;
private BindingStatus status; private BindingStatus status;
public PropertyBinding(String property, Object model, TypeConverter typeConverter, BindingRule bindingRule) { public PropertyBinding(PropertyDescriptor property, Object object, BindingContext bindingContext) {
initProperty(property, model); this.property = property;
this.model = model; this.object = object;
this.typeConverter = typeConverter; this.bindingContext = bindingContext;
this.bindingRule = bindingRule;
this.buffer = new ValueBuffer(getModel()); this.buffer = new ValueBuffer(getModel());
status = BindingStatus.CLEAN; status = BindingStatus.CLEAN;
} }
...@@ -71,23 +64,23 @@ public class PropertyBinding implements Binding { ...@@ -71,23 +64,23 @@ public class PropertyBinding implements Binding {
} }
public boolean isEditable() { public boolean isEditable() {
return isWriteableProperty() && bindingRule.getEditableCondition().isTrue(); return isWriteableProperty() && bindingContext.getEditableCondition().isTrue();
} }
public boolean isEnabled() { public boolean isEnabled() {
return bindingRule.getEnabledCondition().isTrue(); return bindingContext.getEnabledCondition().isTrue();
} }
public boolean isVisible() { public boolean isVisible() {
return bindingRule.getVisibleCondition().isTrue(); return bindingContext.getVisibleCondition().isTrue();
} }
public void applySourceValue(Object sourceValue) { public void applySourceValue(Object sourceValue) {
assertEditable(); assertEditable();
assertEnabled(); assertEnabled();
if (sourceValue instanceof String) { if (sourceValue instanceof String) {
try { try {
buffer.setValue(bindingRule.getFormatter().parse((String) sourceValue, getLocale())); buffer.setValue(bindingContext.getFormatter().parse((String) sourceValue, getLocale()));
sourceValue = null; sourceValue = null;
status = BindingStatus.DIRTY; status = BindingStatus.DIRTY;
} catch (ParseException e) { } catch (ParseException e) {
...@@ -97,7 +90,7 @@ public class PropertyBinding implements Binding { ...@@ -97,7 +90,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(bindingRule.getElementFormatter().getClass()); Class<?> parsedType = getFormattedObjectType(bindingContext.getElementFormatter().getClass());
if (parsedType == null) { if (parsedType == null) {
parsedType = String.class; parsedType = String.class;
} }
...@@ -105,7 +98,8 @@ public class PropertyBinding implements Binding { ...@@ -105,7 +98,8 @@ 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 = bindingRule.getElementFormatter().parse(sourceValues[i], LocaleContextHolder.getLocale()); parsedValue = bindingContext.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;
...@@ -121,14 +115,14 @@ public class PropertyBinding implements Binding { ...@@ -121,14 +115,14 @@ public class PropertyBinding implements Binding {
} }
} }
} }
public BindingStatus getStatus() { public BindingStatus getStatus() {
return status; return status;
} }
public Alert getStatusAlert() { public Alert getStatusAlert() {
if (status == BindingStatus.INVALID_SOURCE_VALUE) { if (status == BindingStatus.INVALID_SOURCE_VALUE) {
return new Alert() { return new AbstractAlert() {
public String getCode() { public String getCode() {
return "typeMismatch"; return "typeMismatch";
} }
...@@ -139,11 +133,11 @@ public class PropertyBinding implements Binding { ...@@ -139,11 +133,11 @@ public class PropertyBinding implements Binding {
public Severity getSeverity() { public Severity getSeverity() {
return Severity.ERROR; return Severity.ERROR;
} }
}; };
} else if (status == BindingStatus.COMMIT_FAILURE) { } else if (status == BindingStatus.COMMIT_FAILURE) {
if (buffer.getFlushException() instanceof ConversionFailedException) { if (buffer.getFlushException() instanceof ConversionFailedException) {
return new Alert() { return new AbstractAlert() {
public String getCode() { public String getCode() {
return "typeMismatch"; return "typeMismatch";
} }
...@@ -154,25 +148,25 @@ public class PropertyBinding implements Binding { ...@@ -154,25 +148,25 @@ public class PropertyBinding implements Binding {
public Severity getSeverity() { public Severity getSeverity() {
return Severity.ERROR; return Severity.ERROR;
} }
}; };
} else { } else {
return new Alert() { return new AbstractAlert() {
public String getCode() { public String getCode() {
return "internalError"; return "internalError";
} }
public String getMessage() { public String getMessage() {
return "Internal error occurred"; return "Internal error occurred " + buffer.getFlushException();
} }
public Severity getSeverity() { public Severity getSeverity() {
return Severity.FATAL; return Severity.FATAL;
} }
}; };
} }
} else if (status == BindingStatus.COMMITTED) { } else if (status == BindingStatus.COMMITTED) {
return new Alert() { return new AbstractAlert() {
public String getCode() { public String getCode() {
return "bindSucces"; return "bindSucces";
} }
...@@ -183,8 +177,8 @@ public class PropertyBinding implements Binding { ...@@ -183,8 +177,8 @@ public class PropertyBinding implements Binding {
public Severity getSeverity() { public Severity getSeverity() {
return Severity.INFO; return Severity.INFO;
} }
}; };
} else { } else {
return null; return null;
} }
...@@ -204,7 +198,7 @@ public class PropertyBinding implements Binding { ...@@ -204,7 +198,7 @@ public class PropertyBinding implements Binding {
throw new IllegalStateException("Binding is not dirty; nothing to commit"); throw new IllegalStateException("Binding is not dirty; nothing to commit");
} }
} }
public void revert() { public void revert() {
if (status == BindingStatus.INVALID_SOURCE_VALUE) { if (status == BindingStatus.INVALID_SOURCE_VALUE) {
sourceValue = null; sourceValue = null;
...@@ -212,28 +206,29 @@ public class PropertyBinding implements Binding { ...@@ -212,28 +206,29 @@ public class PropertyBinding implements Binding {
status = BindingStatus.CLEAN; status = BindingStatus.CLEAN;
} else if (status == BindingStatus.DIRTY || status == BindingStatus.COMMIT_FAILURE) { } else if (status == BindingStatus.DIRTY || status == BindingStatus.COMMIT_FAILURE) {
buffer.clear(); buffer.clear();
status = BindingStatus.CLEAN; status = BindingStatus.CLEAN;
} else { } else {
throw new IllegalStateException("Nothing to revert"); throw new IllegalStateException("Nothing to revert");
} }
} }
public Model getModel() { public Model getModel() {
return new Model() { return new Model() {
public Object getValue() { public Object getValue() {
return ReflectionUtils.invokeMethod(propertyDescriptor.getReadMethod(), model); return ReflectionUtils.invokeMethod(property.getReadMethod(), object);
} }
public Class<?> getValueType() { public Class<?> getValueType() {
return propertyDescriptor.getPropertyType(); return property.getPropertyType();
} }
public void setValue(Object value) { public void setValue(Object value) {
TypeDescriptor targetType = new TypeDescriptor(new MethodParameter(propertyDescriptor.getWriteMethod(), 0)); TypeDescriptor targetType = new TypeDescriptor(new MethodParameter(property.getWriteMethod(), 0));
if (value != null && typeConverter.canConvert(value.getClass(), targetType)) { TypeConverter converter = bindingContext.getTypeConverter();
value = typeConverter.convert(value, targetType); if (value != null && converter.canConvert(value.getClass(), targetType)) {
value = converter.convert(value, targetType);
} }
ReflectionUtils.invokeMethod(propertyDescriptor.getWriteMethod(), model, value); ReflectionUtils.invokeMethod(property.getWriteMethod(), object, value);
} }
}; };
} }
...@@ -243,7 +238,7 @@ public class PropertyBinding implements Binding { ...@@ -243,7 +238,7 @@ public class PropertyBinding implements Binding {
if (getValue() == null) { if (getValue() == null) {
createValue(); createValue();
} }
return bindingRule.getBinding(property, getValue()); return bindingContext.getBinding(property, getValue());
} }
public boolean isList() { public boolean isList() {
...@@ -264,7 +259,7 @@ public class PropertyBinding implements Binding { ...@@ -264,7 +259,7 @@ public class PropertyBinding implements Binding {
assertMapProperty(); assertMapProperty();
if (key instanceof String) { if (key instanceof String) {
try { try {
key = bindingRule.getKeyFormatter().parse((String) key, getLocale()); key = bindingContext.getKeyFormatter().parse((String) key, getLocale());
} catch (ParseException e) { } catch (ParseException e) {
throw new IllegalArgumentException("Invald key", e); throw new IllegalArgumentException("Invald key", e);
} }
...@@ -276,41 +271,17 @@ public class PropertyBinding implements Binding { ...@@ -276,41 +271,17 @@ 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 = bindingRule.getElementFormatter(); formatter = bindingContext.getElementFormatter();
} else { } else {
formatter = bindingRule.getFormatter(); formatter = bindingContext.getFormatter();
} }
Class<?> formattedType = getFormattedObjectType(formatter.getClass()); Class<?> formattedType = getFormattedObjectType(formatter.getClass());
value = typeConverter.convert(value, formattedType); value = bindingContext.getTypeConverter().convert(value, formattedType);
return formatter.format(value, getLocale()); return formatter.format(value, getLocale());
} }
// 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) {
PropertyDescriptor[] propDescs = getBeanInfo(model.getClass()).getPropertyDescriptors();
for (PropertyDescriptor propDesc : propDescs) {
if (propDesc.getName().equals(property)) {
return propDesc;
}
}
throw new IllegalArgumentException("No property '" + property + "' found on model ["
+ model.getClass().getName() + "]");
}
private BeanInfo getBeanInfo(Class<?> clazz) {
try {
return Introspector.getBeanInfo(clazz);
} catch (IntrospectionException e) {
throw new IllegalStateException("Unable to introspect model type " + clazz);
}
}
private Locale getLocale() { private Locale getLocale() {
return LocaleContextHolder.getLocale(); return LocaleContextHolder.getLocale();
} }
...@@ -320,11 +291,11 @@ public class PropertyBinding implements Binding { ...@@ -320,11 +291,11 @@ public class PropertyBinding implements Binding {
Object value = getModel().getValueType().newInstance(); Object value = getModel().getValueType().newInstance();
getModel().setValue(value); getModel().setValue(value);
} catch (InstantiationException e) { } catch (InstantiationException e) {
throw new IllegalStateException("Could not lazily instantiate model of type [" + getModel().getValueType().getName() throw new IllegalStateException("Could not lazily instantiate object of type ["
+ "] to access property" + property, e); + getModel().getValueType().getName() + "] to access property" + property, e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new IllegalStateException("Could not lazily instantiate model of type [" + getModel().getValueType().getName() throw new IllegalStateException("Could not lazily instantiate object of type ["
+ "] to access property" + property, e); + getModel().getValueType().getName() + "] to access property" + property, e);
} }
} }
...@@ -358,8 +329,7 @@ public class PropertyBinding implements Binding { ...@@ -358,8 +329,7 @@ public class PropertyBinding implements Binding {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private CollectionTypeDescriptor getCollectionTypeDescriptor() { private CollectionTypeDescriptor getCollectionTypeDescriptor() {
Class<?> elementType = GenericCollectionTypeResolver.getCollectionReturnType(propertyDescriptor Class<?> elementType = GenericCollectionTypeResolver.getCollectionReturnType(property.getReadMethod());
.getReadMethod());
return new CollectionTypeDescriptor(getModel().getValueType(), elementType); return new CollectionTypeDescriptor(getModel().getValueType(), elementType);
} }
...@@ -383,7 +353,7 @@ public class PropertyBinding implements Binding { ...@@ -383,7 +353,7 @@ public class PropertyBinding implements Binding {
throw new IllegalStateException("Not a Map property binding"); throw new IllegalStateException("Not a Map property binding");
} }
} }
private void assertEditable() { private void assertEditable() {
if (!isEditable()) { if (!isEditable()) {
throw new IllegalStateException("Binding is not editable"); throw new IllegalStateException("Binding is not editable");
...@@ -397,6 +367,13 @@ public class PropertyBinding implements Binding { ...@@ -397,6 +367,13 @@ public class PropertyBinding implements Binding {
} }
private boolean isWriteableProperty() { private boolean isWriteableProperty() {
return propertyDescriptor.getWriteMethod() != null; return property.getWriteMethod() != null;
} }
static abstract class AbstractAlert implements Alert {
public String toString() {
return getCode() + " - " + getMessage();
}
}
} }
\ No newline at end of file
...@@ -97,32 +97,29 @@ public class GenericBinderTests { ...@@ -97,32 +97,29 @@ public class GenericBinderTests {
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() {
BindingRulesBuilder builder = new BindingRulesBuilder(TestBean.class); GenericBinder binder = new GenericBinder(bean);
builder.bind("date").formatWith(new DateFormatter()); binder.bindingRule("date").formatWith(new DateFormatter());
GenericBinder binder = new GenericBinder(bean, builder.getBindingRules());
BindingResults results = binder.bind(Collections.singletonMap("date", "bogus")); BindingResults results = binder.bind(Collections.singletonMap("date", "bogus"));
assertEquals(1, results.size()); assertEquals(1, results.size());
assertTrue(results.get(0).isFailure()); assertTrue(results.get(0).isFailure());
assertEquals("invalidFormat", results.get(0).getAlert().getCode()); assertEquals("typeMismatch", results.get(0).getAlert().getCode());
} }
@Test @Test
public void bindSingleValueWithFormatterRegistedByType() throws ParseException { public void bindSingleValueWithFormatterRegistedByType() throws ParseException {
BindingRulesBuilder builder = new BindingRulesBuilder(TestBean.class); GenericBinder binder = new GenericBinder(bean);
builder.bind("date").formatWith(new DateFormatter());
GenericBinder binder = new GenericBinder(bean, builder.getBindingRules());
GenericFormatterRegistry formatterRegistry = new GenericFormatterRegistry(); GenericFormatterRegistry formatterRegistry = new GenericFormatterRegistry();
formatterRegistry.add(Date.class, new DateFormatter()); formatterRegistry.add(Date.class, new DateFormatter());
binder.setFormatterRegistry(formatterRegistry);
binder.bind(Collections.singletonMap("date", "2009-06-01")); binder.bind(Collections.singletonMap("date", "2009-06-01"));
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 bindSingleValueWithAnnotationFormatterFactoryRegistered() throws ParseException { public void bindSingleValueWithAnnotationFormatterFactoryRegistered() throws ParseException {
binder.addBinding("currency"); binder.addBinding("currency");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册