diff options
-rw-r--r-- | all/src/main/templates/release-notes.html | 1 | ||||
-rw-r--r-- | server/src/main/java/com/vaadin/data/Binder.java | 27 | ||||
-rw-r--r-- | server/src/test/java/com/vaadin/data/BinderTest.java | 47 |
3 files changed, 52 insertions, 23 deletions
diff --git a/all/src/main/templates/release-notes.html b/all/src/main/templates/release-notes.html index d488f3e5e0..fab73eff2a 100644 --- a/all/src/main/templates/release-notes.html +++ b/all/src/main/templates/release-notes.html @@ -105,6 +105,7 @@ <li><tt>Button</tt> has a new constructor that may cause constructor calls with null as first parameter to be ambiguous.</li> <li><tt>DataCommunicator</tt> method <tt>getDataProviderSize</tt> is now <tt>public</tt>, not <tt>protected</tt>.</li> <li><tt>Binder</tt> method <tt>getBindings</tt> now returns a Collection, not a Set.</li> + <li><tt>BindingBuilder</tt> now works like a proper builder. Adding a converter will not mark Binding as <tt>bound</tt> allowing chaining to the same object.</li> <h2>For incompatible or behaviour-altering changes in 8.1, please see <a href="https://vaadin.com/download/release/8.1/8.1.0/release-notes.html#incompatible">8.1 release notes</a></h2> diff --git a/server/src/main/java/com/vaadin/data/Binder.java b/server/src/main/java/com/vaadin/data/Binder.java index afb81efa67..0ec15c2345 100644 --- a/server/src/main/java/com/vaadin/data/Binder.java +++ b/server/src/main/java/com/vaadin/data/Binder.java @@ -137,9 +137,9 @@ public class Binder<BEAN> implements Serializable { public BindingValidationStatusHandler getValidationStatusHandler(); /** - * Unbinds the binding from its respective {@code Binder} - * Removes any {@code ValueChangeListener} {@code Registration} from - * associated {@code HasValue} + * Unbinds the binding from its respective {@code Binder} Removes any + * {@code ValueChangeListener} {@code Registration} from associated + * {@code HasValue} * * @since 8.2 */ @@ -571,7 +571,7 @@ public class Binder<BEAN> implements Serializable { * Contains all converters and validators chained together in the * correct order. */ - private Converter<FIELDVALUE, TARGET> converterValidatorChain; + private Converter<FIELDVALUE, ?> converterValidatorChain; /** * Creates a new binding builder associated with the given field. @@ -667,7 +667,7 @@ public class Binder<BEAN> implements Serializable { checkUnbound(); Objects.requireNonNull(validator, "validator cannot be null"); - converterValidatorChain = converterValidatorChain + converterValidatorChain = ((Converter<FIELDVALUE, TARGET>) converterValidatorChain) .chain(new ValidatorAsConverter<>(validator)); return this; } @@ -729,15 +729,14 @@ public class Binder<BEAN> implements Serializable { checkUnbound(); Objects.requireNonNull(converter, "converter cannot be null"); - // Mark this step to be bound to prevent modifying multiple times. - bound = true; - if (resetNullRepresentation) { getBinder().initialConverters.get(field).setIdentity(); } - return getBinder().createBinding(field, - converterValidatorChain.chain(converter), statusHandler); + converterValidatorChain = ((Converter<FIELDVALUE, TARGET>) converterValidatorChain) + .chain(converter); + + return (BindingBuilder<BEAN, NEWTARGET>) this; } /** @@ -807,7 +806,7 @@ public class Binder<BEAN> implements Serializable { this.binder = builder.getBinder(); this.field = builder.field; this.statusHandler = builder.statusHandler; - converterValidatorChain = builder.converterValidatorChain; + converterValidatorChain = ((Converter<FIELDVALUE, TARGET>) builder.converterValidatorChain); onValueChange = getField() .addValueChangeListener(this::handleFieldValueChange); @@ -842,7 +841,8 @@ public class Binder<BEAN> implements Serializable { @Override public BindingValidationStatus<TARGET> validate() { - Objects.requireNonNull(binder, "This Binding is no longer attached to a Binder"); + Objects.requireNonNull(binder, + "This Binding is no longer attached to a Binder"); BindingValidationStatus<TARGET> status = doValidation(); getBinder().getValidationStatusHandler() .statusChange(new BinderValidationStatus<>(getBinder(), @@ -2525,7 +2525,8 @@ public class Binder<BEAN> implements Serializable { * * This method should just be used for internal cleanup. * - * @param binding The {@code Binding} to remove from the binding map + * @param binding + * The {@code Binding} to remove from the binding map * * @since 8.2 */ diff --git a/server/src/test/java/com/vaadin/data/BinderTest.java b/server/src/test/java/com/vaadin/data/BinderTest.java index af84d7a808..36d1692fcb 100644 --- a/server/src/test/java/com/vaadin/data/BinderTest.java +++ b/server/src/test/java/com/vaadin/data/BinderTest.java @@ -18,9 +18,10 @@ import org.junit.Test; import com.vaadin.data.Binder.Binding; import com.vaadin.data.Binder.BindingBuilder; -import com.vaadin.data.converter.StringToDoubleConverter; import com.vaadin.data.converter.StringToIntegerConverter; +import com.vaadin.data.validator.IntegerRangeValidator; import com.vaadin.data.validator.NotEmptyValidator; +import com.vaadin.data.validator.StringLengthValidator; import com.vaadin.server.ErrorMessage; import com.vaadin.tests.data.bean.Person; import com.vaadin.tests.data.bean.Sex; @@ -672,15 +673,41 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> { Assert.assertArrayEquals(s1.toArray(), s2.toArray()); } - /** - * Access to old step in binding chain that already has a converter applied - * to it is expected to prevent modifications. - */ - @Test(expected = IllegalStateException.class) - public void multiple_calls_to_same_binder_throws() { - BindingBuilder<Person, String> forField = binder.forField(nameField); - forField.withConverter(new StringToDoubleConverter("Failed")); - forField.bind(Person::getFirstName, Person::setFirstName); + @Test + public void multiple_calls_to_same_binding_builder() { + String stringLength = "String length failure"; + String conversion = "Conversion failed"; + String ageLimit = "Age not in valid range"; + BindingValidationStatus validation; + + binder = new Binder<>(Person.class); + BindingBuilder builder = binder.forField(ageField); + builder.withValidator(new StringLengthValidator(stringLength, 0, 3)); + builder.withConverter(new StringToIntegerConverter(conversion)); + builder.withValidator(new IntegerRangeValidator(ageLimit, 3, 150)); + Binding<Person, ?> bind = builder.bind("age"); + + binder.setBean(item); + + ageField.setValue("123123"); + validation = bind.validate(); + Assert.assertTrue(validation.isError()); + Assert.assertEquals(stringLength, validation.getMessage().get()); + + ageField.setValue("age"); + validation = bind.validate(); + Assert.assertTrue(validation.isError()); + Assert.assertEquals(conversion, validation.getMessage().get()); + + ageField.setValue("256"); + validation = bind.validate(); + Assert.assertTrue(validation.isError()); + Assert.assertEquals(ageLimit, validation.getMessage().get()); + + ageField.setValue("30"); + validation = bind.validate(); + Assert.assertFalse(validation.isError()); + Assert.assertEquals(30, item.getAge()); } @Test |