validator example bean java hibernate validation annotations hibernate-mapping

java - example - Validador de Hibernate: agregue un Dynamic ConstraintValidator



bean validation (3)

Después de conocer Hibernate Custom Validators , me ha interesado un tema, ¿podría crear una anotación base en la que pudiera establecer qué Validator usar?

@Target({ ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = validator().class) public @interface CustomAnnotation { public String message(); Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; Class<? extends ConstraintValidator<? extends CustomAnnotation, Serializable>> validator(); }

Para poder usar @CustomAnnotation de esta manera

@CustomAnnotation(validator = CustomConstraintValidator.class, message = "validationMessage") private Object fieldName;


No creo que pueda implementar un resolvedor de validadores dinámico además del soporte de Hibernate Validator. Es mucho mejor tener un conjunto dedicado de pares de validación y anotación, por lo que cuando anota un campo con una anotación de Validación específica, queda claro qué Validador se va a usar.


No lo recomendaría pero puedes hacerlo más o menos de la siguiente manera:

@Target({ ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = GenericValidatorBootstrapperValidator.class) public @interface CustomAnnotation { public String message(); Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; Class<? extends ConstraintValidator<? extends CustomAnnotation, Serializable>> validator(); } public class GenericValidatorBootstrapperValidator implements ConstraintValidator<CustomAnnotation, Object> { private final ConstraintValidator validator; @Override public void initialize(CustomAnnotation constraintAnnotation) { Class<? extends ConstraintValidator> validatorClass = constraintAnnotation.validator(); validator = validatorClass.newInstance(); validator.initialize( ... ); //TODO with what? } @Override public boolean isValid(Object value, ConstraintValidatorContext context) { return validator.isValid(value, context); } }

Pero de nuevo, prefieren anotaciones específicas, son más expresivas.

Editar

Después de su comentario, creo que lo que desea es poder establecer diferentes validadores según el tipo de devolución de la propiedad.

@CustomAnnotation List<String> foo; @CustomAnnotation Table bar;

Si ese es el caso, agregue varias implementaciones de validadores en la anotación @Constraint .

@Target({ ElementType.FIELD }) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = {ListValidatorImpl.class, TableValidatorImpl.class, ...}) public @interface CustomAnnotation { public String message(); Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; } public class ListValidatorImpl implements ConstraintValidator<CustomAnnotation, List> { @Override public boolean isValid(List value, ConstraintValidatorContext context) { } } public class TableValidatorImpl implements ConstraintValidator<CustomAnnotation, Table> { @Override public boolean isValid(Table value, ConstraintValidatorContext context) { } }

Incluso puede vincular una anotación contraint con una implementación a través del archivo META/validation.xml

<constraint-mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.1.xsd" xmlns="http://jboss.org/xml/ns/javax/validation/mapping" version="1.1"> <constraint-definition annotation="org.mycompany.CustomAnnotation"> <validated-by include-existing-validators="true"> <value>org.mycompany.EnumCustomValidatorImpl</value> </validated-by> </constraint-definition> </constraint-mappings>

Si necesita algo más flexible, creo que mi propuesta inicial funcionaría. En el método GenericValidatorBootstrapperValidator isValid, puede llamar a la instancia de validador correcta en función del tipo de objeto del parámetro de value (por instanceof mediante instanceof ).


Hibernate Validator también ofrece ahora una anotación @ScriptAssert que facilita la implementación de validaciones personalizadas y ayuda a evitar muchas líneas de código.

Ejemplo de uso:

@ScriptAssert(lang = "javascript", script = "_this.capital.equals(_this.capital.toUpperCase)", message = "capital has not Capital letters") public class BigLetters { private String capital; public String getCapital() { return capital; } public void setCapital(String capital) { this.capital = capital; } }