2010-12-16 9 views
41

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 [email protected] 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.Validador de Hibernación: @Email acepta ask @ stackoverflow como válido?

¿Realmente necesito cambiar a @Pattern (y cualquier recomendación para un patrón de correo electrónico que sea flexible) o me falta algo?

+0

¿Te refieres a 'org.hibernate.validator.Email'? – skaffman

+0

Además, ¿qué versión de Hibernate Validator? – skaffman

+2

org.hibernate.validator.constraints.Email; y la versión 4.0.2.GA – jack

Respuesta

28

En realidad, @Email de Hibernate Validator uses regexp internally. Se puede definir fácilmente su propio restricción basada en esa expresión regular, con las modificaciones que necesita (nótese 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 
        + ")$"; 
} 
+14

Cierto, pero estoy un poco sorprendido de que necesite hacer un validador personalizado para lo que parece ser un requisito muy común. Esperaría una bandera para este tipo de cosas. – jack

+0

Una buena manera de personalizar algunos consejos y trucos +1 :) – ThierryB

+1

@Matt solución es mucho más simple, ya que solo agrega una línea en las anotaciones –

37

También puede utilizar constraint composition como una solución temporal. En el siguiente ejemplo, confío en el validador @Email para realizar la validación principal y agrego un validador @Pattern para asegurarme de que la dirección sea en la forma de [email protected] (no recomiendo usar solo el @Pattern para la validación de correo electrónico normal)

@Email(message="Please provide a valid email address") 
@Pattern(regexp="[email protected]+\\..+", 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 {}; 
} 
+0

Esta es de hecho la mejor solución – Arefe

0

La solución de composición de restricciones 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 correo electrónico anula algunos atributos del patrón, a saber, flags y regexp (la clave aquí). Si elimino @Email, solo se aplicará la expresión regular @Pattern 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 { }; 
11

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 adolece del problema de falsos negativos.

El próximo 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 [email protected] no sea válido, porque nl es un dominio de nivel superior de un país registrado.

+1

¡Esta es la respuesta correcta! –

3

Aquí es un validador de correo electrónico javax.validation usando Apache Commons Validador

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(); 
    } 
} 
0

Obviamente estoy tarde a la fiesta, todavía estoy respondiendo a esta pregunta,

¿Por qué no puede usamos la anotación @Pattern con expresiones regulares en nuestra clase de validación de este tipo

public Class Sigunup { 

    @NotNull 
    @NotEmpty 
    @Pattern((regexp="[A-Za-z0-9._%-+][email protected][A-Za-z0-9.-]+\\.[A-Za-z]{2,4}") 
    private String email; 

} 

Es más fácil.

+0

... y mal. "test @ myexample..loc" es válido con esta expresión regular. – Bertl

+0

¿Puedes por favor elaborar un poco más? – user2245151

+0

Los puntos dobles en la parte del dominio no se reconocen como incorrectos. Además, los dominios umlaut y muchos más patrones válidos de direcciones de correo electrónico no se detectan como válidos. Por lo tanto, es mejor dejar que la validación sea realizada por bibliotecas especiales, como Apache Commons EmailValidator. Consulte https://gist.github.com/robertoschwald/ce23c8c23ebd5b93fc3f60c150e35cea cómo hacerlo con Hibernate. – Bertl

Cuestiones relacionadas