for - invocation of init method failed nested exception is org hibernate annotationexception
Validador de Hibernate: @Email acepta ask @ stackoverflow como válido? (7)
Estoy usando la anotación @Email
para validar una dirección de correo electrónico. El problema que estoy teniendo es que está aceptando cosas como ask@stackoverflow
como una dirección válida de correo electrónico. Supongo que esto se debe a que quieren admitir direcciones de intranet, pero parece que no puedo encontrar una bandera, así que compruebo si hay una extensión.
¿Realmente necesito cambiar a @Pattern
(y cualquier recomendación para un patrón de correo electrónico que sea flexible) o me falta algo?
Aquí hay un validador de correo electrónico javax.validation que utiliza el validador de Apache Commons
public class CommonsEmailValidator implements ConstraintValidator<Email, String> {
private static final boolean ALLOW_LOCAL = false;
private EmailValidator realValidator = EmailValidator.getInstance(ALLOW_LOCAL);
@Override
public void initialize(Email email) {
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if( s == null ) return true;
return realValidator.isValid(s);
}
}
Y la anotación:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {CommonsEmailValidator.class})
@Documented
@ReportAsSingleViolation
public @interface Email {
String message() default "{org.hibernate.validator.constraints.Email.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface List {
Email[] value();
}
}
De hecho, @Email
de Hibernate Validator usa la @Email
internamente . Puede definir fácilmente su propia restricción en función de esa expresión regular, modificada como necesite (tenga en cuenta el +
al final de DOMAIN
):
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Pattern(regexp = Constants.PATTERN, flags = Pattern.Flag.CASE_INSENSITIVE)
public @interface EmailWithTld {
String message() default "Wrong email";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
interface Constants {
static final String ATOM = "[a-z0-9!#$%&''*+/=?^_`{|}~-]";
static final String DOMAIN = "(" + ATOM + "+(//." + ATOM + "+)+";
static final String IP_DOMAIN = "//[[0-9]{1,3}//.[0-9]{1,3}//.[0-9]{1,3}//.[0-9]{1,3}//]";
static final String PATTERN =
"^" + ATOM + "+(//." + ATOM + "+)*@"
+ DOMAIN
+ "|"
+ IP_DOMAIN
+ ")$";
}
En realidad, validar las direcciones de correo electrónico es realmente complejo. No es posible validar que una dirección de correo electrónico sea sintácticamente correcta y se dirija al destinatario en una anotación. La anotación @Email
es una comprobación mínima útil que no sufre el problema de falsos negativos.
El siguiente paso en la validación debería ser enviar un correo electrónico con un desafío que el usuario debe completar para establecer que el usuario tiene acceso a la dirección de correo electrónico.
Es mejor aceptar algunos falsos positivos en el paso 1 y permitir el paso de algunas direcciones de correo electrónico no válidas que rechazar usuarios válidos. Si desea aplicar reglas adicionales, puede agregar más controles, pero tenga mucho cuidado con lo que supone que es un requisito de una dirección de correo electrónico válida. Por ejemplo, no hay nada en los RFC que dicte que i@nl
sea inválido, porque nl
es un dominio de nivel superior de un país registrado.
La solución de composición de restricción no funciona. Cuando el correo electrónico se utiliza junto con el patrón, la expresión regular de correo electrónico se mantiene en mayor precedencia. Creo que esto se debe a que la anotación de Email anula algunos atributos del patrón, a saber, flags y regexp (la clave aquí). Si @Email
, solo la expresión regular de @Pattern
aplicará en las validaciones.
/**
* @return an additional regular expression the annotated string must match. The default is any string (''.*'')
*/
@OverridesAttribute(constraint = Pattern.class, name = "regexp") String regexp() default ".*";
/**
* @return used in combination with {@link #regexp()} in order to specify a regular expression option
*/
@OverridesAttribute(constraint = Pattern.class, name = "flags") Pattern.Flag[] flags() default { };
Obviamente, llegué tarde a la fiesta, todavía estoy respondiendo a esta pregunta,
¿Por qué no podemos usar la anotación @Pattern con expresiones regulares en nuestra clase de Validación como esta?
public Class Sigunup {
@NotNull
@NotEmpty
@Pattern((regexp="[A-Za-z0-9._%-+]+@[A-Za-z0-9.-]+//.[A-Za-z]{2,4}")
private String email;
}
Es mas fácil.
Si va a probar la solución anterior, https://.com/a/12515543/258544 agregue @ReportAsSingleViolation en la definación de la anotación, de esta forma evitará ambos mensajes de validación (uno de @Email y otro de @Pattern) ya que es una anotación compuesta:
@Email(message="Please provide a valid email address")
@Pattern(regexp=".+@.+//..+", message="Please provide a valid email address")
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Documented
@ReportAsSingleViolation
From @interface ReportAsSingleViolation javax.validation: validation-api: 1.1.0.Final) definición de anotación: "... La evaluación de las restricciones compuestas se detiene en el primer error de validación en caso de que la restricción de composición esté anotada con ReportAsSingleViolation"
También puede usar la composición de restricciones como una solución alternativa. En el siguiente ejemplo, confío en el validador @Email
para hacer la validación principal, y agrego un validador @Pattern
para asegurarme de que la dirección sea en forma de x@yz
(no recomiendo usar solo @Pattern
continuación para validación regular de correo electrónico)
@Email(message="Please provide a valid email address")
@Pattern(regexp=".+@.+//..+", message="Please provide a valid email address")
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface ExtendedEmailValidator {
String message() default "Please provide a valid email address";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}