From 2cb106ce095edd5fc8a72b38a856c76ece05684e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pekka=20Hyv=C3=B6nen?= Date: Tue, 1 Nov 2016 11:53:44 +0200 Subject: [PATCH] Add Bindinding.setRequired Shorthand for making field show required indicator and validating against empty. Removes obsolete NotNullValidator and NotEmptyValidator. Latter is still used in some tests, that why it is still in test packages. Fixes vaadin/framework8-issues#29 Change-Id: Ib116739a20a0bbd1b1460423ee36ed2752c5496a --- .../src/main/java/com/vaadin/data/Binder.java | 52 ++++++++++++++ .../data/validator/NotNullValidator.java | 50 -------------- .../test/java/com/vaadin/data/BinderTest.java | 68 ++++++++++++++++++- .../data/validator/BeanValidatorTest.java | 6 ++ .../data/validator/NotEmptyValidator.java | 26 +++---- .../data/validator/NotNullValidatorTest.java | 42 ------------ 6 files changed, 132 insertions(+), 112 deletions(-) delete mode 100644 server/src/main/java/com/vaadin/data/validator/NotNullValidator.java rename server/src/{main => test}/java/com/vaadin/data/validator/NotEmptyValidator.java (69%) delete mode 100644 server/src/test/java/com/vaadin/data/validator/NotNullValidatorTest.java diff --git a/server/src/main/java/com/vaadin/data/Binder.java b/server/src/main/java/com/vaadin/data/Binder.java index f8ddace8a6..7912a55d72 100644 --- a/server/src/main/java/com/vaadin/data/Binder.java +++ b/server/src/main/java/com/vaadin/data/Binder.java @@ -422,6 +422,47 @@ public class Binder implements Serializable { */ public ValidationStatus validate(); + /** + * Sets the field to be required. This means two things: + *
    + *
  1. the required indicator is visible
  2. + *
  3. the field value is validated for not being empty*
  4. + *
+ * For localizing the error message, use + * {@link #setRequired(SerializableFunction)}. + *

+ * *Value not being the equal to what {@link HasValue#getEmptyValue()} + * returns. + * + * @see #setRequired(SerializableFunction) + * @see HasValue#setRequiredIndicatorVisible(boolean) + * @see HasValue#isEmpty() + * @param errorMessage + * the error message to show for the invalid value + * @return this binding, for chaining + */ + public default Binding setRequired( + String errorMessage) { + return setRequired(context -> errorMessage); + } + + /** + * Sets the field to be required. This means two things: + *

    + *
  1. the required indicator is visible
  2. + *
  3. the field value is validated for not being empty*
  4. + *
+ * *Value not being the equal to what {@link HasValue#getEmptyValue()} + * returns. + * + * @see HasValue#setRequiredIndicatorVisible(boolean) + * @see HasValue#isEmpty() + * @param errorMessageProvider + * the provider for localized validation error message + * @return this binding, for chaining + */ + public Binding setRequired( + ErrorMessageProvider errorMessageProvider); } /** @@ -521,6 +562,17 @@ public class Binder implements Serializable { return this; } + @Override + public Binding setRequired( + ErrorMessageProvider errorMessageProvider) { + checkUnbound(); + + getField().setRequiredIndicatorVisible(true); + return withValidator( + value -> !Objects.equals(value, getField().getEmptyValue()), + errorMessageProvider); + } + @Override public HasValue getField() { return field; diff --git a/server/src/main/java/com/vaadin/data/validator/NotNullValidator.java b/server/src/main/java/com/vaadin/data/validator/NotNullValidator.java deleted file mode 100644 index c92aefac3b..0000000000 --- a/server/src/main/java/com/vaadin/data/validator/NotNullValidator.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.validator; - -import java.util.Objects; - -import com.vaadin.data.ValidationResult; -import com.vaadin.data.util.converter.ValueContext; - -/** - * This validator is used for validating properties that do not allow null - * values. - * - * @author Vaadin Ltd. - * @since 8.0 - */ -@SuppressWarnings("serial") -public class NotNullValidator extends AbstractValidator { - - /** - * Creates a new NullValidator. - * - * @param errorMessage - * the error message to display on invalidation. - */ - public NotNullValidator(String errorMessage) { - super(errorMessage); - } - - @Override - public ValidationResult apply(String value, ValueContext context) { - return Objects.isNull(value) ? ValidationResult.error(getMessage(value)) - : ValidationResult.ok(); - } - -} diff --git a/server/src/test/java/com/vaadin/data/BinderTest.java b/server/src/test/java/com/vaadin/data/BinderTest.java index 6d33ab437b..22af7d2272 100644 --- a/server/src/test/java/com/vaadin/data/BinderTest.java +++ b/server/src/test/java/com/vaadin/data/BinderTest.java @@ -5,14 +5,18 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import java.util.Locale; import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import com.vaadin.data.Binder.Binding; import com.vaadin.data.util.converter.StringToIntegerConverter; -import com.vaadin.data.validator.NotNullValidator; +import com.vaadin.data.validator.NotEmptyValidator; +import com.vaadin.server.ErrorMessage; import com.vaadin.tests.data.bean.Person; import com.vaadin.tests.data.bean.Sex; import com.vaadin.ui.TextField; @@ -310,7 +314,7 @@ public class BinderTest extends BinderTestBase, Person> { public void withValidator_doesNotDisablesDefaulNullRepresentation() { String nullRepresentation = "foo"; binder.forField(nameField).withNullRepresentation(nullRepresentation) - .withValidator(new NotNullValidator("")) + .withValidator(new NotEmptyValidator<>("")) .bind(Person::getFirstName, Person::setFirstName); item.setFirstName(null); binder.setBean(item); @@ -321,4 +325,64 @@ public class BinderTest extends BinderTestBase, Person> { nameField.setValue(newValue); Assert.assertEquals(newValue, item.getFirstName()); } + + @Test + public void setRequired_withErrorMessage_fieldGetsRequiredIndicatorAndValidator() { + TextField textField = new TextField(); + Assert.assertFalse(textField.isRequiredIndicatorVisible()); + + Binding binding = binder.forField(textField); + Assert.assertFalse(textField.isRequiredIndicatorVisible()); + + binding.setRequired("foobar"); + Assert.assertTrue(textField.isRequiredIndicatorVisible()); + + binding.bind(Person::getFirstName, Person::setFirstName); + binder.setBean(item); + Assert.assertNull(textField.getErrorMessage()); + + textField.setValue(textField.getEmptyValue()); + ErrorMessage errorMessage = textField.getErrorMessage(); + Assert.assertNotNull(errorMessage); + Assert.assertEquals("foobar", errorMessage.getFormattedHtmlMessage()); + + textField.setValue("value"); + Assert.assertNull(textField.getErrorMessage()); + Assert.assertTrue(textField.isRequiredIndicatorVisible()); + } + + @Test + public void setRequired_withErrorMessageProvider_fieldGetsRequiredIndicatorAndValidator() { + TextField textField = new TextField(); + textField.setLocale(Locale.CANADA); + Assert.assertFalse(textField.isRequiredIndicatorVisible()); + + Binding binding = binder.forField(textField); + Assert.assertFalse(textField.isRequiredIndicatorVisible()); + AtomicInteger invokes = new AtomicInteger(); + + binding.setRequired(context -> { + invokes.incrementAndGet(); + Assert.assertSame(Locale.CANADA, context.getLocale().get()); + return "foobar"; + }); + Assert.assertTrue(textField.isRequiredIndicatorVisible()); + + binding.bind(Person::getFirstName, Person::setFirstName); + binder.setBean(item); + Assert.assertNull(textField.getErrorMessage()); + Assert.assertEquals(0, invokes.get()); + + textField.setValue(textField.getEmptyValue()); + ErrorMessage errorMessage = textField.getErrorMessage(); + Assert.assertNotNull(errorMessage); + Assert.assertEquals("foobar", errorMessage.getFormattedHtmlMessage()); + // validation is run twice, once for the field, then for all the fields + // for cross field validation... + Assert.assertEquals(2, invokes.get()); + + textField.setValue("value"); + Assert.assertNull(textField.getErrorMessage()); + Assert.assertTrue(textField.isRequiredIndicatorVisible()); + } } \ No newline at end of file diff --git a/server/src/test/java/com/vaadin/data/validator/BeanValidatorTest.java b/server/src/test/java/com/vaadin/data/validator/BeanValidatorTest.java index fb504eea65..97f767bbc7 100644 --- a/server/src/test/java/com/vaadin/data/validator/BeanValidatorTest.java +++ b/server/src/test/java/com/vaadin/data/validator/BeanValidatorTest.java @@ -3,6 +3,7 @@ package com.vaadin.data.validator; import java.util.Calendar; import java.util.Locale; +import org.junit.After; import org.junit.Test; import com.vaadin.tests.data.bean.Address; @@ -77,6 +78,11 @@ public class BeanValidatorTest extends ValidatorTestBase { assertPasses(null, validator("nickname")); } + @After + public void tearDown() { + UI.setCurrent(null); + } + private BeanValidator validator(String propertyName) { return new BeanValidator(BeanToValidate.class, propertyName); } diff --git a/server/src/main/java/com/vaadin/data/validator/NotEmptyValidator.java b/server/src/test/java/com/vaadin/data/validator/NotEmptyValidator.java similarity index 69% rename from server/src/main/java/com/vaadin/data/validator/NotEmptyValidator.java rename to server/src/test/java/com/vaadin/data/validator/NotEmptyValidator.java index 2223c333cb..61cacf8b51 100644 --- a/server/src/main/java/com/vaadin/data/validator/NotEmptyValidator.java +++ b/server/src/test/java/com/vaadin/data/validator/NotEmptyValidator.java @@ -17,6 +17,7 @@ package com.vaadin.data.validator; import java.util.Objects; +import com.vaadin.data.Binder.Binding; import com.vaadin.data.HasValue; import com.vaadin.data.ValidationResult; import com.vaadin.data.Validator; @@ -29,27 +30,16 @@ import com.vaadin.data.util.converter.ValueContext; * This validator works similar to {@link NotNullValidator} but in addition it * also check whether the value is not an empty String. *

- * The main purpose of this validator is its usage with {@link HasRequired} - * field instances. + * This validator can be suitable for fields that have been marked as required + * with {@link HasValue#setRequiredIndicatorVisible(boolean)}. *

- * If the field is required, it is visually indicated in the user interface. - * Furthermore, required fields requires "non-empty" validator. So in addition - * to call {@link HasRequired#setRequiredIndicatorVisible(boolean)} method one - * should add an instance of this validator explicitly so the code looks like - * this: - * - *

- * 
- * Binder binder = new Binder<>();
- * TextField name = new TextField();
- * name.setRequiredIndicatorVisible(true);
- * binder.forField(name).withValidator(
- *      new NonEmptyValidator("Name cannot be empty"))
- *              .bind(Bean::getName, Bean::setName);
- * 
- * 
+ * Note that {@link Binding#setRequired(com.vaadin.data.ErrorMessageProvider)} + * does almost the same thing, but verifies against the value NOT being equal to + * what {@link HasValue#getEmptyValue()} returns and sets the required indicator + * visible with {@link HasValue#setRequiredIndicatorVisible(boolean)}. * * @see HasValue#setRequiredIndicatorVisible(boolean) + * @see Binding#setRequired(com.vaadin.data.ErrorMessageProvider) * @author Vaadin Ltd * @since 8.0 * diff --git a/server/src/test/java/com/vaadin/data/validator/NotNullValidatorTest.java b/server/src/test/java/com/vaadin/data/validator/NotNullValidatorTest.java deleted file mode 100644 index 24b95bf58a..0000000000 --- a/server/src/test/java/com/vaadin/data/validator/NotNullValidatorTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.validator; - -import org.junit.Assert; -import org.junit.Test; - -import com.vaadin.data.ValidationResult; -import com.vaadin.data.util.converter.ValueContext; - -public class NotNullValidatorTest { - - @Test - public void nullValueIsDisallowed() { - NotNullValidator validator = new NotNullValidator("foo"); - ValidationResult result = validator.apply(null, new ValueContext()); - Assert.assertTrue(result.isError()); - Assert.assertEquals("foo", result.getErrorMessage()); - } - - @Test - public void nonNullValueIsAllowed() { - NotNullValidator validator = new NotNullValidator("foo"); - ValidationResult result = validator.apply("bar", new ValueContext()); - Assert.assertFalse(result.isError()); - Assert.assertFalse(result.isError()); - } - -} -- 2.39.5