]> source.dussan.org Git - vaadin-framework.git/commitdiff
Separate Binding and BindingBuilder (#80)
authorLeif Åstrand <legioth@gmail.com>
Mon, 5 Dec 2016 11:15:08 +0000 (13:15 +0200)
committerPekka Hyvönen <pekka@vaadin.com>
Mon, 5 Dec 2016 11:15:08 +0000 (13:15 +0200)
BindingBinder is API that is used before calling bind()

Binding is API that is used after calling bind()

14 files changed:
server/src/main/java/com/vaadin/data/BeanBinder.java
server/src/main/java/com/vaadin/data/Binder.java
server/src/main/java/com/vaadin/data/BinderValidationStatus.java
server/src/main/java/com/vaadin/data/StatusChangeEvent.java
server/src/main/java/com/vaadin/data/ValidationStatus.java
server/src/main/java/com/vaadin/data/ValidationStatusHandler.java
server/src/main/java/com/vaadin/data/util/converter/Converter.java
server/src/test/java/com/vaadin/data/BeanBinderTest.java
server/src/test/java/com/vaadin/data/BinderBookOfVaadinTest.java
server/src/test/java/com/vaadin/data/BinderConverterValidatorTest.java
server/src/test/java/com/vaadin/data/BinderStatusChangeTest.java
server/src/test/java/com/vaadin/data/BinderTest.java
server/src/test/java/com/vaadin/data/BinderValidationStatusTest.java
server/src/test/java/com/vaadin/data/validator/NotEmptyValidator.java

index 068b681d9c641b432e5e925eebdc85403792c425..22761c2cd7d4918738893093a5b451d3ac5594cb 100644 (file)
@@ -66,74 +66,76 @@ public class BeanBinder<BEAN> extends Binder<BEAN> {
      * @param <TARGET>
      *            the target property type
      */
-    public interface BeanBinding<BEAN, TARGET> extends Binding<BEAN, TARGET> {
+    public interface BeanBindingBuilder<BEAN, TARGET>
+            extends BindingBuilder<BEAN, TARGET> {
 
         @Override
-        public BeanBinding<BEAN, TARGET> withValidator(
+        public BeanBindingBuilder<BEAN, TARGET> withValidator(
                 Validator<? super TARGET> validator);
 
         @Override
-        public default BeanBinding<BEAN, TARGET> withValidator(
+        public default BeanBindingBuilder<BEAN, TARGET> withValidator(
                 SerializablePredicate<? super TARGET> predicate,
                 String message) {
-            return (BeanBinding<BEAN, TARGET>) Binding.super.withValidator(
+            return (BeanBindingBuilder<BEAN, TARGET>) BindingBuilder.super.withValidator(
                     predicate, message);
         }
 
         @Override
-        default BeanBinding<BEAN, TARGET> withValidator(
+        default BeanBindingBuilder<BEAN, TARGET> withValidator(
                 SerializablePredicate<? super TARGET> predicate,
                 ErrorMessageProvider errorMessageProvider) {
-            return (BeanBinding<BEAN, TARGET>) Binding.super.withValidator(
+            return (BeanBindingBuilder<BEAN, TARGET>) BindingBuilder.super.withValidator(
                     predicate, errorMessageProvider);
         }
 
         @Override
-        default BeanBinding<BEAN, TARGET> withNullRepresentation(
+        default BeanBindingBuilder<BEAN, TARGET> withNullRepresentation(
                 TARGET nullRepresentation) {
-            return (BeanBinding<BEAN, TARGET>) Binding.super.withNullRepresentation(
+            return (BeanBindingBuilder<BEAN, TARGET>) BindingBuilder.super.withNullRepresentation(
                     nullRepresentation);
         }
 
         @Override
-        public BeanBinding<BEAN, TARGET> setRequired(
+        public BeanBindingBuilder<BEAN, TARGET> setRequired(
                 ErrorMessageProvider errorMessageProvider);
 
         @Override
-        public default BeanBinding<BEAN, TARGET> setRequired(
+        public default BeanBindingBuilder<BEAN, TARGET> setRequired(
                 String errorMessage) {
-            return (BeanBinding<BEAN, TARGET>) Binding.super.setRequired(
+            return (BeanBindingBuilder<BEAN, TARGET>) BindingBuilder.super.setRequired(
                     errorMessage);
         }
 
         @Override
-        public <NEWTARGET> BeanBinding<BEAN, NEWTARGET> withConverter(
+        public <NEWTARGET> BeanBindingBuilder<BEAN, NEWTARGET> withConverter(
                 Converter<TARGET, NEWTARGET> converter);
 
         @Override
-        public default <NEWTARGET> BeanBinding<BEAN, NEWTARGET> withConverter(
+        public default <NEWTARGET> BeanBindingBuilder<BEAN, NEWTARGET> withConverter(
                 SerializableFunction<TARGET, NEWTARGET> toModel,
                 SerializableFunction<NEWTARGET, TARGET> toPresentation) {
-            return (BeanBinding<BEAN, NEWTARGET>) Binding.super.withConverter(
+            return (BeanBindingBuilder<BEAN, NEWTARGET>) BindingBuilder.super.withConverter(
                     toModel, toPresentation);
         }
 
         @Override
-        public default <NEWTARGET> BeanBinding<BEAN, NEWTARGET> withConverter(
+        public default <NEWTARGET> BeanBindingBuilder<BEAN, NEWTARGET> withConverter(
                 SerializableFunction<TARGET, NEWTARGET> toModel,
                 SerializableFunction<NEWTARGET, TARGET> toPresentation,
                 String errorMessage) {
-            return (BeanBinding<BEAN, NEWTARGET>) Binding.super.withConverter(
+            return (BeanBindingBuilder<BEAN, NEWTARGET>) BindingBuilder.super.withConverter(
                     toModel, toPresentation, errorMessage);
         }
 
         @Override
-        public BeanBinding<BEAN, TARGET> withValidationStatusHandler(
+        public BeanBindingBuilder<BEAN, TARGET> withValidationStatusHandler(
                 ValidationStatusHandler handler);
 
         @Override
-        public default BeanBinding<BEAN, TARGET> withStatusLabel(Label label) {
-            return (BeanBinding<BEAN, TARGET>) Binding.super.withStatusLabel(
+        public default BeanBindingBuilder<BEAN, TARGET> withStatusLabel(
+                Label label) {
+            return (BeanBindingBuilder<BEAN, TARGET>) BindingBuilder.super.withStatusLabel(
                     label);
         }
 
@@ -152,19 +154,21 @@ public class BeanBinder<BEAN> extends Binder<BEAN> {
          *
          * @param propertyName
          *            the name of the property to bind, not null
+         * @return the newly created binding
          *
          * @throws IllegalArgumentException
          *             if the property name is invalid
          * @throws IllegalArgumentException
          *             if the property has no accessible getter
          *
-         * @see Binding#bind(SerializableFunction, SerializableBiConsumer)
+         * @see BindingBuilder#bind(SerializableFunction,
+         *      SerializableBiConsumer)
          */
-        public void bind(String propertyName);
+        public Binding<BEAN, TARGET> bind(String propertyName);
     }
 
     /**
-     * An internal implementation of {@link BeanBinding}.
+     * An internal implementation of {@link BeanBindingBuilder}.
      *
      * @param <BEAN>
      *            the bean type
@@ -174,11 +178,8 @@ public class BeanBinder<BEAN> extends Binder<BEAN> {
      *            the target property type
      */
     protected static class BeanBindingImpl<BEAN, FIELDVALUE, TARGET>
-            extends BindingImpl<BEAN, FIELDVALUE, TARGET>
-            implements BeanBinding<BEAN, TARGET> {
-
-        private Method getter;
-        private Method setter;
+            extends BindingBuilderImpl<BEAN, FIELDVALUE, TARGET>
+            implements BeanBindingBuilder<BEAN, TARGET> {
 
         /**
          * Creates a new bean binding.
@@ -200,50 +201,60 @@ public class BeanBinder<BEAN> extends Binder<BEAN> {
         }
 
         @Override
-        public BeanBinding<BEAN, TARGET> withValidator(
+        public BeanBindingBuilder<BEAN, TARGET> withValidator(
                 Validator<? super TARGET> validator) {
-            return (BeanBinding<BEAN, TARGET>) super.withValidator(validator);
+            return (BeanBindingBuilder<BEAN, TARGET>) super.withValidator(
+                    validator);
         }
 
         @Override
-        public <NEWTARGET> BeanBinding<BEAN, NEWTARGET> withConverter(
+        public <NEWTARGET> BeanBindingBuilder<BEAN, NEWTARGET> withConverter(
                 Converter<TARGET, NEWTARGET> converter) {
-            return (BeanBinding<BEAN, NEWTARGET>) super.withConverter(
+            return (BeanBindingBuilder<BEAN, NEWTARGET>) super.withConverter(
                     converter);
         }
 
         @Override
-        public BeanBinding<BEAN, TARGET> withValidationStatusHandler(
+        public BeanBindingBuilder<BEAN, TARGET> withValidationStatusHandler(
                 ValidationStatusHandler handler) {
-            return (BeanBinding<BEAN, TARGET>) super.withValidationStatusHandler(
+            return (BeanBindingBuilder<BEAN, TARGET>) super.withValidationStatusHandler(
                     handler);
         }
 
         @Override
-        public BeanBinding<BEAN, TARGET> setRequired(
+        public BeanBindingBuilder<BEAN, TARGET> setRequired(
                 ErrorMessageProvider errorMessageProvider) {
-            return (BeanBinding<BEAN, TARGET>) super.setRequired(
+            return (BeanBindingBuilder<BEAN, TARGET>) super.setRequired(
                     errorMessageProvider);
         }
 
         @Override
-        public void bind(String propertyName) {
+        public Binding<BEAN, TARGET> bind(String propertyName) {
             checkUnbound();
 
-            Binding<BEAN, Object> finalBinding;
+            BindingBuilder<BEAN, Object> finalBinding;
+
+            PropertyDescriptor descriptor = getDescriptor(propertyName);
+
+            Method getter = descriptor.getReadMethod();
+            Method setter = descriptor.getWriteMethod();
 
-            finalBinding = withConverter(createConverter(), false);
+            finalBinding = withConverter(
+                    createConverter(getter.getReturnType()), false);
 
             if (BeanUtil.checkBeanValidationAvailable()) {
                 finalBinding = finalBinding.withValidator(
                         new BeanValidator(getBinder().beanType, propertyName));
             }
 
-            PropertyDescriptor descriptor = getDescriptor(propertyName);
-            getter = descriptor.getReadMethod();
-            setter = descriptor.getWriteMethod();
-            finalBinding.bind(this::getValue, this::setValue);
-            getBinder().boundProperties.add(propertyName);
+            try {
+                return (Binding<BEAN, TARGET>) finalBinding.bind(
+                        bean -> invokeWrapExceptions(getter, bean),
+                        (bean, value) -> invokeWrapExceptions(setter, bean,
+                                value));
+            } finally {
+                getBinder().boundProperties.add(propertyName);
+            }
         }
 
         @Override
@@ -251,19 +262,13 @@ public class BeanBinder<BEAN> extends Binder<BEAN> {
             return (BeanBinder<BEAN>) super.getBinder();
         }
 
-        private void setValue(BEAN bean, Object value) {
-            try {
-                if (setter != null) {
-                    setter.invoke(bean, value);
-                }
-            } catch (IllegalAccessException | InvocationTargetException e) {
-                throw new RuntimeException(e);
+        private static Object invokeWrapExceptions(Method method, Object target,
+                Object... parameters) {
+            if (method == null) {
+                return null;
             }
-        }
-
-        private Object getValue(BEAN bean) {
             try {
-                return getter.invoke(bean);
+                return method.invoke(target, parameters);
             } catch (IllegalAccessException | InvocationTargetException e) {
                 throw new RuntimeException(e);
             }
@@ -295,9 +300,8 @@ public class BeanBinder<BEAN> extends Binder<BEAN> {
         }
 
         @SuppressWarnings("unchecked")
-        private Converter<TARGET, Object> createConverter() {
-            return Converter.from(
-                    fieldValue -> cast(fieldValue, getter.getReturnType()),
+        private Converter<TARGET, Object> createConverter(Class<?> getterType) {
+            return Converter.from(fieldValue -> cast(fieldValue, getterType),
                     propertyValue -> (TARGET) propertyValue, exception -> {
                         throw new RuntimeException(exception);
                     });
@@ -328,9 +332,9 @@ public class BeanBinder<BEAN> extends Binder<BEAN> {
     }
 
     @Override
-    public <FIELDVALUE> BeanBinding<BEAN, FIELDVALUE> forField(
+    public <FIELDVALUE> BeanBindingBuilder<BEAN, FIELDVALUE> forField(
             HasValue<FIELDVALUE> field) {
-        return (BeanBinding<BEAN, FIELDVALUE>) super.forField(field);
+        return (BeanBindingBuilder<BEAN, FIELDVALUE>) super.forField(field);
     }
 
     /**
@@ -351,6 +355,7 @@ public class BeanBinder<BEAN> extends Binder<BEAN> {
      *            the field to bind, not null
      * @param propertyName
      *            the name of the property to bind, not null
+     * @return the newly created binding
      *
      * @throws IllegalArgumentException
      *             if the property name is invalid
@@ -359,9 +364,9 @@ public class BeanBinder<BEAN> extends Binder<BEAN> {
      *
      * @see #bind(HasValue, SerializableFunction, SerializableBiConsumer)
      */
-    public <FIELDVALUE> void bind(HasValue<FIELDVALUE> field,
-            String propertyName) {
-        forField(field).bind(propertyName);
+    public <FIELDVALUE> Binding<BEAN, FIELDVALUE> bind(
+            HasValue<FIELDVALUE> field, String propertyName) {
+        return forField(field).bind(propertyName);
     }
 
     @Override
index da65b6600d8d5a3590ff8be6b9a75793d9d65a59..da52cfd116e6f21d0b8cd048e785c5be6d15a3d6 100644 (file)
@@ -42,7 +42,6 @@ import com.vaadin.server.SerializablePredicate;
 import com.vaadin.server.UserError;
 import com.vaadin.shared.Registration;
 import com.vaadin.ui.AbstractComponent;
-import com.vaadin.ui.AbstractMultiSelect;
 import com.vaadin.ui.Component;
 import com.vaadin.ui.Label;
 import com.vaadin.ui.UI;
@@ -80,6 +79,7 @@ import com.vaadin.ui.UI;
  * @param <BEAN>
  *            the bean type
  *
+ * @see BindingBuilder
  * @see Binding
  * @see HasValue
  *
@@ -94,12 +94,45 @@ public class Binder<BEAN> implements Serializable {
      *            the bean type
      * @param <TARGET>
      *            the target data type of the binding, matches the field type
-     *            until a converter has been set
+     *            unless a converter has been set
      *
      * @see Binder#forField(HasValue)
      */
     public interface Binding<BEAN, TARGET> extends Serializable {
 
+        /**
+         * Gets the field the binding uses.
+         *
+         * @return the field for the binding
+         */
+        public HasValue<?> getField();
+
+        /**
+         * Validates the field value and returns a {@code ValidationStatus}
+         * instance representing the outcome of the validation.
+         *
+         * @see Binder#validate()
+         * @see Validator#apply(Object)
+         *
+         * @return the validation result.
+         */
+        public ValidationStatus<TARGET> validate();
+
+    }
+
+    /**
+     * Creates a binding between a field and a data property.
+     *
+     * @param <BEAN>
+     *            the bean type
+     * @param <TARGET>
+     *            the target data type of the binding, matches the field type
+     *            until a converter has been set
+     *
+     * @see Binder#forField(HasValue)
+     */
+    public interface BindingBuilder<BEAN, TARGET> extends Serializable {
+
         /**
          * Completes this binding using the given getter and setter functions
          * representing a backing bean property. The functions are used to
@@ -136,10 +169,12 @@ public class Binder<BEAN> implements Serializable {
          * @param setter
          *            the function to write the field value to the property or
          *            null if read-only
+         * @return the newly created binding
          * @throws IllegalStateException
          *             if {@code bind} has already been called on this binding
          */
-        public void bind(SerializableFunction<BEAN, TARGET> getter,
+        public Binding<BEAN, TARGET> bind(
+                SerializableFunction<BEAN, TARGET> getter,
                 com.vaadin.server.SerializableBiConsumer<BEAN, TARGET> setter);
 
         /**
@@ -157,7 +192,7 @@ public class Binder<BEAN> implements Serializable {
          * @throws IllegalStateException
          *             if {@code bind} has already been called
          */
-        public Binding<BEAN, TARGET> withValidator(
+        public BindingBuilder<BEAN, TARGET> withValidator(
                 Validator<? super TARGET> validator);
 
         /**
@@ -180,7 +215,7 @@ public class Binder<BEAN> implements Serializable {
          * @throws IllegalStateException
          *             if {@code bind} has already been called
          */
-        public default Binding<BEAN, TARGET> withValidator(
+        public default BindingBuilder<BEAN, TARGET> withValidator(
                 SerializablePredicate<? super TARGET> predicate,
                 String message) {
             return withValidator(Validator.from(predicate, message));
@@ -207,7 +242,7 @@ public class Binder<BEAN> implements Serializable {
          * @throws IllegalStateException
          *             if {@code bind} has already been called
          */
-        public default Binding<BEAN, TARGET> withValidator(
+        public default BindingBuilder<BEAN, TARGET> withValidator(
                 SerializablePredicate<? super TARGET> predicate,
                 ErrorMessageProvider errorMessageProvider) {
             return withValidator(
@@ -237,7 +272,7 @@ public class Binder<BEAN> implements Serializable {
          * @throws IllegalStateException
          *             if {@code bind} has already been called
          */
-        public <NEWTARGET> Binding<BEAN, NEWTARGET> withConverter(
+        public <NEWTARGET> BindingBuilder<BEAN, NEWTARGET> withConverter(
                 Converter<TARGET, NEWTARGET> converter);
 
         /**
@@ -267,7 +302,7 @@ public class Binder<BEAN> implements Serializable {
          * @throws IllegalStateException
          *             if {@code bind} has already been called
          */
-        public default <NEWTARGET> Binding<BEAN, NEWTARGET> withConverter(
+        public default <NEWTARGET> BindingBuilder<BEAN, NEWTARGET> withConverter(
                 SerializableFunction<TARGET, NEWTARGET> toModel,
                 SerializableFunction<NEWTARGET, TARGET> toPresentation) {
             return withConverter(Converter.from(toModel, toPresentation,
@@ -305,7 +340,7 @@ public class Binder<BEAN> implements Serializable {
          * @throws IllegalStateException
          *             if {@code bind} has already been called
          */
-        public default <NEWTARGET> Binding<BEAN, NEWTARGET> withConverter(
+        public default <NEWTARGET> BindingBuilder<BEAN, NEWTARGET> withConverter(
                 SerializableFunction<TARGET, NEWTARGET> toModel,
                 SerializableFunction<NEWTARGET, TARGET> toPresentation,
                 String errorMessage) {
@@ -321,7 +356,7 @@ public class Binder<BEAN> implements Serializable {
          *            the value to use instead of {@code null}
          * @return a new binding with null representation handling.
          */
-        public default Binding<BEAN, TARGET> withNullRepresentation(
+        public default BindingBuilder<BEAN, TARGET> withNullRepresentation(
                 TARGET nullRepresentation) {
             return withConverter(
                     fieldValue -> Objects.equals(fieldValue, nullRepresentation)
@@ -330,13 +365,6 @@ public class Binder<BEAN> implements Serializable {
                             ? nullRepresentation : modelValue);
         }
 
-        /**
-         * Gets the field the binding uses.
-         *
-         * @return the field for the binding
-         */
-        public HasValue<?> getField();
-
         /**
          * Sets the given {@code label} to show an error message if validation
          * fails.
@@ -369,7 +397,8 @@ public class Binder<BEAN> implements Serializable {
          *            label to show validation status for the field
          * @return this binding, for chaining
          */
-        public default Binding<BEAN, TARGET> withStatusLabel(Label label) {
+        public default BindingBuilder<BEAN, TARGET> withStatusLabel(
+                Label label) {
             return withValidationStatusHandler(status -> {
                 label.setValue(status.getMessage().orElse(""));
                 // Only show the label when validation has failed
@@ -406,20 +435,9 @@ public class Binder<BEAN> implements Serializable {
          *            status change handler
          * @return this binding, for chaining
          */
-        public Binding<BEAN, TARGET> withValidationStatusHandler(
+        public BindingBuilder<BEAN, TARGET> withValidationStatusHandler(
                 ValidationStatusHandler handler);
 
-        /**
-         * Validates the field value and returns a {@code ValidationStatus}
-         * instance representing the outcome of the validation.
-         *
-         * @see Binder#validate()
-         * @see Validator#apply(Object)
-         *
-         * @return the validation result.
-         */
-        public ValidationStatus<TARGET> validate();
-
         /**
          * Sets the field to be required. This means two things:
          * <ol>
@@ -439,7 +457,8 @@ public class Binder<BEAN> implements Serializable {
          *            the error message to show for the invalid value
          * @return this binding, for chaining
          */
-        public default Binding<BEAN, TARGET> setRequired(String errorMessage) {
+        public default BindingBuilder<BEAN, TARGET> setRequired(
+                String errorMessage) {
             return setRequired(context -> errorMessage);
         }
 
@@ -458,12 +477,12 @@ public class Binder<BEAN> implements Serializable {
          *            the provider for localized validation error message
          * @return this binding, for chaining
          */
-        public Binding<BEAN, TARGET> setRequired(
+        public BindingBuilder<BEAN, TARGET> setRequired(
                 ErrorMessageProvider errorMessageProvider);
     }
 
     /**
-     * An internal implementation of {@code Binding}.
+     * An internal implementation of {@code BindingBuilder}.
      *
      * @param <BEAN>
      *            the bean type, must match the Binder bean type
@@ -473,18 +492,16 @@ public class Binder<BEAN> implements Serializable {
      *            the target data type of the binding, matches the field type
      *            until a converter has been set
      */
-    protected static class BindingImpl<BEAN, FIELDVALUE, TARGET>
-            implements Binding<BEAN, TARGET> {
+    protected static class BindingBuilderImpl<BEAN, FIELDVALUE, TARGET>
+            implements BindingBuilder<BEAN, TARGET> {
 
         private final Binder<BEAN> binder;
 
         private final HasValue<FIELDVALUE> field;
-        private Registration onValueChange;
         private ValidationStatusHandler statusHandler;
         private boolean isStatusHandlerChanged;
 
-        private SerializableFunction<BEAN, TARGET> getter;
-        private SerializableBiConsumer<BEAN, TARGET> setter;
+        private boolean bound;
 
         /**
          * Contains all converters and validators chained together in the
@@ -493,8 +510,9 @@ public class Binder<BEAN> implements Serializable {
         private Converter<FIELDVALUE, TARGET> converterValidatorChain;
 
         /**
-         * Creates a new binding associated with the given field. Initializes
-         * the binding with the given converter chain and status change handler.
+         * Creates a new binding builder associated with the given field.
+         * Initializes the builder with the given converter chain and status
+         * change handler.
          *
          * @param binder
          *            the binder this instance is connected to, not null
@@ -505,7 +523,8 @@ public class Binder<BEAN> implements Serializable {
          * @param statusHandler
          *            the handler to track validation status, not null
          */
-        protected BindingImpl(Binder<BEAN> binder, HasValue<FIELDVALUE> field,
+        protected BindingBuilderImpl(Binder<BEAN> binder,
+                HasValue<FIELDVALUE> field,
                 Converter<FIELDVALUE, TARGET> converterValidatorChain,
                 ValidationStatusHandler statusHandler) {
             this.field = field;
@@ -515,22 +534,26 @@ public class Binder<BEAN> implements Serializable {
         }
 
         @Override
-        public void bind(SerializableFunction<BEAN, TARGET> getter,
+        public Binding<BEAN, TARGET> bind(
+                SerializableFunction<BEAN, TARGET> getter,
                 SerializableBiConsumer<BEAN, TARGET> setter) {
             checkUnbound();
             Objects.requireNonNull(getter, "getter cannot be null");
 
-            this.getter = getter;
-            this.setter = setter;
-            onValueChange = getField()
-                    .addValueChangeListener(this::handleFieldValueChange);
-            getBinder().bindings.add(this);
-            getBinder().getBean().ifPresent(this::initFieldValue);
+            BindingImpl<BEAN, FIELDVALUE, TARGET> binding = new BindingImpl<>(
+                    this, getter, setter);
+
+            getBinder().bindings.add(binding);
+            getBinder().getBean().ifPresent(binding::initFieldValue);
             getBinder().fireStatusChangeEvent(false);
+
+            bound = true;
+
+            return binding;
         }
 
         @Override
-        public Binding<BEAN, TARGET> withValidator(
+        public BindingBuilder<BEAN, TARGET> withValidator(
                 Validator<? super TARGET> validator) {
             checkUnbound();
             Objects.requireNonNull(validator, "validator cannot be null");
@@ -541,13 +564,13 @@ public class Binder<BEAN> implements Serializable {
         }
 
         @Override
-        public <NEWTARGET> Binding<BEAN, NEWTARGET> withConverter(
+        public <NEWTARGET> BindingBuilder<BEAN, NEWTARGET> withConverter(
                 Converter<TARGET, NEWTARGET> converter) {
             return withConverter(converter, true);
         }
 
         @Override
-        public Binding<BEAN, TARGET> withValidationStatusHandler(
+        public BindingBuilder<BEAN, TARGET> withValidationStatusHandler(
                 ValidationStatusHandler handler) {
             checkUnbound();
             Objects.requireNonNull(handler, "handler cannot be null");
@@ -562,21 +585,15 @@ public class Binder<BEAN> implements Serializable {
         }
 
         @Override
-        public Binding<BEAN, TARGET> setRequired(
+        public BindingBuilder<BEAN, TARGET> setRequired(
                 ErrorMessageProvider errorMessageProvider) {
             checkUnbound();
-
-            getField().setRequiredIndicatorVisible(true);
+            field.setRequiredIndicatorVisible(true);
             return withValidator(
-                    value -> !Objects.equals(value, getField().getEmptyValue()),
+                    value -> !Objects.equals(value, field.getEmptyValue()),
                     errorMessageProvider);
         }
 
-        @Override
-        public HasValue<FIELDVALUE> getField() {
-            return field;
-        }
-
         /**
          * Implements {@link #withConverter(Converter)} method with additional
          * possibility to disable (reset) default null representation converter.
@@ -597,17 +614,17 @@ public class Binder<BEAN> implements Serializable {
          * @throws IllegalStateException
          *             if {@code bind} has already been called
          */
-        protected <NEWTARGET> Binding<BEAN, NEWTARGET> withConverter(
+        protected <NEWTARGET> BindingBuilder<BEAN, NEWTARGET> withConverter(
                 Converter<TARGET, NEWTARGET> converter,
                 boolean resetNullRepresentation) {
             checkUnbound();
             Objects.requireNonNull(converter, "converter cannot be null");
 
             if (resetNullRepresentation) {
-                getBinder().initialConverters.get(getField()).setIdentity();
+                getBinder().initialConverters.get(field).setIdentity();
             }
 
-            return getBinder().createBinding(getField(),
+            return getBinder().createBinding(field,
                     converterValidatorChain.chain(converter), statusHandler);
         }
 
@@ -629,11 +646,63 @@ public class Binder<BEAN> implements Serializable {
          *             if this binding is already bound
          */
         protected void checkUnbound() {
-            if (getter != null) {
+            if (bound) {
                 throw new IllegalStateException(
                         "cannot modify binding: already bound to a property");
             }
         }
+    }
+
+    /**
+     * An internal implementation of {@code Binding}.
+     *
+     * @param <BEAN>
+     *            the bean type, must match the Binder bean type
+     * @param <FIELDVALUE>
+     *            the value type of the field
+     * @param <TARGET>
+     *            the target data type of the binding, matches the field type
+     *            unless a converter has been set
+     */
+    protected static class BindingImpl<BEAN, FIELDVALUE, TARGET>
+            implements Binding<BEAN, TARGET> {
+
+        private final Binder<BEAN> binder;
+
+        private final HasValue<FIELDVALUE> field;
+        private final ValidationStatusHandler statusHandler;
+
+        private final SerializableFunction<BEAN, TARGET> getter;
+        private final SerializableBiConsumer<BEAN, TARGET> setter;
+
+        // Not final since we temporarily remove listener while changing values
+        private Registration onValueChange;
+
+        /**
+         * Contains all converters and validators chained together in the
+         * correct order.
+         */
+        private final Converter<FIELDVALUE, TARGET> converterValidatorChain;
+
+        public BindingImpl(BindingBuilderImpl<BEAN, FIELDVALUE, TARGET> builder,
+                SerializableFunction<BEAN, TARGET> getter,
+                SerializableBiConsumer<BEAN, TARGET> setter) {
+            this.binder = builder.getBinder();
+            this.field = builder.field;
+            this.statusHandler = builder.statusHandler;
+            converterValidatorChain = builder.converterValidatorChain;
+
+            onValueChange = getField()
+                    .addValueChangeListener(this::handleFieldValueChange);
+
+            this.getter = getter;
+            this.setter = setter;
+        }
+
+        @Override
+        public HasValue<FIELDVALUE> getField() {
+            return field;
+        }
 
         /**
          * Finds an appropriate locale to be used in conversion and validation.
@@ -783,6 +852,16 @@ public class Binder<BEAN> implements Serializable {
             return toValidationStatus(result);
         }
 
+        /**
+         * Returns the {@code Binder} connected to this {@code Binding}
+         * instance.
+         *
+         * @return the binder
+         */
+        protected Binder<BEAN> getBinder() {
+            return binder;
+        }
+
         private void notifyStatusHandler(ValidationStatus<?> status) {
             statusHandler.accept(status);
         }
@@ -895,18 +974,18 @@ public class Binder<BEAN> implements Serializable {
     }
 
     /**
-     * Creates a new binding for the given field. The returned binding may be
+     * Creates a new binding for the given field. The returned builder may be
      * further configured before invoking
-     * {@link Binding#bind(SerializableFunction, SerializableBiConsumer)} which
-     * completes the binding. Until {@code Binding.bind} is called, the binding
-     * has no effect.
+     * {@link BindingBuilder#bind(SerializableFunction, SerializableBiConsumer)}
+     * 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))}.
+     * {@link BindingBuilder#withNullRepresentation(Object)}.
      *
      * @param <FIELDVALUE>
      *            the value type of the field
@@ -916,7 +995,7 @@ public class Binder<BEAN> implements Serializable {
      *
      * @see #bind(HasValue, SerializableFunction, SerializableBiConsumer)
      */
-    public <FIELDVALUE> Binding<BEAN, FIELDVALUE> forField(
+    public <FIELDVALUE> BindingBuilder<BEAN, FIELDVALUE> forField(
             HasValue<FIELDVALUE> field) {
         Objects.requireNonNull(field, "field cannot be null");
         // clear previous errors for this field and any bean level validation
@@ -977,11 +1056,13 @@ public class Binder<BEAN> implements Serializable {
      * @param setter
      *            the function to write the field value to the property or null
      *            if read-only
+     * @return the newly created binding
      */
-    public <FIELDVALUE> void bind(HasValue<FIELDVALUE> field,
+    public <FIELDVALUE> Binding<BEAN, FIELDVALUE> bind(
+            HasValue<FIELDVALUE> field,
             SerializableFunction<BEAN, FIELDVALUE> getter,
             SerializableBiConsumer<BEAN, FIELDVALUE> setter) {
-        forField(field).bind(getter, setter);
+        return forField(field).bind(getter, setter);
     }
 
     /**
@@ -1311,7 +1392,7 @@ public class Binder<BEAN> implements Serializable {
      * @param statusLabel
      *            the status label to set
      * @see #setValidationStatusHandler(BinderStatusHandler)
-     * @see Binding#withStatusLabel(Label)
+     * @see BindingBuilder#withStatusLabel(Label)
      */
     public void setStatusLabel(Label statusLabel) {
         if (statusHandler != null) {
@@ -1349,7 +1430,7 @@ public class Binder<BEAN> implements Serializable {
      * @throws NullPointerException
      *             for <code>null</code> status handler
      * @see #setStatusLabel(Label)
-     * @see Binding#withValidationStatusHandler(ValidationStatusHandler)
+     * @see BindingBuilder#withValidationStatusHandler(ValidationStatusHandler)
      */
     public void setValidationStatusHandler(
             BinderValidationStatusHandler<BEAN> statusHandler) {
@@ -1390,8 +1471,8 @@ public class Binder<BEAN> implements Serializable {
      * <li>{@link #readBean(Object)} is called
      * <li>{@link #setBean(Object)} is called
      * <li>{@link #removeBean()} is called
-     * <li>{@link Binding#bind(SerializableFunction, SerializableBiConsumer)} is
-     * called
+     * <li>{@link BindingBuilder#bind(SerializableFunction, SerializableBiConsumer)}
+     * is called
      * <li>{@link Binder#validate()} or {@link Binding#validate()} is called
      * </ul>
      *
@@ -1401,10 +1482,8 @@ public class Binder<BEAN> implements Serializable {
      * @see #setBean(Object)
      * @see #removeBean()
      * @see #forField(HasValue)
-     * @see #forSelect(AbstractMultiSelect)
      * @see #validate()
      * @see Binding#validate()
-     * @see Binding#bind(Object)
      *
      * @param listener
      *            status change listener to add, not null
@@ -1431,10 +1510,10 @@ public class Binder<BEAN> implements Serializable {
      *            the handler to notify of status changes, not null
      * @return the new incomplete binding
      */
-    protected <FIELDVALUE, TARGET> Binding<BEAN, TARGET> createBinding(
+    protected <FIELDVALUE, TARGET> BindingBuilder<BEAN, TARGET> createBinding(
             HasValue<FIELDVALUE> field, Converter<FIELDVALUE, TARGET> converter,
             ValidationStatusHandler handler) {
-        return new BindingImpl<>(this, field, converter, handler);
+        return new BindingBuilderImpl<>(this, field, converter, handler);
     }
 
     /**
index 41a181dacf2b2735bb01a3dcb82546d8824aa45c..983745c89a86af7f5c5da3a7d96c96c2e87323c7 100644 (file)
@@ -22,13 +22,13 @@ import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.data.validator.BeanValidator;
 
 /**
  * Binder validation status change. Represents the outcome of binder level
  * validation. Has information about the validation results for the
- * {@link Binding#withValidator(Validator) field level} and
+ * {@link BindingBuilder#withValidator(Validator) field level} and
  * {@link Binder#withValidator(Validator)binder level} validation.
  * <p>
  * Note: if there are any field level validation errors, the bean level
@@ -149,7 +149,7 @@ public class BinderValidationStatus<BEAN> implements Serializable {
      * Gets the field level validation statuses.
      * <p>
      * The field level validtors have been added with
-     * {@link Binding#withValidator(Validator)}.
+     * {@link BindingBuilder#withValidator(Validator)}.
      *
      * @return the field validation statuses
      */
@@ -175,7 +175,7 @@ public class BinderValidationStatus<BEAN> implements Serializable {
      * Gets the failed field level validation statuses.
      * <p>
      * The field level validtors have been added with
-     * {@link Binding#withValidator(Validator)}.
+     * {@link BindingBuilder#withValidator(Validator)}.
      *
      * @return a list of failed field level validation statuses
      */
index 076b4a4a4d74e12fe8ff376f07e91308ab4fcee9..ded3ed79556a3d7ee462f669f72ba1bbb5a9294d 100644 (file)
@@ -18,6 +18,7 @@ package com.vaadin.data;
 import java.util.EventObject;
 
 import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.server.SerializableBiConsumer;
 import com.vaadin.server.SerializableFunction;
 
@@ -32,8 +33,8 @@ import com.vaadin.server.SerializableFunction;
  * <li>{@link Binder#readBean(Object)} is called
  * <li>{@link Binder#setBean(Object)} is called
  * <li>{@link Binder#removeBean()} is called
- * <li>{@link Binding#bind(SerializableFunction, SerializableBiConsumer)} is
- * called
+ * <li>{@link BindingBuilder#bind(SerializableFunction, SerializableBiConsumer)}
+ * is called
  * <li>{@link Binder#validate()} or {@link Binding#validate()} is called
  * </ul>
  *
index bbc4326b60fa9ed20f2cc0d35920e64fab0eaa55..a5ff3896aaa41f2d7febd8c00a087130819e5e9e 100644 (file)
@@ -20,14 +20,16 @@ import java.util.Objects;
 import java.util.Optional;
 
 import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 
 /**
  * Represents the status of field validation. Status can be {@code Status.OK},
  * {@code Status.ERROR} or {@code Status.RESET}. Status OK and ERROR are always
  * associated with a ValidationResult {@link #getResult}.
  * <p>
- * Use {@link Binding#withValidationStatusHandler(ValidationStatusHandler)} to
- * register a handler for field level validation status changes.
+ * Use
+ * {@link BindingBuilder#withValidationStatusHandler(ValidationStatusHandler)}
+ * to register a handler for field level validation status changes.
  *
  * @author Vaadin Ltd
  *
@@ -36,7 +38,7 @@ import com.vaadin.data.Binder.Binding;
  *            status changed, matches the field type unless a converter has been
  *            set
  *
- * @see Binding#withValidationStatusHandler(ValidationStatusHandler)
+ * @see BindingBuilder#withValidationStatusHandler(ValidationStatusHandler)
  * @see Binding#validate()
  * @see ValidationStatusHandler
  * @see BinderValidationStatus
index eb38e044f4604a2c603030431505e065587984e5..9cf20b92ea148dd364231901d8df82c6776c3565 100644 (file)
@@ -18,13 +18,13 @@ package com.vaadin.data;
 import java.io.Serializable;
 import java.util.function.Consumer;
 
-import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.ui.AbstractComponent;
 
 /**
  * Handler for {@link ValidationStatus} changes.
  * <p>
- * {@link Binding#withValidationStatusHandler(withValidationStatusHandler)
+ * {@link BindingBuilder#withValidationStatusHandler(withValidationStatusHandler)
  * Register} an instance of this class to be able to override the default
  * handling, which is to show
  * {@link AbstractComponent#setComponentError(com.vaadin.server.ErrorMessage) an
@@ -32,7 +32,7 @@ import com.vaadin.ui.AbstractComponent;
  *
  * @author Vaadin Ltd
  *
- * @see Binding#withValidationStatusHandler(withValidationStatusHandler)
+ * @see BindingBuilder#withValidationStatusHandler(withValidationStatusHandler)
  * @see ValidationStatus
  *
  * @since 8.0
index 9c46469f228b69d54e4ba25f618b05a9d7796ff3..6d58e54613528c20d34327955bd8e46970c77d9c 100644 (file)
@@ -19,7 +19,7 @@ package com.vaadin.data.util.converter;
 import java.io.Serializable;
 import java.util.function.Function;
 
-import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.data.Result;
 import com.vaadin.server.SerializableFunction;
 
@@ -149,7 +149,7 @@ public interface Converter<PRESENTATION, MODEL> extends Serializable {
      * <p>
      * In most typical cases you should not need this method but instead only
      * need to define one converter for a binding using
-     * {@link Binding#withConverter(Converter)}.
+     * {@link BindingBuilder#withConverter(Converter)}.
      *
      * @param <T>
      *            the model type of the resulting converter
index 08cdf3842640b65153ed15d6560cac350b8c9f09..fd15d3981c9fba7941391765fdf6d152666796ef 100644 (file)
@@ -10,8 +10,8 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.vaadin.data.BeanBinder.BeanBinding;
-import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.BeanBinder.BeanBindingBuilder;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.tests.data.bean.BeanToValidate;
 
 public class BeanBinderTest
@@ -178,18 +178,18 @@ public class BeanBinderTest
 
     @Test
     public void beanBindingChainingMethods() {
-        Method[] methods = BeanBinding.class.getMethods();
+        Method[] methods = BeanBindingBuilder.class.getMethods();
         for (int i = 0; i < methods.length; i++) {
             Method method = methods[i];
             try {
-                Method actualMethod = BeanBinding.class.getMethod(
+                Method actualMethod = BeanBindingBuilder.class.getMethod(
                         method.getName(), method.getParameterTypes());
 
                 Assert.assertNotSame(
                         actualMethod + " should be overridden in "
-                                + BeanBinding.class
+                                + BeanBindingBuilder.class
                                 + " with more specific return type ",
-                        Binding.class, actualMethod.getReturnType());
+                        BindingBuilder.class, actualMethod.getReturnType());
             } catch (NoSuchMethodException | SecurityException e) {
                 throw new RuntimeException(e);
             }
index 5aafc475ef10a062c955f36fb63a5742ce355be0..8f61fb5f16edf0458147c6a540f0ed4c215b5067 100644 (file)
@@ -26,6 +26,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.data.ValidationStatus.Status;
 import com.vaadin.data.util.converter.Converter;
 import com.vaadin.data.util.converter.StringToIntegerConverter;
@@ -249,14 +250,15 @@ public class BinderBookOfVaadinTest {
         // Slider for integers between 1 and 10
         Slider salaryLevelField = new Slider("Salary level", 1, 10);
 
-        Binding<BookPerson, String> b1 = binder.forField(yearOfBirthField);
-        Binding<BookPerson, Integer> b2 = b1.withConverter(
+        BindingBuilder<BookPerson, String> b1 = binder
+                .forField(yearOfBirthField);
+        BindingBuilder<BookPerson, Integer> b2 = b1.withConverter(
                 new StringToIntegerConverter("Must enter a number"));
         b2.bind(BookPerson::getYearOfBirth, BookPerson::setYearOfBirth);
 
-        Binding<BookPerson, Double> salaryBinding1 = binder
+        BindingBuilder<BookPerson, Double> salaryBinding1 = binder
                 .forField(salaryLevelField);
-        Binding<BookPerson, Integer> salaryBinding2 = salaryBinding1
+        BindingBuilder<BookPerson, Integer> salaryBinding2 = salaryBinding1
                 .withConverter(Double::intValue, Integer::doubleValue);
         salaryBinding2.bind(BookPerson::getSalaryLevel,
                 BookPerson::setSalaryLevel);
@@ -308,9 +310,9 @@ public class BinderBookOfVaadinTest {
                 .withValidator(
                         returnDate -> !returnDate
                                 .isBefore(departing.getValue()),
-                        "Cannot return before departing");
+                        "Cannot return before departing")
+                .bind(Trip::getReturnDate, Trip::setReturnDate);
 
-        returnBinding.bind(Trip::getReturnDate, Trip::setReturnDate);
         departing.addValueChangeListener(event -> returnBinding.validate());
 
         LocalDate past = LocalDate.now();
@@ -361,9 +363,9 @@ public class BinderBookOfVaadinTest {
                 .withValidator(
                         returnDate -> !returnDate
                                 .isBefore(departing.getValue()),
-                        "Cannot return before departing");
+                        "Cannot return before departing")
+                .bind(Trip::getReturnDate, Trip::setReturnDate);
 
-        returnBinding.bind(Trip::getReturnDate, Trip::setReturnDate);
         departing.addValueChangeListener(event -> returnBinding.validate());
 
         LocalDate past = LocalDate.now();
index 9ad8dca2c3ba5a52c4e9040ede148285c84f603e..f6a7463a12046d81adca39dfd9447320efe5ba9b 100644 (file)
@@ -29,6 +29,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.data.util.converter.StringToIntegerConverter;
 import com.vaadin.data.util.converter.ValueContext;
 import com.vaadin.data.validator.NotEmptyValidator;
@@ -73,7 +74,7 @@ public class BinderConverterValidatorTest
 
     @Test
     public void bound_validatorsAreOK_noErrors() {
-        Binding<Person, String> binding = binder.forField(nameField);
+        BindingBuilder<Person, String> binding = binder.forField(nameField);
         binding.withValidator(Validator.alwaysPass()).bind(Person::getFirstName,
                 Person::setFirstName);
 
@@ -87,7 +88,7 @@ public class BinderConverterValidatorTest
     @SuppressWarnings("serial")
     @Test
     public void bound_validatorsFail_errors() {
-        Binding<Person, String> binding = binder.forField(nameField);
+        BindingBuilder<Person, String> binding = binder.forField(nameField);
         binding.withValidator(Validator.alwaysPass());
         String msg1 = "foo";
         String msg2 = "bar";
@@ -221,7 +222,7 @@ public class BinderConverterValidatorTest
         bean.setStatus("1");
         Binder<StatusBean> binder = new Binder<>();
 
-        Binding<StatusBean, String> binding = binder.forField(field)
+        BindingBuilder<StatusBean, String> binding = binder.forField(field)
                 .withConverter(presentation -> {
                     if (presentation.equals("OK")) {
                         return "1";
@@ -266,7 +267,7 @@ public class BinderConverterValidatorTest
     public void validate_failedBeanValidatorWithFieldValidator() {
         String msg = "foo";
 
-        Binding<Person, String> binding = binder.forField(nameField)
+        BindingBuilder<Person, String> binding = binder.forField(nameField)
                 .withValidator(new NotEmptyValidator<>(msg));
         binding.bind(Person::getFirstName, Person::setFirstName);
 
@@ -286,7 +287,7 @@ public class BinderConverterValidatorTest
     public void validate_failedBothBeanValidatorAndFieldValidator() {
         String msg1 = "foo";
 
-        Binding<Person, String> binding = binder.forField(nameField)
+        BindingBuilder<Person, String> binding = binder.forField(nameField)
                 .withValidator(new NotEmptyValidator<>(msg1));
         binding.bind(Person::getFirstName, Person::setFirstName);
 
@@ -322,7 +323,7 @@ public class BinderConverterValidatorTest
     @Test
     public void binder_saveIfValid() {
         String msg1 = "foo";
-        Binding<Person, String> binding = binder.forField(nameField)
+        BindingBuilder<Person, String> binding = binder.forField(nameField)
                 .withValidator(new NotEmptyValidator<>(msg1));
         binding.bind(Person::getFirstName, Person::setFirstName);
 
@@ -554,11 +555,11 @@ public class BinderConverterValidatorTest
     public void save_validationErrors_exceptionContainsErrors()
             throws ValidationException {
         String msg = "foo";
-        Binding<Person, String> nameBinding = binder.forField(nameField)
+        BindingBuilder<Person, String> nameBinding = binder.forField(nameField)
                 .withValidator(new NotEmptyValidator<>(msg));
         nameBinding.bind(Person::getFirstName, Person::setFirstName);
 
-        Binding<Person, Integer> ageBinding = binder.forField(ageField)
+        BindingBuilder<Person, Integer> ageBinding = binder.forField(ageField)
                 .withConverter(stringToInteger).withValidator(notNegative);
         ageBinding.bind(Person::getAge, Person::setAge);
 
@@ -585,7 +586,7 @@ public class BinderConverterValidatorTest
 
     @Test
     public void binderBindAndLoad_clearsErrors() {
-        Binding<Person, String> binding = binder.forField(nameField)
+        BindingBuilder<Person, String> binding = binder.forField(nameField)
                 .withValidator(notEmpty);
         binding.bind(Person::getFirstName, Person::setFirstName);
         binder.withValidator(bean -> !bean.getFirstName().contains("error"),
@@ -621,7 +622,7 @@ public class BinderConverterValidatorTest
         // bind a new field that has invalid value in bean
         TextField lastNameField = new TextField();
         person.setLastName("");
-        Binding<Person, String> binding2 = binder.forField(lastNameField)
+        BindingBuilder<Person, String> binding2 = binder.forField(lastNameField)
                 .withValidator(notEmpty);
         binding2.bind(Person::getLastName, Person::setLastName);
 
@@ -663,15 +664,15 @@ public class BinderConverterValidatorTest
         final SerializablePredicate<String> lengthPredicate = v -> v
                 .length() > 2;
 
-        Binding<Person, String> firstNameBinding = binder.forField(nameField)
-                .withValidator(lengthPredicate, "length");
+        BindingBuilder<Person, String> firstNameBinding = binder
+                .forField(nameField).withValidator(lengthPredicate, "length");
         firstNameBinding.bind(Person::getFirstName, Person::setFirstName);
 
         Binding<Person, String> lastNameBinding = binder.forField(lastNameField)
                 .withValidator(v -> !nameField.getValue().isEmpty()
                         || lengthPredicate.test(v), "err")
-                .withValidator(lengthPredicate, "length");
-        lastNameBinding.bind(Person::getLastName, Person::setLastName);
+                .withValidator(lengthPredicate, "length")
+                .bind(Person::getLastName, Person::setLastName);
 
         // this will be triggered as a new bean is bound with binder.bind(),
         // causing a validation error to be visible until reset is done
index e453e68482d96f08b164c4033afbc866e150d329..4f46a78a5bbbe81cada0a184f6f01669fdd02e9b 100644 (file)
@@ -22,6 +22,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.data.util.converter.StringToIntegerConverter;
 import com.vaadin.tests.data.bean.Person;
 
@@ -45,7 +46,7 @@ public class BinderStatusChangeTest
     public void bindBinding_unbound_eventWhenBoundEndnoEventsBeforeBound() {
         binder.addStatusChangeListener(this::statusChanged);
 
-        Binding<Person, String> binding = binder.forField(nameField);
+        BindingBuilder<Person, String> binding = binder.forField(nameField);
 
         nameField.setValue("");
         Assert.assertNull(event.get());
@@ -377,8 +378,8 @@ public class BinderStatusChangeTest
 
     @Test
     public void validateBinding_noValidationErrors_statusEventWithoutErrors() {
-        Binding<Person, String> binding = binder.forField(nameField);
-        binding.bind(Person::getFirstName, Person::setFirstName);
+        Binding<Person, String> binding = binder.forField(nameField)
+                .bind(Person::getFirstName, Person::setFirstName);
         binder.forField(ageField)
                 .withConverter(new StringToIntegerConverter(""))
                 .bind(Person::getAge, Person::setAge);
@@ -394,8 +395,8 @@ public class BinderStatusChangeTest
     @Test
     public void validateBinding_validationErrors_statusEventWithError() {
         Binding<Person, String> binding = binder.forField(nameField)
-                .withValidator(name -> false, "");
-        binding.bind(Person::getFirstName, Person::setFirstName);
+                .withValidator(name -> false, "")
+                .bind(Person::getFirstName, Person::setFirstName);
         binder.forField(ageField)
                 .withConverter(new StringToIntegerConverter(""))
                 .bind(Person::getAge, Person::setAge);
index 7f2353a448bcf2aefbf069cfac31ad666ccc9c8b..d1f831003b5abee7c538750583df1bf78de06a26 100644 (file)
@@ -13,7 +13,7 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.data.util.converter.StringToIntegerConverter;
 import com.vaadin.data.validator.NotEmptyValidator;
 import com.vaadin.server.ErrorMessage;
@@ -331,7 +331,7 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> {
         TextField textField = new TextField();
         Assert.assertFalse(textField.isRequiredIndicatorVisible());
 
-        Binding<Person, String> binding = binder.forField(textField);
+        BindingBuilder<Person, String> binding = binder.forField(textField);
         Assert.assertFalse(textField.isRequiredIndicatorVisible());
 
         binding.setRequired("foobar");
@@ -357,7 +357,7 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> {
         textField.setLocale(Locale.CANADA);
         Assert.assertFalse(textField.isRequiredIndicatorVisible());
 
-        Binding<Person, String> binding = binder.forField(textField);
+        BindingBuilder<Person, String> binding = binder.forField(textField);
         Assert.assertFalse(textField.isRequiredIndicatorVisible());
         AtomicInteger invokes = new AtomicInteger();
 
index d901ee00d8b5940e3199d44383ed5eaed1275862..bb4052cc8dd1bd6b5fb1f04fd7fc55c86a3fb210 100644 (file)
@@ -23,6 +23,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.data.ValidationStatus.Status;
 import com.vaadin.tests.data.bean.Person;
 import com.vaadin.ui.Label;
@@ -48,7 +49,7 @@ public class BinderValidationStatusTest
     @Test
     public void bindingWithStatusHandler_handlerGetsEvents() {
         AtomicReference<ValidationStatus<?>> statusCapture = new AtomicReference<>();
-        Binding<Person, String> binding = binder.forField(nameField)
+        BindingBuilder<Person, String> binding = binder.forField(nameField)
                 .withValidator(notEmpty).withValidationStatusHandler(evt -> {
                     Assert.assertNull(statusCapture.get());
                     statusCapture.set(evt);
@@ -86,8 +87,7 @@ public class BinderValidationStatusTest
     public void bindingWithStatusHandler_defaultStatusHandlerIsReplaced() {
         Binding<Person, String> binding = binder.forField(nameField)
                 .withValidator(notEmpty).withValidationStatusHandler(evt -> {
-                });
-        binding.bind(Person::getFirstName, Person::setFirstName);
+                }).bind(Person::getFirstName, Person::setFirstName);
 
         Assert.assertNull(nameField.getComponentError());
 
@@ -106,8 +106,8 @@ public class BinderValidationStatusTest
         Label label = new Label();
 
         Binding<Person, String> binding = binder.forField(nameField)
-                .withValidator(notEmpty).withStatusLabel(label);
-        binding.bind(Person::getFirstName, Person::setFirstName);
+                .withValidator(notEmpty).withStatusLabel(label)
+                .bind(Person::getFirstName, Person::setFirstName);
 
         nameField.setValue("");
 
@@ -133,8 +133,8 @@ public class BinderValidationStatusTest
         Label label = new Label();
 
         Binding<Person, String> binding = binder.forField(nameField)
-                .withValidator(notEmpty).withStatusLabel(label);
-        binding.bind(Person::getFirstName, Person::setFirstName);
+                .withValidator(notEmpty).withStatusLabel(label)
+                .bind(Person::getFirstName, Person::setFirstName);
 
         Assert.assertNull(nameField.getComponentError());
 
@@ -150,7 +150,7 @@ public class BinderValidationStatusTest
 
     @Test(expected = IllegalStateException.class)
     public void bindingWithStatusHandler_addAfterBound() {
-        Binding<Person, String> binding = binder.forField(nameField)
+        BindingBuilder<Person, String> binding = binder.forField(nameField)
                 .withValidator(notEmpty);
         binding.bind(Person::getFirstName, Person::setFirstName);
 
@@ -161,7 +161,7 @@ public class BinderValidationStatusTest
     public void bindingWithStatusLabel_addAfterBound() {
         Label label = new Label();
 
-        Binding<Person, String> binding = binder.forField(nameField)
+        BindingBuilder<Person, String> binding = binder.forField(nameField)
                 .withValidator(notEmpty);
         binding.bind(Person::getFirstName, Person::setFirstName);
 
@@ -172,7 +172,7 @@ public class BinderValidationStatusTest
     public void bindingWithStatusLabel_setAfterHandler() {
         Label label = new Label();
 
-        Binding<Person, String> binding = binder.forField(nameField);
+        BindingBuilder<Person, String> binding = binder.forField(nameField);
 
         binding.withValidationStatusHandler(NOOP);
 
@@ -183,7 +183,7 @@ public class BinderValidationStatusTest
     public void bindingWithStatusHandler_setAfterLabel() {
         Label label = new Label();
 
-        Binding<Person, String> binding = binder.forField(nameField);
+        BindingBuilder<Person, String> binding = binder.forField(nameField);
 
         binding.withStatusLabel(label);
 
@@ -193,7 +193,7 @@ public class BinderValidationStatusTest
     @Test(expected = IllegalStateException.class)
     public void bindingWithStatusHandler_setAfterOtherHandler() {
 
-        Binding<Person, String> binding = binder.forField(nameField);
+        BindingBuilder<Person, String> binding = binder.forField(nameField);
 
         binding.withValidationStatusHandler(NOOP);
 
@@ -394,8 +394,7 @@ public class BinderValidationStatusTest
     public void binderWithStatusHandler_defaultStatusHandlerIsReplaced() {
         Binding<Person, String> binding = binder.forField(nameField)
                 .withValidator(notEmpty).withValidationStatusHandler(evt -> {
-                });
-        binding.bind(Person::getFirstName, Person::setFirstName);
+                }).bind(Person::getFirstName, Person::setFirstName);
 
         Assert.assertNull(nameField.getComponentError());
 
@@ -414,8 +413,8 @@ public class BinderValidationStatusTest
         Label label = new Label();
 
         Binding<Person, String> binding = binder.forField(nameField)
-                .withValidator(notEmpty).withStatusLabel(label);
-        binding.bind(Person::getFirstName, Person::setFirstName);
+                .withValidator(notEmpty).withStatusLabel(label)
+                .bind(Person::getFirstName, Person::setFirstName);
 
         Assert.assertNull(nameField.getComponentError());
 
@@ -431,7 +430,7 @@ public class BinderValidationStatusTest
 
     @Test(expected = IllegalStateException.class)
     public void binderWithStatusHandler_addAfterBound() {
-        Binding<Person, String> binding = binder.forField(nameField)
+        BindingBuilder<Person, String> binding = binder.forField(nameField)
                 .withValidator(notEmpty);
         binding.bind(Person::getFirstName, Person::setFirstName);
 
@@ -442,7 +441,7 @@ public class BinderValidationStatusTest
     public void binderWithStatusLabel_addAfterBound() {
         Label label = new Label();
 
-        Binding<Person, String> binding = binder.forField(nameField)
+        BindingBuilder<Person, String> binding = binder.forField(nameField)
                 .withValidator(notEmpty);
         binding.bind(Person::getFirstName, Person::setFirstName);
 
@@ -453,7 +452,7 @@ public class BinderValidationStatusTest
     public void binderWithStatusLabel_setAfterHandler() {
         Label label = new Label();
 
-        Binding<Person, String> binding = binder.forField(nameField);
+        BindingBuilder<Person, String> binding = binder.forField(nameField);
         binding.bind(Person::getFirstName, Person::setFirstName);
 
         binder.setValidationStatusHandler(event -> {
@@ -466,7 +465,7 @@ public class BinderValidationStatusTest
     public void binderWithStatusHandler_setAfterLabel() {
         Label label = new Label();
 
-        Binding<Person, String> binding = binder.forField(nameField);
+        BindingBuilder<Person, String> binding = binder.forField(nameField);
         binding.bind(Person::getFirstName, Person::setFirstName);
 
         binder.setStatusLabel(label);
@@ -484,7 +483,7 @@ public class BinderValidationStatusTest
     public void binderWithStatusHandler_replaceHandler() {
         AtomicReference<BinderValidationStatus<?>> capture = new AtomicReference<>();
 
-        Binding<Person, String> binding = binder.forField(nameField);
+        BindingBuilder<Person, String> binding = binder.forField(nameField);
         binding.bind(Person::getFirstName, Person::setFirstName);
 
         binder.setValidationStatusHandler(results -> {
index 61cacf8b510432885797e7ac42b5df652ed892e0..3a358b7097b6e7f77d1de5802bbcd41810dc5721 100644 (file)
@@ -17,7 +17,7 @@ package com.vaadin.data.validator;
 
 import java.util.Objects;
 
-import com.vaadin.data.Binder.Binding;
+import com.vaadin.data.Binder.BindingBuilder;
 import com.vaadin.data.HasValue;
 import com.vaadin.data.ValidationResult;
 import com.vaadin.data.Validator;
@@ -33,13 +33,13 @@ import com.vaadin.data.util.converter.ValueContext;
  * This validator can be suitable for fields that have been marked as required
  * with {@link HasValue#setRequiredIndicatorVisible(boolean)}.
  * <p>
- * Note that {@link Binding#setRequired(com.vaadin.data.ErrorMessageProvider)}
+ * Note that {@link BindingBuilder#setRequired(com.vaadin.data.ErrorMessageProvider)}
  * does almost the same thing, but verifies against the value NOT being equal to
  * what {@link HasValue#getEmptyValue()} returns and sets the required indicator
  * visible with {@link HasValue#setRequiredIndicatorVisible(boolean)}.
  *
  * @see HasValue#setRequiredIndicatorVisible(boolean)
- * @see Binding#setRequired(com.vaadin.data.ErrorMessageProvider)
+ * @see BindingBuilder#setRequired(com.vaadin.data.ErrorMessageProvider)
  * @author Vaadin Ltd
  * @since 8.0
  *