/* * Copyright 2000-2021 Vaadin Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.vaadin.data; import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import com.vaadin.data.Binder.BindingBuilder; import com.vaadin.server.SerializablePredicate; /** * Binder validation status change. Represents the outcome of binder level * validation. Has information about the validation results for the * {@link BindingBuilder#withValidator(Validator) field level} and * {@link Binder#withValidator(Validator) binder level} validation. *

* Note: if there are any field level validation errors, the bean level * validation is not run. *

* Use {@link Binder#setValidationStatusHandler(BinderValidationStatusHandler)} * to handle form level validation status changes. * * @author Vaadin Ltd * * @param * the bean type of the binder * * @see BinderValidationStatusHandler * @see Binder#setValidationStatusHandler(BinderValidationStatusHandler) * @see Binder#validate() * @see BindingValidationStatus * * @since 8.0 */ public class BinderValidationStatus implements Serializable { private final Binder binder; private final List> bindingStatuses; private final List binderStatuses; /** * Convenience method for creating a unresolved validation status for the * given binder. *

* In practice this status means that the values might not be valid, but * validation errors should be hidden. * * @param source * the source binder * @return a unresolved validation status * @param * the bean type of the binder */ public static BinderValidationStatus createUnresolvedStatus( Binder source) { return new BinderValidationStatus<>(source, source.getBindings().stream().map( b -> BindingValidationStatus.createUnresolvedStatus(b)) .collect(Collectors.toList()), Collections.emptyList()); } /** * Creates a new binder validation status for the given binder and * validation results. * * @param source * the source binder * @param bindingStatuses * the validation results for the fields * @param binderStatuses * the validation results for binder level validation */ public BinderValidationStatus(Binder source, List> bindingStatuses, List binderStatuses) { Objects.requireNonNull(bindingStatuses, "binding statuses cannot be null"); Objects.requireNonNull(binderStatuses, "binder statuses cannot be null"); this.binder = source; this.bindingStatuses = Collections.unmodifiableList(bindingStatuses); this.binderStatuses = Collections.unmodifiableList(binderStatuses); } /** * Gets whether validation for the binder passed or not. * * @return {@code true} if validation has passed, {@code false} if not */ public boolean isOk() { return !hasErrors(); } /** * Gets whether the validation for the binder failed or not. * * @return {@code true} if validation failed, {@code false} if validation * passed */ public boolean hasErrors() { return binderStatuses.stream().filter(ValidationResult::isError) .findAny().isPresent() || bindingStatuses.stream() .filter(BindingValidationStatus::isError).findAny() .isPresent(); } /** * Gets the source binder of the status. * * @return the source binder */ public Binder getBinder() { return binder; } /** * Gets both field and bean level validation errors. * * @return a list of all validation errors */ public List getValidationErrors() { List errors = getFieldValidationErrors().stream() .map(s -> s.getResult().get()).collect(Collectors.toList()); errors.addAll(getBeanValidationErrors()); return errors; } /** * Gets the field level validation statuses. *

* The field level validators have been added with * {@link BindingBuilder#withValidator(Validator)}. * * @return the field validation statuses */ public List> getFieldValidationStatuses() { return bindingStatuses; } /** * Gets the bean level validation results. * * @return the bean level validation results */ public List getBeanValidationResults() { return binderStatuses; } /** * Gets the failed field level validation statuses. *

* The field level validators have been added with * {@link BindingBuilder#withValidator(Validator)}. * * @return a list of failed field level validation statuses */ public List> getFieldValidationErrors() { return bindingStatuses.stream().filter(BindingValidationStatus::isError) .collect(Collectors.toList()); } /** * Gets the failed bean level validation results. * * @return a list of failed bean level validation results */ public List getBeanValidationErrors() { return binderStatuses.stream().filter(ValidationResult::isError) .collect(Collectors.toList()); } /** * Notifies all validation status handlers in bindings. * * @see #notifyBindingValidationStatusHandlers(SerializablePredicate) * * @since 8.2 */ public void notifyBindingValidationStatusHandlers() { notifyBindingValidationStatusHandlers(t -> true); } /** * Notifies validation status handlers for bindings that pass given filter. * The filter should return {@code true} for each * {@link BindingValidationStatus} that should be delegated to the status * handler in the binding. * * @see #notifyBindingValidationStatusHandlers() * * @param filter * the filter to select bindings to run status handling for * * @since 8.2 */ public void notifyBindingValidationStatusHandlers( SerializablePredicate> filter) { bindingStatuses.stream().filter(filter).forEach(s -> s.getBinding() .getValidationStatusHandler().statusChange(s)); } }