El paso a paso o código que verás en este artículo es la resolución más sencilla y válida que hallamos a tu duda o problema.
Solución:
Cada restricción de campo debe ser manejada por una anotación de validación distinta, o en otras palabras, no es una práctica recomendada tener la anotación de validación de un campo que se compara con otros campos; La validación de campo cruzado debe realizarse a nivel de clase. Además, la forma preferida de JSR-303 Sección 2.2 para expresar múltiples validaciones del mismo tipo es a través de una lista de anotaciones. Esto permite especificar el mensaje de error por coincidencia.
Por ejemplo, validando un formulario común:
@FieldMatch.List(
@FieldMatch(first = "password", second = "confirmPassword", message = "The password fields must match"),
@FieldMatch(first = "email", second = "confirmEmail", message = "The email fields must match")
)
public class UserRegistrationForm
@NotNull
@Size(min=8, max=25)
private String password;
@NotNull
@Size(min=8, max=25)
private String confirmPassword;
@NotNull
@Email
private String email;
@NotNull
@Email
private String confirmEmail;
La anotación:
package constraints;
import constraints.impl.FieldMatchValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
/**
* Validation annotation to validate that 2 fields have the same value.
* An array of fields and their matching confirmation fields can be supplied.
*
* Example, compare 1 pair of fields:
* @FieldMatch(first = "password", second = "confirmPassword", message = "The password fields must match")
*
* Example, compare more than 1 pair of fields:
* @FieldMatch.List(
* @FieldMatch(first = "password", second = "confirmPassword", message = "The password fields must match"),
* @FieldMatch(first = "email", second = "confirmEmail", message = "The email fields must match"))
*/
@Target(TYPE, ANNOTATION_TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = FieldMatchValidator.class)
@Documented
public @interface FieldMatch
String message() default "constraints.fieldmatch";
Class>[] groups() default ;
Class extends Payload>[] payload() default ;
/**
* @return The first field
*/
String first();
/**
* @return The second field
*/
String second();
/**
* Defines several @FieldMatch
annotations on the same element
*
* @see FieldMatch
*/
@Target(TYPE, ANNOTATION_TYPE)
@Retention(RUNTIME)
@Documented
@interface List
FieldMatch[] value();
El Validador:
package constraints.impl;
import constraints.FieldMatch;
import org.apache.commons.beanutils.BeanUtils;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class FieldMatchValidator implements ConstraintValidator
private String firstFieldName;
private String secondFieldName;
@Override
public void initialize(final FieldMatch constraintAnnotation)
firstFieldName = constraintAnnotation.first();
secondFieldName = constraintAnnotation.second();
@Override
public boolean isValid(final Object value, final ConstraintValidatorContext context)
try
firstObj != null && firstObj.equals(secondObj);
catch (final Exception ignore)
// ignore
return true;
Te sugiero otra posible solución. Quizás menos elegante, ¡pero más fácil!
public class MyBean
@Size(min=6, max=50)
private String pass;
private String passVerify;
@AssertTrue(message="passVerify field should be equal than pass field")
private boolean isValid()
return this.pass.equals(this.passVerify);
los isValid
El validador invoca el método automáticamente.
Me sorprende que esto no esté disponible de forma inmediata. De todos modos, aquí hay una posible solución.
Creé un validador de nivel de clase, no el nivel de campo como se describe en la pregunta original.
Aquí está el código de anotación:
package com.moa.podium.util.constraints;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Target(TYPE, ANNOTATION_TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = MatchesValidator.class)
@Documented
public @interface Matches
String message() default "com.moa.podium.util.constraints.matches";
Class>[] groups() default ;
Class extends Payload>[] payload() default ;
String field();
String verifyField();
Y el propio validador:
package com.moa.podium.util.constraints;
import org.mvel2.MVEL;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class MatchesValidator implements ConstraintValidator
private String field;
private String verifyField;
public void initialize(Matches constraintAnnotation)
this.field = constraintAnnotation.field();
this.verifyField = constraintAnnotation.verifyField();
public boolean isValid(Object value, ConstraintValidatorContext context)
Object fieldObj = MVEL.getProperty(field, value);
Object verifyFieldObj = MVEL.getProperty(verifyField, value);
boolean neitherSet = (fieldObj == null) && (verifyFieldObj == null);
if (neitherSet)
return true;
boolean matches = (fieldObj != null) && fieldObj.equals(verifyFieldObj);
if (!matches)
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("message")
.addNode(verifyField)
.addConstraintViolation();
return matches;
Tenga en cuenta que he usado MVEL para inspeccionar las propiedades del objeto que se valida. Esto podría reemplazarse con las API de reflexión estándar o, si está validando una clase específica, los métodos de acceso en sí.
La anotación @Matches se puede usar en un bean de la siguiente manera:
@Matches(field="pass", verifyField="passRepeat")
public class AccountCreateForm
@Size(min=6, max=50)
private String pass;
private String passRepeat;
...
Como descargo de responsabilidad, escribí esto en los últimos 5 minutos, por lo que probablemente aún no haya solucionado todos los errores. Actualizaré la respuesta si algo sale mal.
Finalizando este artículo puedes encontrar las reseñas de otros administradores, tú asimismo eres capaz dejar el tuyo si lo crees conveniente.