Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.
This repository was archived by the owner on May 28, 2018. It is now read-only.

Cannot inject CDI bean into custom validator #3801

@mhorejsi

Description

@mhorejsi

Jersey doesn't allow me to inject CDI bean into my custom Validator.

Sample code:

@ApplicationScoped
public class AllowedWeightsValidator implements ConstraintValidator<AllowedWeights, Map<String, Integer>> {

    @Inject
    private Localizer localizer;

    @Override
    public void initialize(AllowedWeights allowedWeights) {
        // ...
    }

    @Override
    public boolean isValid(Map<String, Integer> weights, ConstraintValidatorContext context) {
        // ...
    }

}

The exception is:

<org.glassfish.jersey.server.internal.JerseyResourceContext> <BEA-000000> <Lookup and initialization failed for a resource class: class package.AllowedWeightsValidator.
A MultiException has 1 exceptions.  They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=Localizer,parent=AllowedWeightsValidator,qualifiers={},position=-1,optional=false,self=false,unqualified=null,1451781908)

        at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:75)
        at org.jvnet.hk2.internal.Utilities.justInject(Utilities.java:941)
        at org.jvnet.hk2.internal.ServiceLocatorImpl.inject(ServiceLocatorImpl.java:980)
        at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:1055)
        at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:1046)
        at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:173)
        at org.glassfish.jersey.server.internal.JerseyResourceContext.getResource(JerseyResourceContext.java:102)
        at org.glassfish.jersey.server.validation.internal.InjectingConstraintValidatorFactory.getInstance(InjectingConstraintValidatorFactory.java:61)
        at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.createAndInitializeValidator(ConstraintValidatorManager.java:141)
        at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.getInitializedValidator(ConstraintValidatorManager.java:101)
        at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:125)
        at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintTree.validateConstraints(ConstraintTree.java:91)
        at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:83)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraint(ValidatorImpl.java:547)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForDefaultGroup(ValidatorImpl.java:487)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateConstraintsForCurrentGroup(ValidatorImpl.java:451)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:403)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateCascadedConstraint(ValidatorImpl.java:723)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateCascadedConstraints(ValidatorImpl.java:601)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateInContext(ValidatorImpl.java:412)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateCascadedConstraint(ValidatorImpl.java:723)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateCascadedConstraints(ValidatorImpl.java:601)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateParametersInContext(ValidatorImpl.java:992)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:300)
        at org.hibernate.validator.internal.engine.ValidatorImpl.validateParameters(ValidatorImpl.java:254)
        at org.glassfish.jersey.server.validation.internal.DefaultConfiguredValidator.onValidate(DefaultConfiguredValidator.java:175)
        at org.glassfish.jersey.server.validation.internal.ValidationInterceptorExecutor.proceed(ValidationInterceptorExecutor.java:113)
        at org.glassfish.jersey.server.validation.internal.DefaultConfiguredValidator.validateResourceAndInputParams(DefaultConfiguredValidator.java:146)
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:134)
        at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:205)
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
        at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)

Such injection should be according to Beans Validation spec (1.1, section 10.3.2) supported:

If no custom ConstraintValidatorFactory is requested by the user, the ValidatorFactory must be configured with a custom ConstraintValidatorFactory instance that returns CDI managed beans representing the requested ConstraintValidator types

When I inject (via @javax.inject.Inject) the Validator manually, everything works as expected. The problem occurs when I have a JAX-RS @POST method accepting POJO with my custom validation annotation.

This problem can be workarounded by registering the following ContextResolver:

public class ValidationConfigResolver implements ContextResolver<ValidationConfig> {

    @Context
    private ResourceContext resourceContext;

    @Override
    public ValidationConfig getContext(Class<?> aClass) {
        return new ValidationConfig().constraintValidatorFactory(new CDIConstraintValidatorFactory(resourceContext));
    }

    private static class CDIConstraintValidatorFactory implements ConstraintValidatorFactory {

        private final ResourceContext resourceContext;

        public CDIConstraintValidatorFactory(ResourceContext resourceContext) {
            this.resourceContext = resourceContext;
        }

        @Override
        public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> clazz) {
            Instance<T> cdiInstance = CDI.current().select(clazz);
            return cdiInstance.isUnsatisfied() ? resourceContext.getResource(clazz) : cdiInstance.get();
        }

        @Override
        public void releaseInstance(ConstraintValidator<?, ?> constraintValidator) {
            try {
                CDI.current().destroy(constraintValidator);
            } catch (UnsupportedOperationException ignored) {
                // If CDI cannot destroy the validator, that's perfectly fine.
                // It could have been created by HK2 (ResourceContext).
            }
        }
    }

}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions