Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: run setBean validation for changed bindings only (#18735) (#18760) (CP: 24.3) #18763

Merged
merged 1 commit into from
Feb 20, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1833,10 +1833,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 @@ -2347,9 +2361,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 @@ -2616,35 +2631,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
Loading