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

Cannot inject CDI bean into custom validator #3801

Open
mhorejsi opened this issue Apr 6, 2018 · 3 comments
Open

Cannot inject CDI bean into custom validator #3801

mhorejsi opened this issue Apr 6, 2018 · 3 comments

Comments

@mhorejsi
Copy link

mhorejsi commented Apr 6, 2018

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).
            }
        }
    }

}
@mhorejsi
Copy link
Author

mhorejsi commented Apr 6, 2018

The affected Jersey version is 2.22.1.

@jansupol
Copy link
Contributor

jansupol commented Apr 6, 2018

The injection has been significantly reworked in 2.26. Can you reproduce with latest Jersey?

@mhorejsi
Copy link
Author

mhorejsi commented Apr 6, 2018

I use WebLogic server 12.2.1.2 which bundles Jersey 2.22.1. Once I have some spare time, I'll try to reproduce this issue with the latest Jersey.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants