Hibernate Validator - add dynamic ConstraintValidator

Upon learning about the Hibernate Custom Validators , he gave me an interest in one topic, can I create one basic annotation in which I could set which validator to use?

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

So I can use @CustomAnnotation this way

 @CustomAnnotation(validator = CustomConstraintValidator.class, message = "validationMessage") private Object fieldName; 
+6
source share
3 answers

I would not recommend it, but you can do it something like this:

 @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); } } 

But then again, prefer specific annotations, they are more expressive.

Edit

After your comment, I think you want to be able to set different validators based on the return type of the property

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

If so, add a few validator implementations in the @Constraint annotations.

 @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) { } } 

You can even link the contraint annotation to the implementation via the META/validation.xml file

 <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> 

If you need something more flexible, I think my initial proposal will work. In the GenericValidatorBootstrapperValidator isValid method, you can call the correct validator instance based on the object type of the value parameter (for example, via instanceof ).

+5
source

Hibernate Validator also now offers the @ScriptAssert annotation, which simplifies custom validation and avoids many lines of code.

Usage example:

  @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; } } 
+1
source

I don’t think you can implement a dynamic authentication analyzer on top of the Hibernate Validator support. It is much better to have a dedicated set of validator annotation pairs, so when you annotate a field with a specific validation annotation, it clearly indicates which validator should be used.

0
source

Source: https://habr.com/ru/post/982080/


All Articles