From 5f98afc180c86cf31b4484a6ed20d41eed2a3a34 Mon Sep 17 00:00:00 2001 From: Toshiaki Maki Date: Fri, 27 Jan 2023 15:43:06 +0900 Subject: [PATCH 1/2] Introduce functional factory methods in Validator This commit introduces `of` method in `Validator` to provide a way to create a validator for the specific type `` using `BiConsumer` and define the validator in a functional way. This also eliminates the boilerplate for implementing the `supports` method. --- .../springframework/validation/Validator.java | 41 ++++++++++++- .../validation/DataBinderTests.java | 37 ++++-------- .../validation/ValidationUtilsTests.java | 59 +++++-------------- 3 files changed, 65 insertions(+), 72 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/validation/Validator.java b/spring-context/src/main/java/org/springframework/validation/Validator.java index b67b6d5d8b..3ad6ade1b5 100644 --- a/spring-context/src/main/java/org/springframework/validation/Validator.java +++ b/spring-context/src/main/java/org/springframework/validation/Validator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,10 @@ package org.springframework.validation; +import java.util.function.BiConsumer; + +import org.springframework.util.Assert; + /** * A validator for application-specific objects. * @@ -59,6 +63,7 @@ package org.springframework.validation; * application. * * @author Rod Johnson + * @author Toshiaki Maki * @see SmartValidator * @see Errors * @see ValidationUtils @@ -92,4 +97,38 @@ public interface Validator { */ void validate(Object target, Errors errors); + /** + * Takes the {@link BiConsumer} containing the validation logic for the specific type + * <T> and returns the {@link Validator} instance.
+ * This validator implements the typical {@link #supports(Class)} method + * for the given <T>.
+ * + * By using this method, a {@link Validator} can be implemented as follows: + * + *
Validator passwordEqualsValidator = Validator.of(PasswordResetForm.class, (form, errors) -> {
+	 *       if (!Objects.equals(form.getPassword(), form.getConfirmPassword())) {
+	 *         errors.rejectValue("confirmPassword",
+	 *             "PasswordEqualsValidator.passwordResetForm.password",
+	 *             "password and confirm password must be same.");
+	 *       }
+	 *     });
+ * @param targetClass the class of the object that is to be validated + * @param delegate the validation logic to delegate for the specific type <T> + * @param the type of the object that is to be validated + * @return the {@link Validator} instance + */ + static Validator of(Class targetClass, BiConsumer delegate) { + Assert.notNull(targetClass, "'targetClass' must not be null."); + return new Validator() { + @Override + public boolean supports(Class clazz) { + return targetClass.isAssignableFrom(clazz); + } + + @Override + public void validate(Object target, Errors errors) { + delegate.accept(targetClass.cast(target), errors); + } + }; + } } diff --git a/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java b/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java index a990612917..1daf0d9191 100644 --- a/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java +++ b/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java @@ -82,6 +82,16 @@ import static org.assertj.core.api.Assertions.entry; */ class DataBinderTests { + Validator spouseValidator = Validator.of(TestBean.class, (tb, errors) -> { + if (tb == null || "XXX".equals(tb.getName())) { + errors.rejectValue("", "SPOUSE_NOT_AVAILABLE"); + return; + } + if (tb.getAge() < 32) { + errors.rejectValue("age", "TOO_YOUNG", "simply too young"); + } + }); + @Test void bindingNoErrors() throws BindException { TestBean rod = new TestBean(); @@ -1144,7 +1154,6 @@ class DataBinderTests { errors.setNestedPath("spouse"); assertThat(errors.getNestedPath()).isEqualTo("spouse."); assertThat(errors.getFieldValue("age")).isEqualTo("argh"); - Validator spouseValidator = new SpouseValidator(); spouseValidator.validate(tb.getSpouse(), errors); errors.setNestedPath(""); @@ -1195,7 +1204,6 @@ class DataBinderTests { errors.setNestedPath("spouse."); assertThat(errors.getNestedPath()).isEqualTo("spouse."); - Validator spouseValidator = new SpouseValidator(); spouseValidator.validate(tb.getSpouse(), errors); errors.setNestedPath(""); @@ -1267,7 +1275,6 @@ class DataBinderTests { errors.setNestedPath("spouse."); assertThat(errors.getNestedPath()).isEqualTo("spouse."); - Validator spouseValidator = new SpouseValidator(); spouseValidator.validate(tb.getSpouse(), errors); errors.setNestedPath(""); @@ -1332,7 +1339,6 @@ class DataBinderTests { testValidator.validate(tb, errors); errors.setNestedPath("spouse."); assertThat(errors.getNestedPath()).isEqualTo("spouse."); - Validator spouseValidator = new SpouseValidator(); spouseValidator.validate(tb.getSpouse(), errors); errors.setNestedPath(""); @@ -1348,7 +1354,6 @@ class DataBinderTests { TestBean tb = new TestBean(); tb.setName("XXX"); Errors errors = new BeanPropertyBindingResult(tb, "tb"); - Validator spouseValidator = new SpouseValidator(); spouseValidator.validate(tb, errors); assertThat(errors.hasGlobalErrors()).isTrue(); @@ -2160,28 +2165,6 @@ class DataBinderTests { } } - - private static class SpouseValidator implements Validator { - - @Override - public boolean supports(Class clazz) { - return TestBean.class.isAssignableFrom(clazz); - } - - @Override - public void validate(@Nullable Object obj, Errors errors) { - TestBean tb = (TestBean) obj; - if (tb == null || "XXX".equals(tb.getName())) { - errors.rejectValue("", "SPOUSE_NOT_AVAILABLE"); - return; - } - if (tb.getAge() < 32) { - errors.rejectValue("age", "TOO_YOUNG", "simply too young"); - } - } - } - - @SuppressWarnings("unused") private static class GrowingList extends AbstractList { diff --git a/spring-context/src/test/java/org/springframework/validation/ValidationUtilsTests.java b/spring-context/src/test/java/org/springframework/validation/ValidationUtilsTests.java index 0a027b95df..bec3ff28ef 100644 --- a/spring-context/src/test/java/org/springframework/validation/ValidationUtilsTests.java +++ b/spring-context/src/test/java/org/springframework/validation/ValidationUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ package org.springframework.validation; import org.junit.jupiter.api.Test; import org.springframework.beans.testfixture.beans.TestBean; -import org.springframework.lang.Nullable; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -34,6 +33,10 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException */ public class ValidationUtilsTests { + Validator emptyValidator = Validator.of(TestBean.class, (testBean, errors) -> ValidationUtils.rejectIfEmpty(errors, "name", "EMPTY", "You must enter a name!")); + + Validator emptyOrWhitespaceValidator = Validator.of(TestBean.class, (testBean, errors) -> ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "EMPTY_OR_WHITESPACE", "You must enter a name!")); + @Test public void testInvokeValidatorWithNullValidator() throws Exception { TestBean tb = new TestBean(); @@ -46,14 +49,14 @@ public class ValidationUtilsTests { public void testInvokeValidatorWithNullErrors() throws Exception { TestBean tb = new TestBean(); assertThatIllegalArgumentException().isThrownBy(() -> - ValidationUtils.invokeValidator(new EmptyValidator(), tb, null)); + ValidationUtils.invokeValidator(emptyValidator, tb, null)); } @Test public void testInvokeValidatorSunnyDay() throws Exception { TestBean tb = new TestBean(); Errors errors = new BeanPropertyBindingResult(tb, "tb"); - ValidationUtils.invokeValidator(new EmptyValidator(), tb, errors); + ValidationUtils.invokeValidator(emptyValidator, tb, errors); assertThat(errors.hasFieldErrors("name")).isTrue(); assertThat(errors.getFieldError("name").getCode()).isEqualTo("EMPTY"); } @@ -62,15 +65,14 @@ public class ValidationUtilsTests { public void testValidationUtilsSunnyDay() throws Exception { TestBean tb = new TestBean(""); - Validator testValidator = new EmptyValidator(); tb.setName(" "); Errors errors = new BeanPropertyBindingResult(tb, "tb"); - testValidator.validate(tb, errors); + emptyValidator.validate(tb, errors); assertThat(errors.hasFieldErrors("name")).isFalse(); tb.setName("Roddy"); errors = new BeanPropertyBindingResult(tb, "tb"); - testValidator.validate(tb, errors); + emptyValidator.validate(tb, errors); assertThat(errors.hasFieldErrors("name")).isFalse(); } @@ -78,8 +80,7 @@ public class ValidationUtilsTests { public void testValidationUtilsNull() throws Exception { TestBean tb = new TestBean(); Errors errors = new BeanPropertyBindingResult(tb, "tb"); - Validator testValidator = new EmptyValidator(); - testValidator.validate(tb, errors); + emptyValidator.validate(tb, errors); assertThat(errors.hasFieldErrors("name")).isTrue(); assertThat(errors.getFieldError("name").getCode()).isEqualTo("EMPTY"); } @@ -88,8 +89,7 @@ public class ValidationUtilsTests { public void testValidationUtilsEmpty() throws Exception { TestBean tb = new TestBean(""); Errors errors = new BeanPropertyBindingResult(tb, "tb"); - Validator testValidator = new EmptyValidator(); - testValidator.validate(tb, errors); + emptyValidator.validate(tb, errors); assertThat(errors.hasFieldErrors("name")).isTrue(); assertThat(errors.getFieldError("name").getCode()).isEqualTo("EMPTY"); } @@ -115,32 +115,31 @@ public class ValidationUtilsTests { @Test public void testValidationUtilsEmptyOrWhitespace() throws Exception { TestBean tb = new TestBean(); - Validator testValidator = new EmptyOrWhitespaceValidator(); // Test null Errors errors = new BeanPropertyBindingResult(tb, "tb"); - testValidator.validate(tb, errors); + emptyOrWhitespaceValidator.validate(tb, errors); assertThat(errors.hasFieldErrors("name")).isTrue(); assertThat(errors.getFieldError("name").getCode()).isEqualTo("EMPTY_OR_WHITESPACE"); // Test empty String tb.setName(""); errors = new BeanPropertyBindingResult(tb, "tb"); - testValidator.validate(tb, errors); + emptyOrWhitespaceValidator.validate(tb, errors); assertThat(errors.hasFieldErrors("name")).isTrue(); assertThat(errors.getFieldError("name").getCode()).isEqualTo("EMPTY_OR_WHITESPACE"); // Test whitespace String tb.setName(" "); errors = new BeanPropertyBindingResult(tb, "tb"); - testValidator.validate(tb, errors); + emptyOrWhitespaceValidator.validate(tb, errors); assertThat(errors.hasFieldErrors("name")).isTrue(); assertThat(errors.getFieldError("name").getCode()).isEqualTo("EMPTY_OR_WHITESPACE"); // Test OK tb.setName("Roddy"); errors = new BeanPropertyBindingResult(tb, "tb"); - testValidator.validate(tb, errors); + emptyOrWhitespaceValidator.validate(tb, errors); assertThat(errors.hasFieldErrors("name")).isFalse(); } @@ -163,32 +162,4 @@ public class ValidationUtilsTests { assertThat(errors.getFieldError("name").getDefaultMessage()).isEqualTo("msg"); } - - private static class EmptyValidator implements Validator { - - @Override - public boolean supports(Class clazz) { - return TestBean.class.isAssignableFrom(clazz); - } - - @Override - public void validate(@Nullable Object obj, Errors errors) { - ValidationUtils.rejectIfEmpty(errors, "name", "EMPTY", "You must enter a name!"); - } - } - - - private static class EmptyOrWhitespaceValidator implements Validator { - - @Override - public boolean supports(Class clazz) { - return TestBean.class.isAssignableFrom(clazz); - } - - @Override - public void validate(@Nullable Object obj, Errors errors) { - ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "EMPTY_OR_WHITESPACE", "You must enter a name!"); - } - } - } From 3c57d5518a31a1de791a81da33ee7157597951d7 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Wed, 19 Apr 2023 15:14:23 +0200 Subject: [PATCH 2/2] Polish contribution - Split Validator::of into two factory methods: - forInstanceOf using Class::isAssignableFrom - forType using Class::equals - Moved anonymous implementation into TypedValidator with default access Closes gh-30341 --- .../validation/TypedValidator.java | 63 +++++++++ .../springframework/validation/Validator.java | 123 +++++++++--------- .../validation/DataBinderTests.java | 2 +- .../validation/ValidationUtilsTests.java | 4 +- .../validation/ValidatorTests.java | 48 +++++++ 5 files changed, 179 insertions(+), 61 deletions(-) create mode 100644 spring-context/src/main/java/org/springframework/validation/TypedValidator.java create mode 100644 spring-context/src/test/java/org/springframework/validation/ValidatorTests.java diff --git a/spring-context/src/main/java/org/springframework/validation/TypedValidator.java b/spring-context/src/main/java/org/springframework/validation/TypedValidator.java new file mode 100644 index 0000000000..000e9389b1 --- /dev/null +++ b/spring-context/src/main/java/org/springframework/validation/TypedValidator.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2023 the original author or authors. + * + * 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 + * + * https://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 org.springframework.validation; + +import java.util.function.BiConsumer; +import java.util.function.Predicate; + +import org.springframework.util.Assert; + +/** + * Validator instance returned by {@link Validator#forInstanceOf(Class, BiConsumer)} + * and {@link Validator#forType(Class, BiConsumer)}. + * + * @author Toshiaki Maki + * @author Arjen Poutsma + * @since 6.1 + * @param the target object type + */ +final class TypedValidator implements Validator { + + private final Class targetClass; + + private final Predicate> supports; + + private final BiConsumer validate; + + + public TypedValidator(Class targetClass, Predicate> supports, BiConsumer validate) { + Assert.notNull(targetClass, "TargetClass must not be null"); + Assert.notNull(supports, "Supports function must not be null"); + Assert.notNull(validate, "Validate function must not be null"); + + this.targetClass = targetClass; + this.supports = supports; + this.validate = validate; + } + + + @Override + public boolean supports(Class clazz) { + return this.supports.test(clazz); + } + + @Override + public void validate(Object target, Errors errors) { + this.validate.accept(this.targetClass.cast(target), errors); + } + +} diff --git a/spring-context/src/main/java/org/springframework/validation/Validator.java b/spring-context/src/main/java/org/springframework/validation/Validator.java index 3ad6ade1b5..36ef7b3726 100644 --- a/spring-context/src/main/java/org/springframework/validation/Validator.java +++ b/spring-context/src/main/java/org/springframework/validation/Validator.java @@ -18,8 +18,6 @@ package org.springframework.validation; import java.util.function.BiConsumer; -import org.springframework.util.Assert; - /** * A validator for application-specific objects. * @@ -30,33 +28,25 @@ import org.springframework.util.Assert; * of an application, and supports the encapsulation of validation * logic as a first-class citizen in its own right. * - *

Find below a simple but complete {@code Validator} - * implementation, which validates that the various {@link String} - * properties of a {@code UserLogin} instance are not empty - * (that is they are not {@code null} and do not consist + *

Implementations can be created via the static factory methods + * {@link #forInstanceOf(Class, BiConsumer)} or + * {@link #forType(Class, BiConsumer)}. + * Below is a simple but complete {@code Validator} that validates that the + * various {@link String} properties of a {@code UserLogin} instance are not + * empty (they are not {@code null} and do not consist * wholly of whitespace), and that any password that is present is * at least {@code 'MINIMUM_PASSWORD_LENGTH'} characters in length. * - *

public class UserLoginValidator implements Validator {
- *
- *    private static final int MINIMUM_PASSWORD_LENGTH = 6;
- *
- *    public boolean supports(Class clazz) {
- *       return UserLogin.class.isAssignableFrom(clazz);
- *    }
- *
- *    public void validate(Object target, Errors errors) {
- *       ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "field.required");
- *       ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "field.required");
- *       UserLogin login = (UserLogin) target;
- *       if (login.getPassword() != null
- *             && login.getPassword().trim().length() < MINIMUM_PASSWORD_LENGTH) {
- *          errors.rejectValue("password", "field.min.length",
- *                new Object[]{Integer.valueOf(MINIMUM_PASSWORD_LENGTH)},
- *                "The password must be at least [" + MINIMUM_PASSWORD_LENGTH + "] characters in length.");
- *       }
- *    }
- * }
+ *
Validator userLoginValidator = Validator.forInstance(UserLogin.class, (login, errors) -> {
+ *   ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "field.required");
+ *   ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "field.required");
+ *   if (login.getPassword() != null
+ *         && login.getPassword().trim().length() < MINIMUM_PASSWORD_LENGTH) {
+ *      errors.rejectValue("password", "field.min.length",
+ *            new Object[]{Integer.valueOf(MINIMUM_PASSWORD_LENGTH)},
+ *            "The password must be at least [" + MINIMUM_PASSWORD_LENGTH + "] characters in length.");
+ *   }
+ * });
* *

See also the Spring reference manual for a fuller discussion of * the {@code Validator} interface and its role in an enterprise @@ -64,6 +54,7 @@ import org.springframework.util.Assert; * * @author Rod Johnson * @author Toshiaki Maki + * @author Arjen Poutsma * @see SmartValidator * @see Errors * @see ValidationUtils @@ -97,38 +88,54 @@ public interface Validator { */ void validate(Object target, Errors errors); - /** - * Takes the {@link BiConsumer} containing the validation logic for the specific type - * <T> and returns the {@link Validator} instance.
- * This validator implements the typical {@link #supports(Class)} method - * for the given <T>.
- * - * By using this method, a {@link Validator} can be implemented as follows: - * - *

Validator passwordEqualsValidator = Validator.of(PasswordResetForm.class, (form, errors) -> {
-	 *       if (!Objects.equals(form.getPassword(), form.getConfirmPassword())) {
-	 *         errors.rejectValue("confirmPassword",
-	 *             "PasswordEqualsValidator.passwordResetForm.password",
-	 *             "password and confirm password must be same.");
-	 *       }
-	 *     });
- * @param targetClass the class of the object that is to be validated - * @param delegate the validation logic to delegate for the specific type <T> - * @param the type of the object that is to be validated - * @return the {@link Validator} instance - */ - static Validator of(Class targetClass, BiConsumer delegate) { - Assert.notNull(targetClass, "'targetClass' must not be null."); - return new Validator() { - @Override - public boolean supports(Class clazz) { - return targetClass.isAssignableFrom(clazz); - } - @Override - public void validate(Object target, Errors errors) { - delegate.accept(targetClass.cast(target), errors); - } - }; + /** + * Return a {@code Validator} that checks whether the target object + * {@linkplain Class#isAssignableFrom(Class) is an instance of} + * {@code targetClass}, resorting to {@code delegate} to populate + * {@link Errors} if it is. + * + *

For instance: + *

Validator passwordEqualsValidator = Validator.forInstanceOf(PasswordResetForm.class, (form, errors) -> {
+	 *   if (!Objects.equals(form.getPassword(), form.getConfirmPassword())) {
+	 * 	   errors.rejectValue("confirmPassword",
+	 * 	         "PasswordEqualsValidator.passwordResetForm.password",
+	 * 	         "password and confirm password must be same.");
+	 * 	   }
+	 * 	 });
+ * @param targetClass the class supported by the returned validator + * @param delegate function invoked with the target object, if it is an + * instance of type T + * @param the target object type + * @return the created {@code Validator} + * @since 6.1 + */ + static Validator forInstanceOf(Class targetClass, BiConsumer delegate) { + return new TypedValidator<>(targetClass, targetClass::isAssignableFrom, delegate); } + + /** + * Return a {@code Validator} that checks whether the target object's class + * is identical to {@code targetClass}, resorting to {@code delegate} to + * populate {@link Errors} if it is. + * + *

For instance: + *

Validator passwordEqualsValidator = Validator.forType(PasswordResetForm.class, (form, errors) -> {
+	 *   if (!Objects.equals(form.getPassword(), form.getConfirmPassword())) {
+	 * 	   errors.rejectValue("confirmPassword",
+	 * 	         "PasswordEqualsValidator.passwordResetForm.password",
+	 * 	         "password and confirm password must be same.");
+	 * 	   }
+	 * 	 });
+ * @param targetClass the exact class supported by the returned validator (no subclasses) + * @param delegate function invoked with the target object, if it is an + * instance of type T + * @param the target object type + * @return the created {@code Validator} + * @since 6.1 + */ + static Validator forType(Class targetClass, BiConsumer delegate) { + return new TypedValidator<>(targetClass, targetClass::equals, delegate); + } + } diff --git a/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java b/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java index 1daf0d9191..e4c4ae97c1 100644 --- a/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java +++ b/spring-context/src/test/java/org/springframework/validation/DataBinderTests.java @@ -82,7 +82,7 @@ import static org.assertj.core.api.Assertions.entry; */ class DataBinderTests { - Validator spouseValidator = Validator.of(TestBean.class, (tb, errors) -> { + private final Validator spouseValidator = Validator.forInstanceOf(TestBean.class, (tb, errors) -> { if (tb == null || "XXX".equals(tb.getName())) { errors.rejectValue("", "SPOUSE_NOT_AVAILABLE"); return; diff --git a/spring-context/src/test/java/org/springframework/validation/ValidationUtilsTests.java b/spring-context/src/test/java/org/springframework/validation/ValidationUtilsTests.java index bec3ff28ef..09694c8e8b 100644 --- a/spring-context/src/test/java/org/springframework/validation/ValidationUtilsTests.java +++ b/spring-context/src/test/java/org/springframework/validation/ValidationUtilsTests.java @@ -33,9 +33,9 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException */ public class ValidationUtilsTests { - Validator emptyValidator = Validator.of(TestBean.class, (testBean, errors) -> ValidationUtils.rejectIfEmpty(errors, "name", "EMPTY", "You must enter a name!")); + private final Validator emptyValidator = Validator.forInstanceOf(TestBean.class, (testBean, errors) -> ValidationUtils.rejectIfEmpty(errors, "name", "EMPTY", "You must enter a name!")); - Validator emptyOrWhitespaceValidator = Validator.of(TestBean.class, (testBean, errors) -> ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "EMPTY_OR_WHITESPACE", "You must enter a name!")); + private final Validator emptyOrWhitespaceValidator = Validator.forInstanceOf(TestBean.class, (testBean, errors) -> ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "EMPTY_OR_WHITESPACE", "You must enter a name!")); @Test public void testInvokeValidatorWithNullValidator() throws Exception { diff --git a/spring-context/src/test/java/org/springframework/validation/ValidatorTests.java b/spring-context/src/test/java/org/springframework/validation/ValidatorTests.java new file mode 100644 index 0000000000..0827b85f85 --- /dev/null +++ b/spring-context/src/test/java/org/springframework/validation/ValidatorTests.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2023 the original author or authors. + * + * 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 + * + * https://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 org.springframework.validation; + +import org.junit.jupiter.api.Test; + +import org.springframework.beans.testfixture.beans.TestBean; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Arjen Poutsma + */ +class ValidatorTests { + + @Test + public void testSupportsForInstanceOf() { + Validator validator = Validator.forInstanceOf(TestBean.class, (testBean, errors) -> {}); + assertThat(validator.supports(TestBean.class)).isTrue(); + assertThat(validator.supports(TestBeanSubclass.class)).isTrue(); + } + + @Test + public void testSupportsForType() { + Validator validator = Validator.forType(TestBean.class, (testBean, errors) -> {}); + assertThat(validator.supports(TestBean.class)).isTrue(); + assertThat(validator.supports(TestBeanSubclass.class)).isFalse(); + } + + + private static class TestBeanSubclass extends TestBean { + } + +}