Search code examples
javajerseycdijersey-2.0hk2

CDI injection source not available in Jersey sub-resource


I'm using CDI in a Jersey app. On root resources, CDI injection works as expected, but whenever I return a sub-resource, the CDI injection sources are not available.

My root resource with sub-resource locator:

@Path("")
public class MyResource {

    @Inject @Named("name") // works
    private String name;

    @Context
    private ResourceContext context;

    @Path("test2")
    public Object test2() {
        return MySubResource.class;
        //return context.getResource(MySubResource.class); // this does not work either
    }

}

The sub-resource:

public class MySubResource {

    @Inject @Named("name") // error
    private String name;

    @GET
    public Response test() {
        return Response.ok("Name in sub resource: " + name).build();
    }

}

Error:

org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=String,parent=MySubResource,qualifiers={@javax.inject.Named(value=name)},position=-1,optional=false,self=false,unqualified=null,1235803160)

I'm using org.glassfish.jersey.ext.cdi:jersey-cdi1x and Weld dependencies, running on Undertow, with the Weld servlet listener added to the deployment.

Again, the same injection on the root resource does work. The @Named("name") String is produced by an @ApplicationScoped producer.

Is this not supposed to work? What am I missing?

Minimal example Maven project available here: https://gitlab.com/Victor8321/jersey-sub-resource-cdi

Note: An open issue for this exists, but not sure what the official stance on this is: https://java.net/jira/browse/JERSEY-3184


Solution

  • As pointed out in https://github.com/eclipse-ee4j/jersey/issues/3456, adding a dummy @Path("xyz") to the sub-resource class is a "fix". However, that exposes your sub-resource under the dummy path.

    Injecting an instance just through CDI works as well (@Inject Instance<MySubResource> ..), but then Jersey-managed resources aren't available for injection, such as @Context HttpServletRequest.

    I've found 2 other approaches that fully work (both CDI injection and JAX-RS injection) and have no side effects (as with @Path):

    • Annotate the sub resource class with @Provider.
    • register() the sub resource class in the ResourceConfig (or Application).

    Both approaches seem to work because they make Jersey - and in turn, CDI - aware of the class.

    Note: I've updated my example project accordingly for future reference.