more passing tests
This commit is contained in:
parent
f39f91701d
commit
2da1bb8607
|
|
@ -29,10 +29,19 @@ public interface Binding {
|
||||||
* The value to display in the UI.
|
* The value to display in the UI.
|
||||||
* Is the formatted model value if {@link BindingStatus#CLEAN} or {@link BindingStatus#COMMITTED}.
|
* Is the formatted model value if {@link BindingStatus#CLEAN} or {@link BindingStatus#COMMITTED}.
|
||||||
* Is the formatted buffered value if {@link BindingStatus#DIRTY} or {@link BindingStatus#COMMIT_FAILURE}.
|
* Is the formatted buffered value if {@link BindingStatus#DIRTY} or {@link BindingStatus#COMMIT_FAILURE}.
|
||||||
* Is the source value if {@link BindingStatus#INVALID_SOURCE_VALUE}.
|
*/
|
||||||
|
String getRenderValue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bound model value.
|
||||||
*/
|
*/
|
||||||
Object getValue();
|
Object getValue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bound model value type.
|
||||||
|
*/
|
||||||
|
Class<?> getValueType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this Binding is editable.
|
* If this Binding is editable.
|
||||||
* Used to determine if the user can edit the field value.
|
* Used to determine if the user can edit the field value.
|
||||||
|
|
@ -63,6 +72,13 @@ public interface Binding {
|
||||||
*/
|
*/
|
||||||
void applySourceValue(Object sourceValue);
|
void applySourceValue(Object sourceValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If {@link BindingStatus#INVALID_SOURCE_VALUE}, returns the invalid source value.
|
||||||
|
* Returns null otherwise.
|
||||||
|
* @return the invalid source value
|
||||||
|
*/
|
||||||
|
Object getInvalidSourceValue();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current binding status.
|
* The current binding status.
|
||||||
* Initially {@link BindingStatus#CLEAN clean}.
|
* Initially {@link BindingStatus#CLEAN clean}.
|
||||||
|
|
@ -96,12 +112,29 @@ public interface Binding {
|
||||||
* @throws IllegalStateException if BindingStatus is CLEAN or COMMITTED.
|
* @throws IllegalStateException if BindingStatus is CLEAN or COMMITTED.
|
||||||
*/
|
*/
|
||||||
void revert();
|
void revert();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access raw model values.
|
* For accessing the raw bound model object.
|
||||||
|
* @author Keith Donald
|
||||||
*/
|
*/
|
||||||
Model getModel();
|
public interface Model {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The model value.
|
||||||
|
*/
|
||||||
|
Object getValue();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The model value type.
|
||||||
|
*/
|
||||||
|
Class<?> getValueType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the model value.
|
||||||
|
*/
|
||||||
|
void setValue(Object value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a Binding to a nested property value.
|
* Get a Binding to a nested property value.
|
||||||
* @param property 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"
|
||||||
|
|
@ -145,28 +178,6 @@ public interface Binding {
|
||||||
*/
|
*/
|
||||||
String formatValue(Object potentialModelValue);
|
String formatValue(Object potentialModelValue);
|
||||||
|
|
||||||
/**
|
|
||||||
* For accessing the raw bound model object.
|
|
||||||
* @author Keith Donald
|
|
||||||
*/
|
|
||||||
public interface Model {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The model value.
|
|
||||||
*/
|
|
||||||
Object getValue();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The model value type.
|
|
||||||
*/
|
|
||||||
Class<?> getValueType();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the model value.
|
|
||||||
*/
|
|
||||||
void setValue(Object value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binding states.
|
* Binding states.
|
||||||
* @author Keith Donald
|
* @author Keith Donald
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,52 @@
|
||||||
*/
|
*/
|
||||||
package org.springframework.ui.binding.support;
|
package org.springframework.ui.binding.support;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.springframework.ui.format.Formatter;
|
import org.springframework.ui.format.Formatter;
|
||||||
|
|
||||||
class DefaultFormatter implements Formatter<Object> {
|
@SuppressWarnings("unchecked")
|
||||||
|
class DefaultFormatter implements Formatter {
|
||||||
|
|
||||||
public static final Formatter<Object> INSTANCE = new DefaultFormatter();
|
public static final Formatter INSTANCE = new DefaultFormatter();
|
||||||
|
|
||||||
|
public static final Formatter COLLECTION_FORMATTER = new Formatter() {
|
||||||
|
public String format(Object object, Locale locale) {
|
||||||
|
if (object == null) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
if (object.getClass().isArray()) {
|
||||||
|
int length = Array.getLength(object);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
buffer.append(INSTANCE.format(Array.get(object, i), locale));
|
||||||
|
if (i < length - 1) {
|
||||||
|
buffer.append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (Collection.class.isAssignableFrom(object.getClass())) {
|
||||||
|
Collection c = (Collection) object;
|
||||||
|
for (Iterator it = c.iterator(); it.hasNext();) {
|
||||||
|
buffer.append(INSTANCE.format(it.next(), locale));
|
||||||
|
if (it.hasNext()) {
|
||||||
|
buffer.append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object parse(String formatted, Locale locale) throws ParseException {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
public String format(Object object, Locale locale) {
|
public String format(Object object, Locale locale) {
|
||||||
if (object == null) {
|
if (object == null) {
|
||||||
return "";
|
return "";
|
||||||
|
|
|
||||||
|
|
@ -300,11 +300,17 @@ public class GenericBinder implements Binder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public BindingRuleConfiguration formatElementsWith(Formatter<?> formatter) {
|
public BindingRuleConfiguration formatElementsWith(Formatter<?> formatter) {
|
||||||
|
if (!List.class.isAssignableFrom(modelClass) || modelClass.isArray()) {
|
||||||
|
throw new IllegalStateException("Bound property is not a List or an array; cannot set a element formatter");
|
||||||
|
}
|
||||||
elementFormatter = formatter;
|
elementFormatter = formatter;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BindingRuleConfiguration formatKeysWith(Formatter<?> formatter) {
|
public BindingRuleConfiguration formatKeysWith(Formatter<?> formatter) {
|
||||||
|
if (!Map.class.isAssignableFrom(modelClass)) {
|
||||||
|
throw new IllegalStateException("Bound property is not a Map; cannot set a key formatter");
|
||||||
|
}
|
||||||
keyFormatter = formatter;
|
keyFormatter = formatter;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,12 +59,12 @@ public class GenericFormatterRegistry implements FormatterRegistry {
|
||||||
}
|
}
|
||||||
Formatter<?> formatter = null;
|
Formatter<?> formatter = null;
|
||||||
Class<?> type;
|
Class<?> type;
|
||||||
if (propertyType.isCollection()) {
|
if (propertyType.isCollection() || propertyType.isArray()) {
|
||||||
formatter = collectionTypeFormatters.get(new GenericCollectionPropertyType(propertyType.getType(), propertyType.getElementType()));
|
formatter = collectionTypeFormatters.get(new GenericCollectionPropertyType(propertyType.getType(), propertyType.getElementType()));
|
||||||
if (formatter != null) {
|
if (formatter != null) {
|
||||||
return formatter;
|
return formatter;
|
||||||
} else {
|
} else {
|
||||||
type = propertyType.getElementType();
|
return DefaultFormatter.COLLECTION_FORMATTER;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
type = propertyType.getType();
|
type = propertyType.getType();
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,14 @@ import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.convert.ConversionFailedException;
|
import org.springframework.core.convert.ConversionFailedException;
|
||||||
import org.springframework.core.convert.TypeConverter;
|
import org.springframework.core.convert.TypeConverter;
|
||||||
import org.springframework.core.convert.TypeDescriptor;
|
import org.springframework.core.convert.TypeDescriptor;
|
||||||
|
import org.springframework.core.style.StylerUtils;
|
||||||
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.binding.support.GenericBinder.BindingContext;
|
||||||
import org.springframework.ui.format.Formatter;
|
import org.springframework.ui.format.Formatter;
|
||||||
|
import org.springframework.ui.message.MessageBuilder;
|
||||||
|
import org.springframework.ui.message.ResolvableArgument;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
@ -38,8 +41,7 @@ public class PropertyBinding implements Binding {
|
||||||
|
|
||||||
private Object sourceValue;
|
private Object sourceValue;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
private Exception invalidSourceValueCause;
|
||||||
private ParseException sourceValueParseException;
|
|
||||||
|
|
||||||
private ValueBuffer buffer;
|
private ValueBuffer buffer;
|
||||||
|
|
||||||
|
|
@ -49,20 +51,26 @@ public class PropertyBinding implements Binding {
|
||||||
this.property = property;
|
this.property = property;
|
||||||
this.object = object;
|
this.object = object;
|
||||||
this.bindingContext = bindingContext;
|
this.bindingContext = bindingContext;
|
||||||
this.buffer = new ValueBuffer(getModel());
|
buffer = new ValueBuffer(getModel());
|
||||||
status = BindingStatus.CLEAN;
|
status = BindingStatus.CLEAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRenderValue() {
|
||||||
|
return format(getValue(), bindingContext.getFormatter());
|
||||||
|
}
|
||||||
|
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
if (status == BindingStatus.INVALID_SOURCE_VALUE) {
|
if (status == BindingStatus.DIRTY || status == BindingStatus.COMMIT_FAILURE) {
|
||||||
return sourceValue;
|
return buffer.getValue();
|
||||||
} else if (status == BindingStatus.DIRTY || status == BindingStatus.COMMIT_FAILURE) {
|
|
||||||
return formatValue(buffer.getValue());
|
|
||||||
} else {
|
} else {
|
||||||
return formatValue(getModel().getValue());
|
return getModel().getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class<?> getValueType() {
|
||||||
|
return getModel().getValueType();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isEditable() {
|
public boolean isEditable() {
|
||||||
return isWriteableProperty() && bindingContext.getEditableCondition().isTrue();
|
return isWriteableProperty() && bindingContext.getEditableCondition().isTrue();
|
||||||
}
|
}
|
||||||
|
|
@ -80,12 +88,17 @@ public class PropertyBinding implements Binding {
|
||||||
assertEnabled();
|
assertEnabled();
|
||||||
if (sourceValue instanceof String) {
|
if (sourceValue instanceof String) {
|
||||||
try {
|
try {
|
||||||
buffer.setValue(bindingContext.getFormatter().parse((String) sourceValue, getLocale()));
|
Object parsed = bindingContext.getFormatter().parse((String) sourceValue, getLocale());
|
||||||
|
buffer.setValue(coerseToValueType(parsed));
|
||||||
sourceValue = null;
|
sourceValue = null;
|
||||||
status = BindingStatus.DIRTY;
|
status = BindingStatus.DIRTY;
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
this.sourceValue = sourceValue;
|
this.sourceValue = sourceValue;
|
||||||
sourceValueParseException = e;
|
invalidSourceValueCause = e;
|
||||||
|
status = BindingStatus.INVALID_SOURCE_VALUE;
|
||||||
|
} catch (ConversionFailedException e) {
|
||||||
|
this.sourceValue = sourceValue;
|
||||||
|
invalidSourceValueCause = e;
|
||||||
status = BindingStatus.INVALID_SOURCE_VALUE;
|
status = BindingStatus.INVALID_SOURCE_VALUE;
|
||||||
}
|
}
|
||||||
} else if (sourceValue instanceof String[]) {
|
} else if (sourceValue instanceof String[]) {
|
||||||
|
|
@ -98,24 +111,36 @@ 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 = bindingContext.getElementFormatter().parse(sourceValues[i],
|
parsedValue = bindingContext.getElementFormatter().parse(sourceValues[i], getLocale());
|
||||||
LocaleContextHolder.getLocale());
|
|
||||||
Array.set(parsed, i, parsedValue);
|
Array.set(parsed, i, parsedValue);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
this.sourceValue = sourceValue;
|
this.sourceValue = sourceValue;
|
||||||
sourceValueParseException = e;
|
invalidSourceValueCause = e;
|
||||||
status = BindingStatus.INVALID_SOURCE_VALUE;
|
status = BindingStatus.INVALID_SOURCE_VALUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (status != BindingStatus.INVALID_SOURCE_VALUE) {
|
if (status != BindingStatus.INVALID_SOURCE_VALUE) {
|
||||||
buffer.setValue(parsed);
|
try {
|
||||||
|
buffer.setValue(coerseToValueType(parsed));
|
||||||
|
} catch (ConversionFailedException e) {
|
||||||
|
this.sourceValue = sourceValue;
|
||||||
|
invalidSourceValueCause = e;
|
||||||
|
status = BindingStatus.INVALID_SOURCE_VALUE;
|
||||||
|
}
|
||||||
sourceValue = null;
|
sourceValue = null;
|
||||||
status = BindingStatus.DIRTY;
|
status = BindingStatus.DIRTY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object getInvalidSourceValue() {
|
||||||
|
if (status != BindingStatus.INVALID_SOURCE_VALUE) {
|
||||||
|
throw new IllegalStateException("No invalid source value");
|
||||||
|
}
|
||||||
|
return sourceValue;
|
||||||
|
}
|
||||||
|
|
||||||
public BindingStatus getStatus() {
|
public BindingStatus getStatus() {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
@ -128,7 +153,25 @@ public class PropertyBinding implements Binding {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return "Could not parse source value";
|
MessageBuilder builder = new MessageBuilder(bindingContext.getMessageSource());
|
||||||
|
builder.code(getCode());
|
||||||
|
if (invalidSourceValueCause instanceof ParseException) {
|
||||||
|
ParseException e = (ParseException) invalidSourceValueCause;
|
||||||
|
builder.arg("label", new ResolvableArgument(property.getName()));
|
||||||
|
builder.arg("value", sourceValue);
|
||||||
|
builder.arg("errorOffset", e.getErrorOffset());
|
||||||
|
builder.defaultMessage("Failed to bind to property '" + property + "'; the user value "
|
||||||
|
+ StylerUtils.style(sourceValue) + " has an invalid format and could no be parsed");
|
||||||
|
} else {
|
||||||
|
ConversionFailedException e = (ConversionFailedException) invalidSourceValueCause;
|
||||||
|
builder.arg("label", new ResolvableArgument(property.getName()));
|
||||||
|
builder.arg("value", sourceValue);
|
||||||
|
builder.defaultMessage("Failed to bind to property '" + property + "'; the user value "
|
||||||
|
+ StylerUtils.style(sourceValue) + " has could not be converted to "
|
||||||
|
+ e.getTargetType().getName());
|
||||||
|
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Severity getSeverity() {
|
public Severity getSeverity() {
|
||||||
|
|
@ -136,35 +179,19 @@ public class PropertyBinding implements Binding {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
} else if (status == BindingStatus.COMMIT_FAILURE) {
|
} else if (status == BindingStatus.COMMIT_FAILURE) {
|
||||||
if (buffer.getFlushException() instanceof ConversionFailedException) {
|
|
||||||
return new AbstractAlert() {
|
|
||||||
public String getCode() {
|
|
||||||
return "typeMismatch";
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return "Could not convert source value";
|
|
||||||
}
|
|
||||||
|
|
||||||
public Severity getSeverity() {
|
|
||||||
return Severity.ERROR;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return new AbstractAlert() {
|
return new AbstractAlert() {
|
||||||
public String getCode() {
|
public String getCode() {
|
||||||
return "internalError";
|
return "internalError";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return "Internal error occurred " + buffer.getFlushException();
|
return "Internal error occurred; message = [" + buffer.getFlushException().getMessage() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public Severity getSeverity() {
|
public Severity getSeverity() {
|
||||||
return Severity.FATAL;
|
return Severity.FATAL;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
} else if (status == BindingStatus.COMMITTED) {
|
} else if (status == BindingStatus.COMMITTED) {
|
||||||
return new AbstractAlert() {
|
return new AbstractAlert() {
|
||||||
public String getCode() {
|
public String getCode() {
|
||||||
|
|
@ -202,7 +229,7 @@ public class PropertyBinding implements Binding {
|
||||||
public void revert() {
|
public void revert() {
|
||||||
if (status == BindingStatus.INVALID_SOURCE_VALUE) {
|
if (status == BindingStatus.INVALID_SOURCE_VALUE) {
|
||||||
sourceValue = null;
|
sourceValue = null;
|
||||||
sourceValueParseException = null;
|
invalidSourceValueCause = null;
|
||||||
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();
|
||||||
|
|
@ -223,11 +250,6 @@ public class PropertyBinding implements Binding {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValue(Object value) {
|
public void setValue(Object value) {
|
||||||
TypeDescriptor targetType = new TypeDescriptor(new MethodParameter(property.getWriteMethod(), 0));
|
|
||||||
TypeConverter converter = bindingContext.getTypeConverter();
|
|
||||||
if (value != null && converter.canConvert(value.getClass(), targetType)) {
|
|
||||||
value = converter.convert(value, targetType);
|
|
||||||
}
|
|
||||||
ReflectionUtils.invokeMethod(property.getWriteMethod(), object, value);
|
ReflectionUtils.invokeMethod(property.getWriteMethod(), object, value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -275,6 +297,10 @@ public class PropertyBinding implements Binding {
|
||||||
} else {
|
} else {
|
||||||
formatter = bindingContext.getFormatter();
|
formatter = bindingContext.getFormatter();
|
||||||
}
|
}
|
||||||
|
return format(value, formatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String format(Object value, Formatter formatter) {
|
||||||
Class<?> formattedType = getFormattedObjectType(formatter.getClass());
|
Class<?> formattedType = getFormattedObjectType(formatter.getClass());
|
||||||
value = bindingContext.getTypeConverter().convert(value, formattedType);
|
value = bindingContext.getTypeConverter().convert(value, formattedType);
|
||||||
return formatter.format(value, getLocale());
|
return formatter.format(value, getLocale());
|
||||||
|
|
@ -327,6 +353,16 @@ public class PropertyBinding implements Binding {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Object coerseToValueType(Object parsed) {
|
||||||
|
TypeDescriptor targetType = new TypeDescriptor(new MethodParameter(property.getWriteMethod(), 0));
|
||||||
|
TypeConverter converter = bindingContext.getTypeConverter();
|
||||||
|
if (parsed != null && converter.canConvert(parsed.getClass(), targetType)) {
|
||||||
|
return converter.convert(parsed, targetType);
|
||||||
|
} else {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
private CollectionTypeDescriptor getCollectionTypeDescriptor() {
|
private CollectionTypeDescriptor getCollectionTypeDescriptor() {
|
||||||
Class<?> elementType = GenericCollectionTypeResolver.getCollectionReturnType(property.getReadMethod());
|
Class<?> elementType = GenericCollectionTypeResolver.getCollectionReturnType(property.getReadMethod());
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import static org.junit.Assert.assertTrue;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
|
@ -17,13 +16,12 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
import org.springframework.context.i18n.LocaleContextHolder;
|
||||||
import org.springframework.ui.binding.Binding;
|
import org.springframework.ui.binding.Binding;
|
||||||
import org.springframework.ui.binding.BindingResult;
|
|
||||||
import org.springframework.ui.binding.BindingResults;
|
import org.springframework.ui.binding.BindingResults;
|
||||||
import org.springframework.ui.binding.MissingSourceValuesException;
|
import org.springframework.ui.binding.MissingSourceValuesException;
|
||||||
|
import org.springframework.ui.binding.Binding.BindingStatus;
|
||||||
import org.springframework.ui.format.AnnotationFormatterFactory;
|
import org.springframework.ui.format.AnnotationFormatterFactory;
|
||||||
import org.springframework.ui.format.Formatted;
|
import org.springframework.ui.format.Formatted;
|
||||||
import org.springframework.ui.format.Formatter;
|
import org.springframework.ui.format.Formatter;
|
||||||
|
|
@ -32,7 +30,6 @@ import org.springframework.ui.format.number.CurrencyFormat;
|
||||||
import org.springframework.ui.format.number.CurrencyFormatter;
|
import org.springframework.ui.format.number.CurrencyFormatter;
|
||||||
import org.springframework.ui.format.number.IntegerFormatter;
|
import org.springframework.ui.format.number.IntegerFormatter;
|
||||||
import org.springframework.ui.message.MockMessageSource;
|
import org.springframework.ui.message.MockMessageSource;
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
public class GenericBinderTests {
|
public class GenericBinderTests {
|
||||||
|
|
||||||
|
|
@ -154,56 +151,66 @@ public class GenericBinderTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBindingCustomFormatter() {
|
public void getBindingCustomFormatter() {
|
||||||
|
binder.bindingRule("currency").formatWith(new CurrencyFormatter());
|
||||||
Binding b = binder.getBinding("currency");
|
Binding b = binder.getBinding("currency");
|
||||||
assertFalse(b.isList());
|
assertFalse(b.isList());
|
||||||
assertFalse(b.isMap());
|
assertFalse(b.isMap());
|
||||||
assertEquals("", b.getValue());
|
assertEquals(null, b.getValue());
|
||||||
|
assertEquals("", b.getRenderValue());
|
||||||
b.applySourceValue("$23.56");
|
b.applySourceValue("$23.56");
|
||||||
assertEquals("$23.56", b.getValue());
|
assertEquals(BindingStatus.DIRTY, b.getStatus());
|
||||||
|
assertEquals(new BigDecimal("23.56"), b.getValue());
|
||||||
|
assertEquals("$23.56", b.getRenderValue());
|
||||||
b.commit();
|
b.commit();
|
||||||
assertEquals("$23.56", b.getValue());
|
assertEquals(new BigDecimal("23.56"), b.getValue());
|
||||||
|
assertEquals("$23.56", b.getRenderValue());
|
||||||
|
assertEquals(BindingStatus.COMMITTED, b.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
@Test
|
@Test
|
||||||
public void getBindingCustomFormatterRequiringTypeCoersion() {
|
public void getBindingCustomFormatterRequiringTypeCoersion() {
|
||||||
// IntegerFormatter formats Longs, so conversion from Integer -> Long is performed
|
// IntegerFormatter formats Longs, so conversion from Integer -> Long is performed
|
||||||
binder.addBinding("integer").formatWith(new IntegerFormatter());
|
binder.bindingRule("integer").formatWith(new IntegerFormatter());
|
||||||
Binding b = binder.getBinding("integer");
|
Binding b = binder.getBinding("integer");
|
||||||
b.setValue("2,300");
|
b.applySourceValue("2,300");
|
||||||
assertEquals("2,300", b.getValue());
|
assertEquals("2,300", b.getRenderValue());
|
||||||
|
b.commit();
|
||||||
|
assertEquals(BindingStatus.COMMITTED, b.getStatus());
|
||||||
|
assertEquals("2,300", b.getRenderValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void invalidFormatBindingResultCustomAlertMessage() {
|
public void invalidFormatBindingResultCustomAlertMessage() {
|
||||||
MockMessageSource messages = new MockMessageSource();
|
MockMessageSource messages = new MockMessageSource();
|
||||||
messages.addMessage("invalidFormat", Locale.US,
|
messages.addMessage("typeMismatch", Locale.US,
|
||||||
"Please enter an integer in format ### for the #{label} field; you entered #{value}");
|
"Please enter an integer in format ### for the #{label} field; you entered #{value}");
|
||||||
binder.setMessageSource(messages);
|
binder.setMessageSource(messages);
|
||||||
binder.addBinding("integer").formatWith(new IntegerFormatter());
|
binder.bindingRule("integer").formatWith(new IntegerFormatter());
|
||||||
Binding b = binder.getBinding("integer");
|
Binding b = binder.getBinding("integer");
|
||||||
BindingResult result = b.setValue("bogus");
|
b.applySourceValue("bogus");
|
||||||
assertEquals("Please enter an integer in format ### for the integer field; you entered bogus", result
|
assertEquals("Please enter an integer in format ### for the integer field; you entered bogus", b.getStatusAlert().getMessage());
|
||||||
.getAlert().getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getBindingMultiValued() {
|
public void getBindingMultiValued() {
|
||||||
binder.addBinding("foos");
|
|
||||||
Binding b = binder.getBinding("foos");
|
Binding b = binder.getBinding("foos");
|
||||||
assertTrue(b.isIndexable());
|
assertTrue(b.isList());
|
||||||
assertEquals(0, b.getCollectionValues().length);
|
assertEquals(null, b.getValue());
|
||||||
b.setValue(new String[] { "BAR", "BAZ", "BOOP" });
|
assertEquals("", b.getRenderValue());
|
||||||
|
b.applySourceValue(new String[] { "BAR", "BAZ", "BOOP" });
|
||||||
|
b.commit();
|
||||||
assertEquals(FooEnum.BAR, bean.getFoos().get(0));
|
assertEquals(FooEnum.BAR, bean.getFoos().get(0));
|
||||||
assertEquals(FooEnum.BAZ, bean.getFoos().get(1));
|
assertEquals(FooEnum.BAZ, bean.getFoos().get(1));
|
||||||
assertEquals(FooEnum.BOOP, bean.getFoos().get(2));
|
assertEquals(FooEnum.BOOP, bean.getFoos().get(2));
|
||||||
String[] values = b.getCollectionValues();
|
String asString = b.getRenderValue();
|
||||||
assertEquals(3, values.length);
|
assertEquals("BAR,BAZ,BOOP", asString);
|
||||||
assertEquals("BAR", values[0]);
|
List<FooEnum> value = (List<FooEnum>) b.getValue();
|
||||||
assertEquals("BAZ", values[1]);
|
assertEquals(FooEnum.BAR, value.get(0));
|
||||||
assertEquals("BOOP", values[2]);
|
assertEquals(FooEnum.BAZ, value.get(1));
|
||||||
|
assertEquals(FooEnum.BOOP, value.get(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
@Test
|
@Test
|
||||||
public void getBindingMultiValuedIndexAccess() {
|
public void getBindingMultiValuedIndexAccess() {
|
||||||
binder.addBinding("foos");
|
binder.addBinding("foos");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue