* property. If any validator returns a failure, the property value is
* not updated.
*
+ * @see #withValidator(SerializablePredicate, String)
+ * @see #withValidator(SerializablePredicate, ErrorMessageProvider)
+ *
* @param validator
* the validator to add, not null
* @return this binding, for chaining
* failure, the property value is not updated.
*
* @see #withValidator(Validator)
+ * @see #withValidator(SerializablePredicate, ErrorMessageProvider)
* @see Validator#from(SerializablePredicate, String)
*
* @param predicate
return withValidator(Validator.from(predicate, message));
}
+ /**
+ * A convenience method to add a validator to this binding using the
+ * {@link Validator#from(SerializablePredicate, ErrorMessageProvider)}
+ * 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 Validator#from(SerializablePredicate, ErrorMessageProvider)
+ *
+ * @param predicate
+ * the predicate performing validation, not null
+ * @param errorMessageProvider
+ * the provider to generate error messages, not null
+ * @return this binding, for chaining
+ * @throws IllegalStateException
+ * if {@code bind} has already been called
+ */
+ public default Binding<BEAN, FIELDVALUE, TARGET> withValidator(
+ SerializablePredicate<? super TARGET> predicate,
+ ErrorMessageProvider errorMessageProvider) {
+ return withValidator(
+ Validator.from(predicate, errorMessageProvider));
+ }
+
/**
* Maps the binding to another data type using the given
* {@link Converter}.
*
* @see #writeBean(Object)
* @see #writeBeanIfValid(Object)
+ * @see #withValidator(SerializablePredicate, String)
+ * @see #withValidator(SerializablePredicate, ErrorMessageProvider)
*
* @param validator
* the validator to add, not null
* updated. If the validators fail, the bean instance is reverted to its
* previous state.
*
- * @see #save(Object)
- * @see #saveIfValid(Object)
+ * @see #writeBean(Object)
+ * @see #writeBeanIfValid(Object)
+ * @see #withValidator(Validator)
+ * @see #withValidator(SerializablePredicate, ErrorMessageProvider)
*
* @param predicate
* the predicate performing validation, not null
return withValidator(Validator.from(predicate, message));
}
+ /**
+ * A convenience method to add a validator to this binder using the
+ * {@link Validator#from(SerializablePredicate, ErrorMessageProvider)}
+ * factory method.
+ * <p>
+ * Bean level validators are applied on the bean instance after the bean is
+ * updated. If the validators fail, the bean instance is reverted to its
+ * previous state.
+ *
+ * @see #writeBean(Object)
+ * @see #writeBeanIfValid(Object)
+ * @see #withValidator(Validator)
+ * @see #withValidator(SerializablePredicate, String)
+ *
+ * @param predicate
+ * the predicate performing validation, not null
+ * @param errorMessageProvider
+ * the provider to generate error messages, not null
+ * @return this binder, for chaining
+ */
+ public Binder<BEAN> withValidator(SerializablePredicate<BEAN> predicate,
+ ErrorMessageProvider errorMessageProvider) {
+ return withValidator(Validator.from(predicate, errorMessageProvider));
+ }
+
/**
* Validates the values of all bound fields and returns the validation
* status.
--- /dev/null
+/*
+ * 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 com.vaadin.data.util.converter.ValueContext;
+import com.vaadin.server.SerializableFunction;
+
+/**
+ * Provider interface for generating localizable error messages using
+ * {@link ValueContext}.
+ *
+ * @since
+ * @author Vaadin Ltd.
+ */
+@FunctionalInterface
+public interface ErrorMessageProvider
+ extends SerializableFunction<ValueContext, String> {
+
+ /**
+ * Returns a generated error message for given {@code ValueContext}.
+ *
+ * @param context
+ * the value context
+ *
+ * @return generated error message
+ */
+ @Override
+ public String apply(ValueContext context);
+}
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
+ * 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
+ * @return the new validator using the function
+ */
+ public static <T> Validator<T> from(SerializablePredicate<T> guard,
+ ErrorMessageProvider errorMessageProvider) {
+ Objects.requireNonNull(guard, "guard cannot be null");
+ Objects.requireNonNull(errorMessageProvider,
+ "errorMessageProvider cannot be null");
return (value, context) -> {
try {
if (guard.test(value)) {
return Result.ok(value);
} else {
- return Result.error(errorMessage);
+ return Result.error(errorMessageProvider.apply(context));
}
} catch (Exception e) {
- return Result.error(errorMessage);
+ return Result.error(errorMessageProvider.apply(context));
}
};
}
*/
package com.vaadin.data;
+import java.util.Locale;
import java.util.Objects;
import org.junit.Assert;
import org.junit.Test;
import com.vaadin.data.util.converter.ValueContext;
+import com.vaadin.data.validator.ValidatorTestBase;
/**
* @author Vaadin Ltd
*
*/
-public class ValidatorTest {
+public class ValidatorTest extends ValidatorTestBase {
@Test
public void alwaysPass() {
result = validator.apply("", new ValueContext());
Assert.assertFalse(result.isError());
}
+
+ @Test
+ public void withValidator_customErrorMessageProvider() {
+ String finnishError = "Käyttäjän tulee olla täysi-ikäinen";
+ String englishError = "The user must be an adult";
+ String notTranslatableError = "NOT TRANSLATABLE";
+
+ Validator<Integer> ageValidator = Validator.from(age -> age >= 18,
+ ctx -> {
+ Locale locale = ctx.getLocale().orElse(Locale.ENGLISH);
+
+ if (locale.getLanguage().equals("fi")) {
+ return finnishError;
+ } else if (locale.getLanguage().equals("en")) {
+ return englishError;
+ }
+ return notTranslatableError;
+ });
+
+ setLocale(Locale.ENGLISH);
+ assertFails(17, englishError, ageValidator);
+ setLocale(new Locale("fi", "FI"));
+ assertFails(17, finnishError, ageValidator);
+ setLocale(Locale.GERMAN);
+ assertFails(17, notTranslatableError, ageValidator);
+ }
}
package com.vaadin.data.validator;
+import java.util.Locale;
+
import org.junit.Assert;
+import org.junit.Before;
import com.vaadin.data.Validator;
import com.vaadin.data.util.converter.ValueContext;
+import com.vaadin.ui.Label;
public class ValidatorTestBase {
+ private Label localeContext;
+
+ @Before
+ public void setUp() {
+ localeContext = new Label();
+ }
+
protected <T> void assertPasses(T value, Validator<? super T> v) {
v.apply(value, new ValueContext())
.handle(val -> Assert.assertEquals(value, val), err -> Assert
protected <T> void assertFails(T value, String errorMessage,
Validator<? super T> v) {
- v.apply(value, new ValueContext()).handle(
+ v.apply(value, new ValueContext(localeContext)).handle(
val -> Assert.fail(value + " should fail " + v),
err -> Assert.assertEquals(errorMessage, err));
}
protected <T> void assertFails(T value, AbstractValidator<? super T> v) {
assertFails(value, v.getMessage(value), v);
}
-}
+
+ protected void setLocale(Locale locale) {
+ localeContext.setLocale(locale);
+ }
+}
\ No newline at end of file