diff options
author | Teemu Suo-Anttila <teemusa@vaadin.com> | 2016-10-19 14:54:33 +0300 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2016-10-24 08:36:48 +0000 |
commit | 09485d529d085a380b347a118b54df9ae30fefd0 (patch) | |
tree | 6549d3b5fe2df51481b6fe26af78b07ae8a27b8a /server/src/main/java/com/vaadin/data | |
parent | 2cdb3b39329232dcefee2ae61ded92f2c3fe54b0 (diff) | |
download | vaadin-framework-09485d529d085a380b347a118b54df9ae30fefd0.tar.gz vaadin-framework-09485d529d085a380b347a118b54df9ae30fefd0.zip |
Initial support for null representations in Binder
Change-Id: If40bfa28764d1399b5ed4d5928988560e9989dce
Diffstat (limited to 'server/src/main/java/com/vaadin/data')
-rw-r--r-- | server/src/main/java/com/vaadin/data/BeanBinder.java | 4 | ||||
-rw-r--r-- | server/src/main/java/com/vaadin/data/Binder.java | 49 | ||||
-rw-r--r-- | server/src/main/java/com/vaadin/data/HasValue.java | 28 |
3 files changed, 70 insertions, 11 deletions
diff --git a/server/src/main/java/com/vaadin/data/BeanBinder.java b/server/src/main/java/com/vaadin/data/BeanBinder.java index d8e8c0450d..96654e37a0 100644 --- a/server/src/main/java/com/vaadin/data/BeanBinder.java +++ b/server/src/main/java/com/vaadin/data/BeanBinder.java @@ -266,8 +266,8 @@ public class BeanBinder<BEAN> extends Binder<BEAN> { @Override public <FIELDVALUE> BeanBinding<BEAN, FIELDVALUE, FIELDVALUE> forField( HasValue<FIELDVALUE> field) { - return createBinding(field, Converter.identity(), - this::handleValidationStatus); + return (BeanBinding<BEAN, FIELDVALUE, FIELDVALUE>) super.forField( + field); } /** diff --git a/server/src/main/java/com/vaadin/data/Binder.java b/server/src/main/java/com/vaadin/data/Binder.java index 1dfed366ba..8356a03dda 100644 --- a/server/src/main/java/com/vaadin/data/Binder.java +++ b/server/src/main/java/com/vaadin/data/Binder.java @@ -280,6 +280,23 @@ public class Binder<BEAN> implements Serializable { } /** + * Maps binding value {@code null} to given null representation and back + * to {@code null} when converting back to model value. + * + * @param nullRepresentation + * the value to use instead of {@code null} + * @return a new binding with null representation handling. + */ + public default Binding<BEAN, FIELDVALUE, TARGET> withNullRepresentation( + TARGET nullRepresentation) { + return withConverter( + fieldValue -> Objects.equals(fieldValue, nullRepresentation) + ? null : fieldValue, + modelValue -> Objects.isNull(modelValue) + ? nullRepresentation : modelValue); + } + + /** * Gets the field the binding uses. * * @return the field for the binding @@ -615,10 +632,6 @@ public class Binder<BEAN> implements Serializable { return validationStatus; } - private void setBeanValue(BEAN bean, TARGET value) { - setter.accept(bean, value); - } - private void notifyStatusHandler(ValidationStatus<?> status) { statusHandler.accept(status); } @@ -694,6 +707,13 @@ public class Binder<BEAN> implements Serializable { * {@link Binding#bind(Function, BiConsumer) Binding.bind} which completes * the binding. Until {@code Binding.bind} is called, the binding has no * effect. + * <p> + * <strong>Note:</strong> Not all {@link HasValue} implementations support + * passing {@code null} as the value. For these the Binder will + * automatically change {@code null} to a null representation provided by + * {@link HasValue#getEmptyValue()}. This conversion is one-way only, if you + * want to have a two-way mapping back to {@code null}, use + * {@link Binding#withNullRepresentation(Object))}. * * @param <FIELDVALUE> * the value type of the field @@ -710,7 +730,10 @@ public class Binder<BEAN> implements Serializable { clearError(field); getStatusLabel().ifPresent(label -> label.setValue("")); - return createBinding(field, Converter.identity(), + return createBinding(field, Converter.from(fieldValue -> fieldValue, + modelValue -> Objects.isNull(modelValue) ? field.getEmptyValue() + : modelValue, + exception -> exception.getMessage()), this::handleValidationStatus); } @@ -722,6 +745,14 @@ public class Binder<BEAN> implements Serializable { * Use the {@link #forField(HasValue)} overload instead if you want to * further configure the new binding. * <p> + * <strong>Note:</strong> Not all {@link HasValue} implementations support + * passing {@code null} as the value. For these the Binder will + * automatically change {@code null} to a null representation provided by + * {@link HasValue#getEmptyValue()}. This conversion is one-way only, if you + * want to have a two-way mapping back to {@code null}, use + * {@link #forField(HasValue)} and + * {@link Binding#withNullRepresentation(Object))}. + * <p> * When a bean is bound with {@link Binder#bind(BEAN)}, the field value is * set to the return value of the given getter. The property value is then * updated via the given setter whenever the field value changes. The setter @@ -905,8 +936,8 @@ public class Binder<BEAN> implements Serializable { // Save old bean values so we can restore them if validators fail Map<Binding<BEAN, ?, ?>, Object> oldValues = new HashMap<>(); - bindings.forEach(binding -> oldValues.put(binding, - binding.convertDataToFieldType(bean))); + bindings.forEach( + binding -> oldValues.put(binding, binding.getter.apply(bean))); bindings.forEach(binding -> binding.storeFieldValue(bean)); // Now run bean level validation against the updated bean @@ -915,8 +946,8 @@ public class Binder<BEAN> implements Serializable { .findAny().isPresent(); if (hasErrors) { // Bean validator failed, revert values - bindings.forEach((BindingImpl binding) -> binding.setBeanValue(bean, - oldValues.get(binding))); + bindings.forEach((BindingImpl binding) -> binding.setter + .accept(bean, oldValues.get(binding))); } else { // Save successful, reset hasChanges to false setHasChanges(false); diff --git a/server/src/main/java/com/vaadin/data/HasValue.java b/server/src/main/java/com/vaadin/data/HasValue.java index 89d8d69e66..0ad3203b78 100644 --- a/server/src/main/java/com/vaadin/data/HasValue.java +++ b/server/src/main/java/com/vaadin/data/HasValue.java @@ -17,6 +17,9 @@ package com.vaadin.data; import java.io.Serializable; import java.lang.reflect.Method; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.function.Function; import com.vaadin.event.ConnectorEvent; import com.vaadin.event.EventListener; @@ -170,4 +173,29 @@ public interface HasValue<V> extends Serializable { */ public Registration addValueChangeListener( ValueChangeListener<? super V> listener); + + /** + * Returns the value that represents an empty value. + * <p> + * By default {@link HasValue} is expected to support {@code null} as empty + * values. Specific implementations might not support this. + * + * @return empty value + * @see Binder#bind(HasValue, Function, BiConsumer) + */ + public default V getEmptyValue() { + return null; + } + + /** + * Returns whether this {@code HasValue} is considered to be empty. + * <p> + * By default this is an equality check between current value and empty + * value. + * + * @return {@code true} if considered empty; {@code false} if not + */ + public default boolean isEmpty() { + return Objects.equals(getValue(), getEmptyValue()); + } } |