简体   繁体   中英

how add custom validator for `javax.validation.constraints` annotation?

I have implemented validation for Long field and @PastOrPresent validation

public class PastOrPresentValidator implements ConstraintValidator<PastOrPresent, Long>{
    @Override
    public boolean isValid(Long value, ConstraintValidatorContext context) {
        if (value == null) {
            return false;
        }
        return value <= System.currentTimeMillis();
    }
}

public class MyDto {
    @PastOrPresent
    Long timestamp;    
}

And got error:

HV000030: No validator could be found for constraint 'javax.validation.constraints.PastOrPresent' validating type 'java.lang.Long'. Check configuration for 'push.dto.timestamp'

But when I create custom annotation like @PastOrPresentLong and use same validator code everything works.

Is there a way to add custom validator for javax.validation.constraints annotation?

Just implementing the ConstraintValidator interface isn't enough for your new validator to work. It should be somehow registered so that BeanValidation provider knows about it. This can be done via XML (see for more info here ):

<constraint-mappings
        xmlns="http://xmlns.jcp.org/xml/ns/validation/mapping"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/validation/mapping
            http://xmlns.jcp.org/xml/ns/validation/mapping/validation-mapping-2.0.xsd"
        version="2.0">
    <!-- anything else -->
    <constraint-definition annotation="javax.validation.constraints.PastOrPresent">
        <validated-by include-existing-validators="true">
            <value>org.mycompany.PastOrPresentLongValidator</value>
        </validated-by>
    </constraint-definition>
</constraint-mappings>

Then if you are using Hibernate Validator as BeanValidation provider you also have two more options - use service loader or programmatic definition. Using Service loader is the easiest way of adding new validator. All you need to do is create a META-INF/services/javax.validation.ConstraintValidator file and add a FQCN of your validator to it. See detailed examples in this post under section "Use standard constraints for non standard classes" or in the doc . With programmatic approach you would have to do something like:

ConstraintMapping constraintMapping = configuration.createConstraintMapping();

constraintMapping
        .constraintDefinition( PastOrPresent.class )
        .validatedBy( PastOrPresentLongValidator.class );

And then add this constraint mapping to your configuration and create a validator from it:

Validator validator = configuration.addMapping( constraintMapping )
        .buildValidatorFactory()
        .getValidator();

But as I mentioned earlier - Service Loader is the easiest and quickest way to go.

Simpler Approach

A simpler declarative approach to linking the annotation to the validator is to specify the linkage through a Constraint(validatedBy) annotation.

@Retention(RUNTIME)
@Target({ FIELD, METHOD, PARAMETER, ANNOTATION_TYPE })
@Constraint(validatedBy = PastOrPrsentValidator.class)
public class PastOrPresentValidator implements ConstraintValidator<PastOrPresent, Long>{
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM