Skip to content

Commit

Permalink
fix: run setBean validation for changed bindings only (#18735) (#18760)
Browse files Browse the repository at this point in the history
  • Loading branch information
tepi authored and vaadin-bot committed Feb 20, 2024
1 parent d602710 commit 58e3a38
Showing 1 changed file with 33 additions and 28 deletions.
61 changes: 33 additions & 28 deletions flow-data/src/main/java/com/vaadin/flow/data/binder/Binder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1811,10 +1811,24 @@ public static <BEAN> Binder<BEAN> withPropertySet(
*/
protected void handleFieldValueChange(Binding<BEAN, ?> binding) {
changedBindings.add(binding);
if (getBean() != null) {
doWriteIfValid(getBean(), changedBindings);

if (getBean() == null) {
binding.validate();
} else {
validate(binding);
BinderValidationStatus<BEAN> status = validateBindingsAndBean();
if (status.isOk()) {
doWriteIfValid(getBean(), changedBindings);
} else {
// Fire status change for changed bindings only
getValidationStatusHandler()
.statusChange(new BinderValidationStatus<>(this,
status.getFieldValidationStatuses().stream()
.filter(s -> changedBindings
.contains(s.getBinding()))
.collect(Collectors.toList()),
status.getBeanValidationErrors()));
fireStatusChangeEvent(status.hasErrors());
}
}
}

Expand Down Expand Up @@ -2325,9 +2339,10 @@ private BinderValidationStatus<BEAN> doWriteIfValid(BEAN bean,
bindings);

// First run fields level validation, if no validation errors then
// update bean. Note that this will validate all bindings.
List<BindingValidationStatus<?>> bindingResults = getBindings().stream()
.map(b -> b.validate(false)).collect(Collectors.toList());
// update bean.
List<BindingValidationStatus<?>> bindingResults = currentBindings
.stream().map(b -> b.validate(false))
.collect(Collectors.toList());

if (bindingResults.stream()
.noneMatch(BindingValidationStatus::isError)) {
Expand Down Expand Up @@ -2594,35 +2609,25 @@ protected BinderValidationStatus<BEAN> validate(boolean fireEvent) {
}

/**
* Validates the target binding. Also runs validation for all other
* bindings, and if possible, bean-level validations as well.
* Runs validation for all bindings to determine binder's validity state. If
* a bean has been set and all bindings pass validation, bean-level
* validations are run as well.
*
* {@link BinderValidationStatusHandler} is called with only the status of
* the target binding.
*
* {@link StatusChangeEvent} is fired with current binder validation status
*
* @param targetBinding
* target binding for validation
* @return BinderValidationStatus for the validation run
*/
private void validate(Binding<BEAN, ?> targetBinding) {
List<BindingValidationStatus<?>> bindingValidationStatuses = validateBindings();
private BinderValidationStatus<BEAN> validateBindingsAndBean() {
List<BindingValidationStatus<?>> bindingStatuses = validateBindings();
boolean bindingsInError = bindingStatuses.stream()
.anyMatch(BindingValidationStatus::isError);

List<ValidationResult> beanStatuses = new ArrayList<>();
if (getBean() != null) {
// Only execute bean-level validation when binding validators pass
if (!bindingsInError) {
beanStatuses.addAll(validateBean(getBean()));
}
BindingValidationStatus<?> status = bindingValidationStatuses.stream()
.filter(s -> targetBinding.equals(s.getBinding())).findFirst()
.orElse(null);

getValidationStatusHandler().statusChange(new BinderValidationStatus<>(
this, Collections.singletonList(status),
Collections.emptyList()));

fireStatusChangeEvent(bindingValidationStatuses.stream()
.anyMatch(BindingValidationStatus::isError)
|| beanStatuses.stream().anyMatch(ValidationResult::isError));
return new BinderValidationStatus<>(this, bindingStatuses,
beanStatuses);
}

/**
Expand Down

0 comments on commit 58e3a38

Please sign in to comment.