提交 603ffe80 编写于 作者: K Keith Donald

list element binding

上级 2da1bb86
......@@ -15,6 +15,7 @@
*/
package org.springframework.ui.binding;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.ui.alert.Alert;
import org.springframework.ui.alert.Severity;
......@@ -26,7 +27,7 @@ import org.springframework.ui.alert.Severity;
public interface Binding {
/**
* The value to display in the UI.
* The model value formatted for display in a single field in the UI.
* 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}.
*/
......@@ -129,6 +130,11 @@ public interface Binding {
*/
Class<?> getValueType();
/**
* The model value type descriptor.
*/
TypeDescriptor<?> getValueTypeDescriptor();
/**
* Set the model value.
*/
......
......@@ -9,6 +9,7 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
......@@ -47,16 +48,24 @@ public class PropertyBinding implements Binding {
private BindingStatus status;
private Map<Integer, ListElementBinding> listElementBindings;
private Class<?> elementType;
public PropertyBinding(PropertyDescriptor property, Object object, BindingContext bindingContext) {
this.property = property;
this.object = object;
this.bindingContext = bindingContext;
buffer = new ValueBuffer(getModel());
status = BindingStatus.CLEAN;
if (isList()) {
listElementBindings = new HashMap<Integer, ListElementBinding>();
elementType = GenericCollectionTypeResolver.getCollectionReturnType(property.getReadMethod());
}
}
public String getRenderValue() {
return format(getValue(), bindingContext.getFormatter());
return format(getValue(), getFormatter());
}
public Object getValue() {
......@@ -88,7 +97,7 @@ public class PropertyBinding implements Binding {
assertEnabled();
if (sourceValue instanceof String) {
try {
Object parsed = bindingContext.getFormatter().parse((String) sourceValue, getLocale());
Object parsed = getFormatter().parse((String) sourceValue, getLocale());
buffer.setValue(coerseToValueType(parsed));
sourceValue = null;
status = BindingStatus.DIRTY;
......@@ -123,13 +132,23 @@ public class PropertyBinding implements Binding {
if (status != BindingStatus.INVALID_SOURCE_VALUE) {
try {
buffer.setValue(coerseToValueType(parsed));
sourceValue = null;
status = BindingStatus.DIRTY;
} catch (ConversionFailedException e) {
this.sourceValue = sourceValue;
invalidSourceValueCause = e;
status = BindingStatus.INVALID_SOURCE_VALUE;
}
}
} else {
try {
buffer.setValue(coerseToValueType(sourceValue));
sourceValue = null;
status = BindingStatus.DIRTY;
} catch (ConversionFailedException e) {
this.sourceValue = sourceValue;
invalidSourceValueCause = e;
status = BindingStatus.INVALID_SOURCE_VALUE;
}
}
}
......@@ -179,19 +198,19 @@ public class PropertyBinding implements Binding {
}
};
} else if (status == BindingStatus.COMMIT_FAILURE) {
return new AbstractAlert() {
public String getCode() {
return "internalError";
}
return new AbstractAlert() {
public String getCode() {
return "internalError";
}
public String getMessage() {
return "Internal error occurred; message = [" + buffer.getFlushException().getMessage() + "]";
}
public String getMessage() {
return "Internal error occurred; message = [" + buffer.getFlushException().getMessage() + "]";
}
public Severity getSeverity() {
return Severity.FATAL;
}
};
public Severity getSeverity() {
return Severity.FATAL;
}
};
} else if (status == BindingStatus.COMMITTED) {
return new AbstractAlert() {
public String getCode() {
......@@ -248,6 +267,10 @@ public class PropertyBinding implements Binding {
public Class<?> getValueType() {
return property.getPropertyType();
}
public TypeDescriptor<?> getValueTypeDescriptor() {
return new TypeDescriptor(new MethodParameter(property.getReadMethod(), -1));
}
public void setValue(Object value) {
ReflectionUtils.invokeMethod(property.getWriteMethod(), object, value);
......@@ -264,17 +287,21 @@ public class PropertyBinding implements Binding {
}
public boolean isList() {
return getModel().getValueType().isArray() || List.class.isAssignableFrom(getModel().getValueType());
return List.class.isAssignableFrom(getValueType());
}
public Binding getListElementBinding(int index) {
assertListProperty();
//return new IndexedBinding(index, (List) getValue(), getCollectionTypeDescriptor(), typeConverter);
return null;
ListElementBinding binding = listElementBindings.get(index);
if (binding == null) {
binding = new ListElementBinding(index);
listElementBindings.put(index, binding);
}
return binding;
}
public boolean isMap() {
return Map.class.isAssignableFrom(getModel().getValueType());
return Map.class.isAssignableFrom(getValueType());
}
public Binding getMapValueBinding(Object key) {
......@@ -299,7 +326,7 @@ public class PropertyBinding implements Binding {
}
return format(value, formatter);
}
private String format(Object value, Formatter formatter) {
Class<?> formattedType = getFormattedObjectType(formatter.getClass());
value = bindingContext.getTypeConverter().convert(value, formattedType);
......@@ -308,6 +335,10 @@ public class PropertyBinding implements Binding {
// internal helpers
protected Formatter getFormatter() {
return bindingContext.getFormatter();
}
private Locale getLocale() {
return LocaleContextHolder.getLocale();
}
......@@ -354,7 +385,7 @@ public class PropertyBinding implements Binding {
}
private Object coerseToValueType(Object parsed) {
TypeDescriptor targetType = new TypeDescriptor(new MethodParameter(property.getWriteMethod(), 0));
TypeDescriptor targetType = getModel().getValueTypeDescriptor();
TypeConverter converter = bindingContext.getTypeConverter();
if (parsed != null && converter.canConvert(parsed.getClass(), targetType)) {
return converter.convert(parsed, targetType);
......@@ -363,12 +394,6 @@ public class PropertyBinding implements Binding {
}
}
@SuppressWarnings("unused")
private CollectionTypeDescriptor getCollectionTypeDescriptor() {
Class<?> elementType = GenericCollectionTypeResolver.getCollectionReturnType(property.getReadMethod());
return new CollectionTypeDescriptor(getModel().getValueType(), elementType);
}
private void assertScalarProperty() {
if (isList()) {
throw new IllegalArgumentException("Is a Collection but should be a scalar");
......@@ -411,5 +436,72 @@ public class PropertyBinding implements Binding {
return getCode() + " - " + getMessage();
}
}
class ListElementBinding extends PropertyBinding {
private int index;
public ListElementBinding(int index) {
super(property, object, bindingContext);
this.index = index;
growListIfNecessary();
}
protected Formatter getFormatter() {
return bindingContext.getElementFormatter();
}
public Model getModel() {
return new Model() {
public Object getValue() {
return getList().get(index);
}
public Class<?> getValueType() {
if (elementType != null) {
return elementType;
} else {
return getValue().getClass();
}
}
public TypeDescriptor<?> getValueTypeDescriptor() {
return TypeDescriptor.valueOf(getValueType());
}
public void setValue(Object value) {
getList().set(index, value);
}
};
}
// internal helpers
private void growListIfNecessary() {
if (index >= getList().size()) {
for (int i = getList().size(); i <= index; i++) {
addValue();
}
}
}
private List getList() {
return (List) PropertyBinding.this.getValue();
}
private void addValue() {
try {
Object value = getValueType().newInstance();
getList().add(value);
} catch (InstantiationException e) {
throw new IllegalStateException("Could not lazily instantiate model of type ["
+ getValueType().getName() + "] to grow List", e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Could not lazily instantiate model of type ["
+ getValueType().getName() + "] to grow List", e);
}
}
}
}
\ No newline at end of file
......@@ -19,9 +19,11 @@ public class PropertyPath implements Iterable<PropertyPathElement> {
props = new String[] { propertyPath };
}
for (String prop : props) {
if (prop.startsWith("[")) {
int end = prop.indexOf(']');
String index = prop.substring(0, end);
if (prop.contains("[")) {
int start = prop.indexOf('[');
int end = prop.indexOf(']', start);
String index = prop.substring(start + 1, end);
elements.add(new PropertyPathElement(prop.substring(0, start), true));
elements.add(new PropertyPathElement(index, true));
} else {
elements.add(new PropertyPathElement(prop, false));
......@@ -35,7 +37,7 @@ public class PropertyPath implements Iterable<PropertyPathElement> {
public List<PropertyPathElement> getNestedElements() {
if (elements.size() > 1) {
return elements.subList(1, elements.size() - 1);
return elements.subList(1, elements.size());
} else {
return Collections.emptyList();
}
......
......@@ -7,6 +7,7 @@ import static org.junit.Assert.assertTrue;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
......@@ -210,18 +211,19 @@ public class GenericBinderTests {
assertEquals(FooEnum.BOOP, value.get(2));
}
/*
@Test
public void getBindingMultiValuedIndexAccess() {
binder.addBinding("foos");
bean.setFoos(Arrays.asList(new FooEnum[] { FooEnum.BAR }));
Binding b = binder.getBinding("foos[0]");
assertFalse(b.isIndexable());
assertEquals("BAR", b.getValue());
b.setValue("BAZ");
assertEquals("BAZ", b.getValue());
assertFalse(b.isList());
assertEquals(FooEnum.BAR, b.getValue());
assertEquals("BAR", b.getRenderValue());
b.applySourceValue("BAZ");
assertEquals("BAZ", b.getRenderValue());
assertEquals(FooEnum.BAZ, b.getValue());
}
/*
@Test
public void getBindingMultiValuedTypeConversionFailure() {
binder.addBinding("foos");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册