Dependency Injection in Constraint-Validators

There is no special requirement for constraint-validators. As soon as the bean-validation module has been added to a project it's possible to use dependency injection in std. constraint-validators.

Inject beans in constraint validators
public class UserNameValidator implements ConstraintValidator<UserName, String>
{
    @Inject
    private UserService userService;

    public void initialize(UserName userName)
    {
    }

    public boolean isValid(String userName, ConstraintValidatorContext constraintValidatorContext)
    {
        return this.userService.validateUserName(userName);
    }
}

You don't have to annotate such a ConstraintValidator with @Advanced. CODI will inject beans automatically, if you use the @Advanced qualifier for injection.

Producers

Via the @Advanced qualifier it's possible to inject the following BV artifacts in your beans:

  • ValidatorFactory
  • ConstraintValidatorFactory
  • MessageInterpolator
  • Validator

CODI produces injectable (dependent) proxies which dynamically lookup the cached ValidatorFactory for creating new instances dynamically. So you don't have to care about correct caching of different bean-validation artifacts. E.g. every call of Validator#validate will automatically resolve the cached ValidatorFactory, creates a new Validator (because it isn't allowed to cache it) and call #validate on it. Everything a user has to do is:

Inject bean-validation artifacts
public class DemoBean
{
    @Inject
    public DemoBean(@Advanced Validator validator)
    {
        this.validator = validator;
        validate(); //uses the injected Validator - e.g.: validator.validate(this);
    }
    //...
}

In this case constructor injection is used, however, for sure it's possible to use the other injection types as well. The only part which is specific to CODI is the usage of the @Advanced qualifier and CODI will do the rest for you.

Hint

If you are using also the JSF module of CODI, you get the ValidatorFactory configured for JSF + the enhancements of the BV module.

Hint

If you are using also the BV module of MyFaces ExtVal, ExtVal will use the ValidatorFactory created by the BV module of CODI. That means the combination of CODI and ExtVal works out-of-the-box.

ClassLevelConstraintValidator

Currently this class allows to implement custom ConstraintValidator s which can provide the invalid value in case of class level validation.

Hint

This feature is currently only available in combination with the JSF module.

Simple usage of the invalidValue placeholder
@Constraint(validatedBy = DifferentNameValidator.class)
@Target(TYPE)
@Retention(RUNTIME)
public @interface DifferentName
{
    String message() default "The same name '{invalidValue}' isn't allowed.";

    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}


@ApplicationScoped
public class DifferentNameValidator extends ClassLevelConstraintValidator<DifferentName, Person>
{
    private static final long serialVersionUID = 3851988368625335444L;

    @Inject
    private ValidationService validationService;

    private String invalidValue;

    @Override
    protected boolean isValidInstance(Person person, ConstraintValidatorContext constraintValidatorContext)
    {
        boolean result = this.validationService.isValid(person);

        if(result)
        {
            this.invalidValue = null;
        }
        else
        {
            this.invalidValue = person.getFirstName();
        }
        return result;
    }

    @Override
    protected Serializable getInvalidValue()
    {
        return this.invalidValue;
    }
}
  • No labels