|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2021 the original author or authors. |
| 2 | + * Copyright 2002-2023 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
16 | 16 |
|
17 | 17 | package org.springframework.validation;
|
18 | 18 |
|
| 19 | +import java.util.function.BiConsumer; |
| 20 | + |
19 | 21 | /**
|
20 | 22 | * A validator for application-specific objects.
|
21 | 23 | *
|
|
26 | 28 | * of an application, and supports the encapsulation of validation
|
27 | 29 | * logic as a first-class citizen in its own right.
|
28 | 30 | *
|
29 |
| - * <p>Find below a simple but complete {@code Validator} |
30 |
| - * implementation, which validates that the various {@link String} |
31 |
| - * properties of a {@code UserLogin} instance are not empty |
32 |
| - * (that is they are not {@code null} and do not consist |
| 31 | + * <p>Implementations can be created via the static factory methods |
| 32 | + * {@link #forInstanceOf(Class, BiConsumer)} or |
| 33 | + * {@link #forType(Class, BiConsumer)}. |
| 34 | + * Below is a simple but complete {@code Validator} that validates that the |
| 35 | + * various {@link String} properties of a {@code UserLogin} instance are not |
| 36 | + * empty (they are not {@code null} and do not consist |
33 | 37 | * wholly of whitespace), and that any password that is present is
|
34 | 38 | * at least {@code 'MINIMUM_PASSWORD_LENGTH'} characters in length.
|
35 | 39 | *
|
36 |
| - * <pre class="code">public class UserLoginValidator implements Validator { |
37 |
| - * |
38 |
| - * private static final int MINIMUM_PASSWORD_LENGTH = 6; |
39 |
| - * |
40 |
| - * public boolean supports(Class clazz) { |
41 |
| - * return UserLogin.class.isAssignableFrom(clazz); |
42 |
| - * } |
43 |
| - * |
44 |
| - * public void validate(Object target, Errors errors) { |
45 |
| - * ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "field.required"); |
46 |
| - * ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "field.required"); |
47 |
| - * UserLogin login = (UserLogin) target; |
48 |
| - * if (login.getPassword() != null |
49 |
| - * && login.getPassword().trim().length() < MINIMUM_PASSWORD_LENGTH) { |
50 |
| - * errors.rejectValue("password", "field.min.length", |
51 |
| - * new Object[]{Integer.valueOf(MINIMUM_PASSWORD_LENGTH)}, |
52 |
| - * "The password must be at least [" + MINIMUM_PASSWORD_LENGTH + "] characters in length."); |
53 |
| - * } |
54 |
| - * } |
55 |
| - * }</pre> |
| 40 | + * <pre class="code">Validator userLoginValidator = Validator.forInstance(UserLogin.class, (login, errors) -> { |
| 41 | + * ValidationUtils.rejectIfEmptyOrWhitespace(errors, "userName", "field.required"); |
| 42 | + * ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "field.required"); |
| 43 | + * if (login.getPassword() != null |
| 44 | + * && login.getPassword().trim().length() < MINIMUM_PASSWORD_LENGTH) { |
| 45 | + * errors.rejectValue("password", "field.min.length", |
| 46 | + * new Object[]{Integer.valueOf(MINIMUM_PASSWORD_LENGTH)}, |
| 47 | + * "The password must be at least [" + MINIMUM_PASSWORD_LENGTH + "] characters in length."); |
| 48 | + * } |
| 49 | + * });</pre> |
56 | 50 | *
|
57 | 51 | * <p>See also the Spring reference manual for a fuller discussion of
|
58 | 52 | * the {@code Validator} interface and its role in an enterprise
|
59 | 53 | * application.
|
60 | 54 | *
|
61 | 55 | * @author Rod Johnson
|
| 56 | + * @author Toshiaki Maki |
| 57 | + * @author Arjen Poutsma |
62 | 58 | * @see SmartValidator
|
63 | 59 | * @see Errors
|
64 | 60 | * @see ValidationUtils
|
@@ -92,4 +88,54 @@ public interface Validator {
|
92 | 88 | */
|
93 | 89 | void validate(Object target, Errors errors);
|
94 | 90 |
|
| 91 | + |
| 92 | + /** |
| 93 | + * Return a {@code Validator} that checks whether the target object |
| 94 | + * {@linkplain Class#isAssignableFrom(Class) is an instance of} |
| 95 | + * {@code targetClass}, resorting to {@code delegate} to populate |
| 96 | + * {@link Errors} if it is. |
| 97 | + * |
| 98 | + * <p>For instance: |
| 99 | + * <pre class="code">Validator passwordEqualsValidator = Validator.forInstanceOf(PasswordResetForm.class, (form, errors) -> { |
| 100 | + * if (!Objects.equals(form.getPassword(), form.getConfirmPassword())) { |
| 101 | + * errors.rejectValue("confirmPassword", |
| 102 | + * "PasswordEqualsValidator.passwordResetForm.password", |
| 103 | + * "password and confirm password must be same."); |
| 104 | + * } |
| 105 | + * });</pre> |
| 106 | + * @param targetClass the class supported by the returned validator |
| 107 | + * @param delegate function invoked with the target object, if it is an |
| 108 | + * instance of type T |
| 109 | + * @param <T> the target object type |
| 110 | + * @return the created {@code Validator} |
| 111 | + * @since 6.1 |
| 112 | + */ |
| 113 | + static <T> Validator forInstanceOf(Class<T> targetClass, BiConsumer<T, Errors> delegate) { |
| 114 | + return new TypedValidator<>(targetClass, targetClass::isAssignableFrom, delegate); |
| 115 | + } |
| 116 | + |
| 117 | + /** |
| 118 | + * Return a {@code Validator} that checks whether the target object's class |
| 119 | + * is identical to {@code targetClass}, resorting to {@code delegate} to |
| 120 | + * populate {@link Errors} if it is. |
| 121 | + * |
| 122 | + * <p>For instance: |
| 123 | + * <pre class="code">Validator passwordEqualsValidator = Validator.forType(PasswordResetForm.class, (form, errors) -> { |
| 124 | + * if (!Objects.equals(form.getPassword(), form.getConfirmPassword())) { |
| 125 | + * errors.rejectValue("confirmPassword", |
| 126 | + * "PasswordEqualsValidator.passwordResetForm.password", |
| 127 | + * "password and confirm password must be same."); |
| 128 | + * } |
| 129 | + * });</pre> |
| 130 | + * @param targetClass the exact class supported by the returned validator (no subclasses) |
| 131 | + * @param delegate function invoked with the target object, if it is an |
| 132 | + * instance of type T |
| 133 | + * @param <T> the target object type |
| 134 | + * @return the created {@code Validator} |
| 135 | + * @since 6.1 |
| 136 | + */ |
| 137 | + static <T> Validator forType(Class<T> targetClass, BiConsumer<T, Errors> delegate) { |
| 138 | + return new TypedValidator<>(targetClass, targetClass::equals, delegate); |
| 139 | + } |
| 140 | + |
95 | 141 | }
|
0 commit comments