summaryrefslogtreecommitdiffstats
path: root/server/src
diff options
context:
space:
mode:
authorTeemu Suo-Anttila <tsuoanttila@users.noreply.github.com>2017-10-11 16:04:58 +0300
committerHenri Sara <henri.sara@gmail.com>2017-10-11 16:04:58 +0300
commitd0b5741b81d214491c93d4d042c79e10bb4f192e (patch)
treeea36411bfcf99c456e2e590782a51d0882ae0315 /server/src
parentdd806e8bb31ecc7bce50f3aed5ed3fab48364895 (diff)
downloadvaadin-framework-d0b5741b81d214491c93d4d042c79e10bb4f192e.tar.gz
vaadin-framework-d0b5741b81d214491c93d4d042c79e10bb4f192e.zip
Add ErrorLevel to Validators and results (#10099)
Fixes #9792
Diffstat (limited to 'server/src')
-rw-r--r--server/src/main/java/com/vaadin/data/Binder.java121
-rw-r--r--server/src/main/java/com/vaadin/data/BindingValidationStatus.java80
-rw-r--r--server/src/main/java/com/vaadin/data/ValidationResult.java77
-rw-r--r--server/src/main/java/com/vaadin/data/ValidationResultWrap.java102
-rw-r--r--server/src/main/java/com/vaadin/data/Validator.java71
-rw-r--r--server/src/test/java/com/vaadin/data/BinderTest.java20
6 files changed, 420 insertions, 51 deletions
diff --git a/server/src/main/java/com/vaadin/data/Binder.java b/server/src/main/java/com/vaadin/data/Binder.java
index e28c191018..828130bd81 100644
--- a/server/src/main/java/com/vaadin/data/Binder.java
+++ b/server/src/main/java/com/vaadin/data/Binder.java
@@ -43,12 +43,14 @@ import com.vaadin.data.HasValue.ValueChangeListener;
import com.vaadin.data.converter.StringToIntegerConverter;
import com.vaadin.data.validator.BeanValidator;
import com.vaadin.event.EventRouter;
+import com.vaadin.server.AbstractErrorMessage.ContentMode;
import com.vaadin.server.ErrorMessage;
import com.vaadin.server.SerializableFunction;
import com.vaadin.server.SerializablePredicate;
import com.vaadin.server.Setter;
import com.vaadin.server.UserError;
import com.vaadin.shared.Registration;
+import com.vaadin.shared.ui.ErrorLevel;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
@@ -286,6 +288,7 @@ public class Binder<BEAN> implements Serializable {
* failure, the property value is not updated.
*
* @see #withValidator(Validator)
+ * @see #withValidator(SerializablePredicate, String, ErrorLevel)
* @see #withValidator(SerializablePredicate, ErrorMessageProvider)
* @see Validator#from(SerializablePredicate, String)
*
@@ -305,6 +308,40 @@ public class Binder<BEAN> implements Serializable {
/**
* A convenience method to add a validator to this binding using the
+ * {@link Validator#from(SerializablePredicate, String, ErrorLevel)}
+ * factory method.
+ * <p>
+ * Validators are applied, in registration order, when the field value
+ * is written to the backing property. If any validator returns a
+ * failure, the property value is not updated.
+ *
+ * @see #withValidator(Validator)
+ * @see #withValidator(SerializablePredicate, String)
+ * @see #withValidator(SerializablePredicate, ErrorMessageProvider,
+ * ErrorLevel)
+ * @see Validator#from(SerializablePredicate, String)
+ *
+ * @param predicate
+ * the predicate performing validation, not null
+ * @param message
+ * the error message to report in case validation failure
+ * @param errorLevel
+ * the error level for failures from this validator, not null
+ * @return this binding, for chaining
+ * @throws IllegalStateException
+ * if {@code bind} has already been called
+ *
+ * @since 8.2
+ */
+ public default BindingBuilder<BEAN, TARGET> withValidator(
+ SerializablePredicate<? super TARGET> predicate, String message,
+ ErrorLevel errorLevel) {
+ return withValidator(
+ Validator.from(predicate, message, errorLevel));
+ }
+
+ /**
+ * A convenience method to add a validator to this binding using the
* {@link Validator#from(SerializablePredicate, ErrorMessageProvider)}
* factory method.
* <p>
@@ -314,6 +351,8 @@ public class Binder<BEAN> implements Serializable {
*
* @see #withValidator(Validator)
* @see #withValidator(SerializablePredicate, String)
+ * @see #withValidator(SerializablePredicate, ErrorMessageProvider,
+ * ErrorLevel)
* @see Validator#from(SerializablePredicate, ErrorMessageProvider)
*
* @param predicate
@@ -332,6 +371,41 @@ public class Binder<BEAN> implements Serializable {
}
/**
+ * A convenience method to add a validator to this binding using the
+ * {@link Validator#from(SerializablePredicate, ErrorMessageProvider, ErrorLevel)}
+ * factory method.
+ * <p>
+ * Validators are applied, in registration order, when the field value
+ * is written to the backing property. If any validator returns a
+ * failure, the property value is not updated.
+ *
+ * @see #withValidator(Validator)
+ * @see #withValidator(SerializablePredicate, String, ErrorLevel)
+ * @see #withValidator(SerializablePredicate, ErrorMessageProvider)
+ * @see Validator#from(SerializablePredicate, ErrorMessageProvider,
+ * ErrorLevel)
+ *
+ * @param predicate
+ * the predicate performing validation, not null
+ * @param errorMessageProvider
+ * the provider to generate error messages, not null
+ * @param errorLevel
+ * the error level for failures from this validator, not null
+ * @return this binding, for chaining
+ * @throws IllegalStateException
+ * if {@code bind} has already been called
+ *
+ * @since 8.2
+ */
+ public default BindingBuilder<BEAN, TARGET> withValidator(
+ SerializablePredicate<? super TARGET> predicate,
+ ErrorMessageProvider errorMessageProvider,
+ ErrorLevel errorLevel) {
+ return withValidator(Validator.from(predicate, errorMessageProvider,
+ errorLevel));
+ }
+
+ /**
* Maps the binding to another data type using the given
* {@link Converter}.
* <p>
@@ -905,10 +979,7 @@ public class Binder<BEAN> implements Serializable {
private BindingValidationStatus<TARGET> toValidationStatus(
Result<TARGET> result) {
- return new BindingValidationStatus<>(this,
- result.isError()
- ? ValidationResult.error(result.getMessage().get())
- : ValidationResult.ok());
+ return new BindingValidationStatus<>(result, this);
}
/**
@@ -1031,11 +1102,7 @@ public class Binder<BEAN> implements Serializable {
@Override
public Result<T> convertToModel(T value, ValueContext context) {
ValidationResult validationResult = validator.apply(value, context);
- if (validationResult.isError()) {
- return Result.error(validationResult.getErrorMessage());
- } else {
- return Result.ok(value);
- }
+ return new ValidationResultWrap<>(value, validationResult);
}
@Override
@@ -2012,14 +2079,18 @@ public class Binder<BEAN> implements Serializable {
*
* @param field
* the field with the invalid value
- * @param error
- * the error message to set
+ * @param result
+ * the validation error result
+ *
+ * @since 8.2
*/
- protected void handleError(HasValue<?> field, String error) {
- if (field instanceof AbstractComponent) {
- ((AbstractComponent) field).setComponentError(new UserError(error));
- }
-
+ protected void handleError(HasValue<?> field, ValidationResult result) {
+ result.getErrorLevel().ifPresent(level -> {
+ if (field instanceof AbstractComponent) {
+ ((AbstractComponent) field).setComponentError(new UserError(
+ result.getErrorMessage(), ContentMode.TEXT, level));
+ }
+ });
}
/**
@@ -2033,7 +2104,23 @@ public class Binder<BEAN> implements Serializable {
HasValue<?> source = status.getField();
clearError(source);
if (status.isError()) {
- handleError(source, status.getMessage().get());
+ Optional<ValidationResult> firstError = status
+ .getValidationResults().stream()
+ .filter(ValidationResult::isError).findFirst();
+ if (firstError.isPresent()) {
+ // Failed with a Validation error
+ handleError(source, firstError.get());
+ } else {
+ // Conversion error
+ status.getResult()
+ .ifPresent(result -> handleError(source, result));
+ }
+ } else {
+ // Show first non-error ValidationResult message.
+ status.getValidationResults().stream()
+ .filter(result -> result.getErrorLevel().isPresent())
+ .findFirst()
+ .ifPresent(result -> handleError(source, result));
}
}
diff --git a/server/src/main/java/com/vaadin/data/BindingValidationStatus.java b/server/src/main/java/com/vaadin/data/BindingValidationStatus.java
index 5b5a066418..f6a7809970 100644
--- a/server/src/main/java/com/vaadin/data/BindingValidationStatus.java
+++ b/server/src/main/java/com/vaadin/data/BindingValidationStatus.java
@@ -16,6 +16,8 @@
package com.vaadin.data;
import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import java.util.Optional;
@@ -24,8 +26,8 @@ import com.vaadin.data.Binder.BindingBuilder;
/**
* Represents the status of field validation. Status can be {@code Status.OK},
- * {@code Status.ERROR} or {@code Status.RESET}. Status OK and ERROR are always
- * associated with a ValidationResult {@link #getResult}.
+ * {@code Status.ERROR} or {@code Status.UNRESOLVED}. Status OK and ERROR are
+ * always associated with a ValidationResult {@link #getResult}.
* <p>
* Use
* {@link BindingBuilder#withValidationStatusHandler(BindingValidationStatusHandler)}
@@ -70,8 +72,9 @@ public class BindingValidationStatus<TARGET> implements Serializable {
}
private final Status status;
- private final ValidationResult result;
+ private final List<ValidationResult> results;
private final Binding<?, TARGET> binding;
+ private Result<TARGET> result;
/**
* Convenience method for creating a {@link Status#UNRESOLVED} validation
@@ -86,7 +89,7 @@ public class BindingValidationStatus<TARGET> implements Serializable {
*/
public static <TARGET> BindingValidationStatus<TARGET> createUnresolvedStatus(
Binding<?, TARGET> source) {
- return new BindingValidationStatus<>(source, Status.UNRESOLVED, null);
+ return new BindingValidationStatus<TARGET>(null, source);
}
/**
@@ -98,6 +101,7 @@ public class BindingValidationStatus<TARGET> implements Serializable {
* @param result
* the result of the validation
*/
+ @Deprecated
public BindingValidationStatus(Binding<?, TARGET> source,
ValidationResult result) {
this(source, result.isError() ? Status.ERROR : Status.OK, result);
@@ -116,20 +120,43 @@ public class BindingValidationStatus<TARGET> implements Serializable {
* @param result
* the related result, may be {@code null}
*/
+ @Deprecated
public BindingValidationStatus(Binding<?, TARGET> source, Status status,
ValidationResult result) {
+ this(result.isError() ? Result.error(result.getErrorMessage())
+ : Result.ok(null), source);
+ }
+
+ /**
+ * Creates a new status change event.
+ * <p>
+ * If {@code result} is {@code null}, the {@code status} is
+ * {@link Status#UNRESOLVED}.
+ *
+ * @param result
+ * the related result object, may be {@code null}
+ * @param source
+ * field whose status has changed, not {@code null}
+ *
+ * @since 8.2
+ */
+ public BindingValidationStatus(Result<TARGET> result,
+ Binding<?, TARGET> source) {
Objects.requireNonNull(source, "Event source may not be null");
- Objects.requireNonNull(status, "Status may not be null");
- if (Objects.equals(status, Status.OK) && result.isError()
- || Objects.equals(status, Status.ERROR) && !result.isError()
- || Objects.equals(status, Status.UNRESOLVED)
- && result != null) {
- throw new IllegalStateException(
- "Invalid validation status " + status + " for given result "
- + (result == null ? "null" : result.toString()));
- }
+
binding = source;
- this.status = status;
+ if (result != null) {
+ this.status = result.isError() ? Status.ERROR : Status.OK;
+ if (result instanceof ValidationResultWrap) {
+ results = ((ValidationResultWrap<TARGET>) result)
+ .getValidationResults();
+ } else {
+ results = Collections.emptyList();
+ }
+ } else {
+ this.status = Status.UNRESOLVED;
+ results = Collections.emptyList();
+ }
this.result = result;
}
@@ -159,8 +186,10 @@ public class BindingValidationStatus<TARGET> implements Serializable {
* status is not an error
*/
public Optional<String> getMessage() {
- return Optional.ofNullable(result).filter(ValidationResult::isError)
- .map(ValidationResult::getErrorMessage);
+ if (getStatus() == Status.OK || result == null) {
+ return Optional.empty();
+ }
+ return result.getMessage();
}
/**
@@ -171,7 +200,24 @@ public class BindingValidationStatus<TARGET> implements Serializable {
* @return the validation result
*/
public Optional<ValidationResult> getResult() {
- return Optional.ofNullable(result);
+ if (result == null) {
+ return Optional.empty();
+ }
+ return Optional.of(result.isError()
+ ? ValidationResult.error(result.getMessage().orElse(""))
+ : ValidationResult.ok());
+ }
+
+ /**
+ * Gets all the validation results related to this binding validation
+ * status.
+ *
+ * @return list of validation results
+ *
+ * @since 8.2
+ */
+ public List<ValidationResult> getValidationResults() {
+ return Collections.unmodifiableList(results);
}
/**
diff --git a/server/src/main/java/com/vaadin/data/ValidationResult.java b/server/src/main/java/com/vaadin/data/ValidationResult.java
index d458911ba1..33e10d6db2 100644
--- a/server/src/main/java/com/vaadin/data/ValidationResult.java
+++ b/server/src/main/java/com/vaadin/data/ValidationResult.java
@@ -17,6 +17,9 @@ package com.vaadin.data;
import java.io.Serializable;
import java.util.Objects;
+import java.util.Optional;
+
+import com.vaadin.shared.ui.ErrorLevel;
/**
* Represents the result of a validation. A result may be either successful or
@@ -35,26 +38,30 @@ public interface ValidationResult extends Serializable {
class SimpleValidationResult implements ValidationResult {
private final String error;
+ private final ErrorLevel errorLevel;
- SimpleValidationResult(String error) {
+ SimpleValidationResult(String error, ErrorLevel errorLevel) {
+ if (error != null && errorLevel == null) {
+ throw new IllegalStateException("ValidationResult has an "
+ + "error message, but no ErrorLevel is provided.");
+ }
this.error = error;
+ this.errorLevel = errorLevel;
}
@Override
public String getErrorMessage() {
- if (error == null) {
+ if (!getErrorLevel().isPresent()) {
throw new IllegalStateException("The result is not an error. "
+ "It cannot contain error message");
} else {
- return error;
+ return error != null ? error : "";
}
}
- @Override
- public boolean isError() {
- return error != null;
+ public Optional<ErrorLevel> getErrorLevel() {
+ return Optional.ofNullable(errorLevel);
}
-
}
/**
@@ -69,12 +76,36 @@ public interface ValidationResult extends Serializable {
String getErrorMessage();
/**
+ * Returns optional error level for this validation result. Error level is
+ * not present for successful validation results.
+ * <p>
+ * <strong>Note:</strong> By default {@link ErrorLevel#INFO} and
+ * {@link ErrorLevel#WARNING} are not considered to be blocking the
+ * validation and conversion chain.
+ *
+ * @see #isError()
+ *
+ * @return optional error level; error level is present for validation
+ * results that have not passed validation
+ *
+ * @since 8.2
+ */
+ Optional<ErrorLevel> getErrorLevel();
+
+ /**
* Checks if the result denotes an error.
+ * <p>
+ * <strong>Note:</strong> By default {@link ErrorLevel#INFO} and
+ * {@link ErrorLevel#WARNING} are not considered to be errors.
*
* @return <code>true</code> if the result denotes an error,
* <code>false</code> otherwise
*/
- boolean isError();
+ default boolean isError() {
+ ErrorLevel errorLevel = getErrorLevel().orElse(null);
+ return errorLevel != null && errorLevel != ErrorLevel.INFO
+ && errorLevel != ErrorLevel.WARNING;
+ }
/**
* Returns a successful result.
@@ -82,7 +113,7 @@ public interface ValidationResult extends Serializable {
* @return the successful result
*/
public static ValidationResult ok() {
- return new SimpleValidationResult(null);
+ return new SimpleValidationResult(null, null);
}
/**
@@ -98,6 +129,32 @@ public interface ValidationResult extends Serializable {
*/
public static ValidationResult error(String errorMessage) {
Objects.requireNonNull(errorMessage);
- return new SimpleValidationResult(errorMessage);
+ return create(errorMessage, ErrorLevel.ERROR);
+ }
+
+ /**
+ * Creates the validation result with the given {@code errorMessage} and
+ * {@code errorLevel}. Results with {@link ErrorLevel} of {@code INFO} or
+ * {@code WARNING} are not errors by default.
+ *
+ * @see #ok()
+ * @see #error(String)
+ *
+ * @param errorMessage
+ * error message, not {@code null}
+ * @param errorLevel
+ * error level, not {@code null}
+ * @return validation result with the given {@code errorMessage} and
+ * {@code errorLevel}
+ * @throws NullPointerException
+ * if {@code errorMessage} or {@code errorLevel} is {@code null}
+ *
+ * @since 8.2
+ */
+ public static ValidationResult create(String errorMessage,
+ ErrorLevel errorLevel) {
+ Objects.requireNonNull(errorMessage);
+ Objects.requireNonNull(errorLevel);
+ return new SimpleValidationResult(errorMessage, errorLevel);
}
}
diff --git a/server/src/main/java/com/vaadin/data/ValidationResultWrap.java b/server/src/main/java/com/vaadin/data/ValidationResultWrap.java
new file mode 100644
index 0000000000..71bb475686
--- /dev/null
+++ b/server/src/main/java/com/vaadin/data/ValidationResultWrap.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2000-2016 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.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import com.vaadin.server.SerializableConsumer;
+import com.vaadin.server.SerializableFunction;
+
+/**
+ * Internal implementation of a {@code Result} that collects all possible
+ * ValidationResults into one list. This class intercepts the normal chaining of
+ * Converters and Validators, catching and collecting results.
+ *
+ * @param <R>
+ * the result data type
+ *
+ * @since 8.2
+ */
+class ValidationResultWrap<R> implements Result<R> {
+
+ private final List<ValidationResult> resultList;
+ private final Result<R> wrappedResult;
+
+ ValidationResultWrap(Result<R> result, List<ValidationResult> resultList) {
+ this.resultList = resultList;
+ this.wrappedResult = result;
+ }
+
+ ValidationResultWrap(R value, ValidationResult result) {
+ if (result.isError()) {
+ wrappedResult = new SimpleResult<>(null, result.getErrorMessage());
+ } else {
+ wrappedResult = new SimpleResult<>(value, null);
+ }
+ this.resultList = new ArrayList<>();
+ this.resultList.add(result);
+ }
+
+ List<ValidationResult> getValidationResults() {
+ return Collections.unmodifiableList(resultList);
+ }
+
+ Result<R> getWrappedResult() {
+ return wrappedResult;
+ }
+
+ @Override
+ public <S> Result<S> flatMap(SerializableFunction<R, Result<S>> mapper) {
+ Result<S> result = wrappedResult.flatMap(mapper);
+ if (!(result instanceof ValidationResultWrap)) {
+ return new ValidationResultWrap<S>(result, resultList);
+ }
+
+ List<ValidationResult> currentResults = new ArrayList<>(resultList);
+ ValidationResultWrap<S> resultWrap = (ValidationResultWrap<S>) result;
+ currentResults.addAll(resultWrap.getValidationResults());
+
+ return new ValidationResultWrap<>(resultWrap.getWrappedResult(),
+ currentResults);
+ }
+
+ @Override
+ public void handle(SerializableConsumer<R> ifOk,
+ SerializableConsumer<String> ifError) {
+ wrappedResult.handle(ifOk, ifError);
+ }
+
+ @Override
+ public boolean isError() {
+ return wrappedResult.isError();
+ }
+
+ @Override
+ public Optional<String> getMessage() {
+ return wrappedResult.getMessage();
+ }
+
+ @Override
+ public <X extends Throwable> R getOrThrow(
+ SerializableFunction<String, ? extends X> exceptionProvider)
+ throws X {
+ return wrappedResult.getOrThrow(exceptionProvider);
+ }
+
+}
diff --git a/server/src/main/java/com/vaadin/data/Validator.java b/server/src/main/java/com/vaadin/data/Validator.java
index 30d6976bde..4f8f4dc8ca 100644
--- a/server/src/main/java/com/vaadin/data/Validator.java
+++ b/server/src/main/java/com/vaadin/data/Validator.java
@@ -21,6 +21,7 @@ import java.util.Objects;
import java.util.function.BiFunction;
import com.vaadin.server.SerializablePredicate;
+import com.vaadin.shared.ui.ErrorLevel;
/**
* A functional interface for validating user input or other potentially invalid
@@ -80,8 +81,8 @@ public interface Validator<T>
* Builds a validator out of a conditional function and an error message. If
* the function returns true, the validator returns {@code Result.ok()}; if
* it returns false or throws an exception,
- * {@link ValidationResult#error(String)} is returned with the given
- * message.
+ * {@link ValidationResult#error(String)} is returned with the given message
+ * and error level {@link ErrorLevel#ERROR}.
* <p>
* For instance, the following validator checks if a number is between 0 and
* 10, inclusive:
@@ -101,12 +102,44 @@ public interface Validator<T>
*/
public static <T> Validator<T> from(SerializablePredicate<T> guard,
String errorMessage) {
- Objects.requireNonNull(guard, "guard cannot be null");
Objects.requireNonNull(errorMessage, "errorMessage cannot be null");
return from(guard, ctx -> errorMessage);
}
/**
+ * Builds a validator out of a conditional function and an error message. If
+ * the function returns true, the validator returns {@code Result.ok()}; if
+ * it returns false or throws an exception,
+ * {@link ValidationResult#error(String)} is returned with the given message
+ * and error level.
+ * <p>
+ * For instance, the following validator checks if a number is between 0 and
+ * 10, inclusive:
+ *
+ * <pre>
+ * Validator&lt;Integer&gt; v = Validator.from(num -&gt; num &gt;= 0 && num &lt;= 10,
+ * "number must be between 0 and 10", ErrorLevel.ERROR);
+ * </pre>
+ *
+ * @param <T>
+ * the value type
+ * @param guard
+ * the function used to validate, not null
+ * @param errorMessage
+ * the message returned if validation fails, not null
+ * @param errorLevel
+ * the error level for failures from this validator, not null
+ * @return the new validator using the function
+ *
+ * @since 8.2
+ */
+ public static <T> Validator<T> from(SerializablePredicate<T> guard,
+ String errorMessage, ErrorLevel errorLevel) {
+ Objects.requireNonNull(errorMessage, "errorMessage cannot be null");
+ return from(guard, ctx -> errorMessage, errorLevel);
+ }
+
+ /**
* Builds a validator out of a conditional function and an error message
* provider. If the function returns true, the validator returns
* {@code Result.ok()}; if it returns false or throws an exception,
@@ -122,20 +155,44 @@ public interface Validator<T>
*/
public static <T> Validator<T> from(SerializablePredicate<T> guard,
ErrorMessageProvider errorMessageProvider) {
+ return from(guard, errorMessageProvider, ErrorLevel.ERROR);
+ }
+
+ /**
+ * Builds a validator out of a conditional function and an error message
+ * provider. If the function returns true, the validator returns
+ * {@code Result.ok()}; if it returns false or throws an exception,
+ * {@code Result.error()} is returned with the message from the provider.
+ *
+ * @param <T>
+ * the value type
+ * @param guard
+ * the function used to validate, not null
+ * @param errorMessageProvider
+ * the provider to generate error messages, not null
+ * @param errorLevel
+ * the error level for failures from this validator, not null
+ * @return the new validator using the function
+ *
+ * @since 8.2
+ */
+ public static <T> Validator<T> from(SerializablePredicate<T> guard,
+ ErrorMessageProvider errorMessageProvider, ErrorLevel errorLevel) {
Objects.requireNonNull(guard, "guard cannot be null");
Objects.requireNonNull(errorMessageProvider,
"errorMessageProvider cannot be null");
+ Objects.requireNonNull(errorLevel, "errorLevel cannot be null");
return (value, context) -> {
try {
if (guard.test(value)) {
return ValidationResult.ok();
} else {
- return ValidationResult
- .error(errorMessageProvider.apply(context));
+ return ValidationResult.create(
+ errorMessageProvider.apply(context), errorLevel);
}
} catch (Exception e) {
- return ValidationResult
- .error(errorMessageProvider.apply(context));
+ return ValidationResult.create(
+ errorMessageProvider.apply(context), errorLevel);
}
};
}
diff --git a/server/src/test/java/com/vaadin/data/BinderTest.java b/server/src/test/java/com/vaadin/data/BinderTest.java
index a44e3b3e06..032ce99580 100644
--- a/server/src/test/java/com/vaadin/data/BinderTest.java
+++ b/server/src/test/java/com/vaadin/data/BinderTest.java
@@ -14,6 +14,7 @@ import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -24,6 +25,7 @@ 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.shared.ui.ErrorLevel;
import com.vaadin.tests.data.bean.Person;
import com.vaadin.tests.data.bean.Sex;
import com.vaadin.ui.TextField;
@@ -943,6 +945,24 @@ public class BinderTest extends BinderTestBase<Binder<Person>, Person> {
}
@Test
+ public void info_validator_not_considered_error() {
+ String infoMessage = "Young";
+ binder.forField(ageField)
+ .withConverter(new StringToIntegerConverter("Can't convert"))
+ .withValidator(i -> i > 5, infoMessage, ErrorLevel.INFO)
+ .bind(Person::getAge, Person::setAge);
+
+ binder.setBean(item);
+ ageField.setValue("3");
+ Assert.assertEquals(infoMessage,
+ ageField.getComponentError().getFormattedHtmlMessage());
+ Assert.assertEquals(ErrorLevel.INFO,
+ ageField.getComponentError().getErrorLevel());
+
+ Assert.assertEquals(3, item.getAge());
+ }
+
+ @Test
public void two_asRequired_fields_without_initial_values() {
binder.forField(nameField).asRequired("Empty name").bind(p -> "",
(p, s) -> {