diff options
author | Teemu Suo-Anttila <tsuoanttila@users.noreply.github.com> | 2017-10-11 15:15:46 +0300 |
---|---|---|
committer | Henri Sara <henri.sara@gmail.com> | 2017-10-11 15:15:46 +0300 |
commit | dd806e8bb31ecc7bce50f3aed5ed3fab48364895 (patch) | |
tree | 78a37299c2bda5e6a5dff17f2d1289739f829a3c /server/src/main/java | |
parent | 75ac029f5a8f18ff42ef33644876f063e9981031 (diff) | |
download | vaadin-framework-dd806e8bb31ecc7bce50f3aed5ed3fab48364895.tar.gz vaadin-framework-dd806e8bb31ecc7bce50f3aed5ed3fab48364895.zip |
Fix Binder bean writing to only validate and write given bindings (#10162)
Diffstat (limited to 'server/src/main/java')
-rw-r--r-- | server/src/main/java/com/vaadin/data/Binder.java | 80 |
1 files changed, 53 insertions, 27 deletions
diff --git a/server/src/main/java/com/vaadin/data/Binder.java b/server/src/main/java/com/vaadin/data/Binder.java index 7f63cb3841..e28c191018 100644 --- a/server/src/main/java/com/vaadin/data/Binder.java +++ b/server/src/main/java/com/vaadin/data/Binder.java @@ -118,14 +118,33 @@ public class Binder<BEAN> implements Serializable { /** * Validates the field value and returns a {@code ValidationStatus} - * instance representing the outcome of the validation. + * instance representing the outcome of the validation. This method is a + * short-hand for calling {@link #validate(boolean)} with + * {@code fireEvent} {@code true}. * + * @see #validate(boolean) * @see Binder#validate() * @see Validator#apply(Object, ValueContext) * * @return the validation result. */ - public BindingValidationStatus<TARGET> validate(); + public default BindingValidationStatus<TARGET> validate() { + return validate(true); + } + + /** + * Validates the field value and returns a {@code ValidationStatus} + * instance representing the outcome of the validation. + * + * @see #validate() + * + * @param fireEvent + * {@code true} to fire status event; {@code false} to not + * @return the validation result. + * + * @since 8.2 + */ + public BindingValidationStatus<TARGET> validate(boolean fireEvent); /** * Gets the validation status handler for this Binding. @@ -423,11 +442,9 @@ public class Binder<BEAN> implements Serializable { TARGET nullRepresentation) { return withConverter( fieldValue -> Objects.equals(fieldValue, nullRepresentation) - ? null - : fieldValue, + ? null : fieldValue, modelValue -> Objects.isNull(modelValue) - ? nullRepresentation - : modelValue); + ? nullRepresentation : modelValue); } /** @@ -842,14 +859,17 @@ public class Binder<BEAN> implements Serializable { } @Override - public BindingValidationStatus<TARGET> validate() { + public BindingValidationStatus<TARGET> validate(boolean fireEvent) { Objects.requireNonNull(binder, "This Binding is no longer attached to a Binder"); BindingValidationStatus<TARGET> status = doValidation(); - getBinder().getValidationStatusHandler() - .statusChange(new BinderValidationStatus<>(getBinder(), - Arrays.asList(status), Collections.emptyList())); - getBinder().fireStatusChangeEvent(status.isError()); + if (fireEvent) { + getBinder().getValidationStatusHandler() + .statusChange(new BinderValidationStatus<>(getBinder(), + Arrays.asList(status), + Collections.emptyList())); + getBinder().fireStatusChangeEvent(status.isError()); + } return status; } @@ -1449,7 +1469,8 @@ public class Binder<BEAN> implements Serializable { * if some of the bound field values fail to validate */ public void writeBean(BEAN bean) throws ValidationException { - BinderValidationStatus<BEAN> status = doWriteIfValid(bean, bindings); + BinderValidationStatus<BEAN> status = doWriteIfValid(bean, + new ArrayList<>(bindings)); if (status.hasErrors()) { throw new ValidationException(status.getFieldValidationErrors(), status.getBeanValidationErrors()); @@ -1478,12 +1499,15 @@ public class Binder<BEAN> implements Serializable { * updated, {@code false} otherwise */ public boolean writeBeanIfValid(BEAN bean) { - return doWriteIfValid(bean, bindings).isOk(); + return doWriteIfValid(bean, new ArrayList<>(bindings)).isOk(); } /** * Writes the field values into the given bean if all field level validators * pass. Runs bean level validators on the bean after writing. + * <p> + * <strong>Note:</strong> The collection of bindings is cleared on + * successful save. * * @param bean * the bean to write field values into @@ -1498,12 +1522,12 @@ public class Binder<BEAN> implements Serializable { Objects.requireNonNull(bean, "bean cannot be null"); List<ValidationResult> binderResults = Collections.emptyList(); - // First run fields level validation - List<BindingValidationStatus<?>> bindingStatuses = validateBindings(); + // First run fields level validation, if no validation errors then + // update bean + List<BindingValidationStatus<?>> bindingResults = bindings.stream() + .map(b -> b.validate(false)).collect(Collectors.toList()); - // If no validation errors then update bean - // TODO: Enable partial write when some fields don't pass - if (bindingStatuses.stream() + if (bindingResults.stream() .noneMatch(BindingValidationStatus::isError)) { // Store old bean values so we can restore them if validators fail Map<Binding<BEAN, ?>, Object> oldValues = getBeanState(bean, @@ -1516,14 +1540,17 @@ public class Binder<BEAN> implements Serializable { if (binderResults.stream().anyMatch(ValidationResult::isError)) { // Bean validator failed, revert values restoreBeanState(bean, oldValues); - } else if (getBean() == null || bean.equals(getBean())) { + } else if (bean.equals(getBean())) { /* * Changes have been successfully saved. The set is only cleared - * if using readBean/writeBean or when the changes are stored in - * the currently set bean. - * - * Writing changes to another bean when using setBean does not - * clear the set of changed bindings. + * when the changes are stored in the currently set bean. + */ + bindings.clear(); + } else if (getBean() == null) { + /* + * When using readBean and writeBean there is no knowledge of + * which bean the changes come from or are stored in. Binder is + * no longer "changed" when saved succesfully to any bean. */ changedBindings.clear(); } @@ -1531,7 +1558,7 @@ public class Binder<BEAN> implements Serializable { // Generate status object and fire events. BinderValidationStatus<BEAN> status = new BinderValidationStatus<>(this, - bindingStatuses, binderResults); + bindingResults, binderResults); getValidationStatusHandler().statusChange(status); fireStatusChangeEvent(!status.isOk()); return status; @@ -2160,8 +2187,7 @@ public class Binder<BEAN> implements Serializable { Converter<FIELDVALUE, FIELDVALUE> nullRepresentationConverter = Converter .from(fieldValue -> fieldValue, modelValue -> Objects.isNull(modelValue) - ? field.getEmptyValue() - : modelValue, + ? field.getEmptyValue() : modelValue, exception -> exception.getMessage()); ConverterDelegate<FIELDVALUE> converter = new ConverterDelegate<>( nullRepresentationConverter); |