Search code examples
jax-rsjersey-2.0websphere-libertyopen-libertyjava-ee-8

CDI injection not working in REST Resource in WAS Liberty with Jersey as JAX-RS implementation


I am using websphere liberty 19.0.0.8 and I wanted to use Jersey instead of default CXF for jax-rs implementation. I removed jaxrs-2.1 feature from server xml and packaged jersey implementation jars in my webapp .war.

<featureManager>
    <feature>servlet-4.0</feature>
    <feature>jndi-1.0</feature>
    <feature>requestTiming-1.0</feature>
    <feature>monitor-1.0</feature>
    <feature>localConnector-1.0</feature>
    <feature>restConnector-2.0</feature>

<!-- Do not add enabled webProfile-8.0 because we want to disable default 
    REST implementation (Apache-CXF) provided by Liberty. We want to use Jersey 
    as our REST implementation because it better support multi-part streaming, -->
    <!-- <feature>webProfile-8.0</feature> -->
    <feature>jsp-2.3</feature>
    <feature>cdi-2.0</feature>
    <feature>managedBeans-1.0</feature>
    <feature>jdbc-4.2</feature>
    <!-- <feature>jaxrs-2.1</feature> -->
</featureManager>

Gradle build including jersey implementation

//JxRS Jersey implementation    
compile group: 'org.glassfish.jersey.containers', name: 'jersey-container-servlet', version: '2.25.1'       
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-json-jackson', version: '2.25.1'
compile group: 'org.glassfish.jersey.media', name: 'jersey-media-multipart', version: '2.25.1'
compile group: 'com.fasterxml.jackson.jaxrs', name: 'jackson-jaxrs-json-provider', version: '2.9.0'

Extended jersey's ResourceConfig to configure my RestApplication

@ApplicationPath("/")
public class RestApplicationConfig extends ResourceConfig {

    private static final Logger LOGGER = LoggerFactory.getLogger(RestApplicationConfig.class);

    public RestApplicationConfig() {
        super();
        configureResourcesAndFeatures();
    }

    private void configureResourcesAndFeatures() {
        packages(RestApplicationConfig.class.getPackage().getName());
        register(MultiPartFeature.class);
    }
}

With all this setup my rest api works and I am able to make use of Jersey's multiple related classes in my code.

Now the problem is with CDI. In my resource class I am able to inject CDI managed resource/classes for example

@ApplicationScoped
@Path("/ping")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class PingResource {

    private static final Logger LOGGER = LoggerFactory.getLogger(PingResource.class);

    @Resource(lookup = "jndi_dpa_iss_rest_url")
    private String issRestBaseUrlInResource;

    @Inject
    private DocumentService documentService;
}

In above class @Resource and @Inject are not able to resolve JNDI resource and managed bean. As soon as I enable jaxrs-2.1 feature in server.xml CDI injection works but then I loose jersey, it uses CXF.

DocumentService and its implementation class is defined as below. Everything is under same package as RestApplicationConfig class or it's sub-packages.

@ApplicationScoped
@Transactional(value = Transactional.TxType.NOT_SUPPORTED)
public class DocumentServiceImpl implements DocumentService {
    // some code here
}

What do I need to use CDI in my rest resource classes?


Solution

  • Because there is no jersey extension for CDI 2.0 at the moment, I had to find workaround. Workaround is to manually query CDI container to the the type of bean we are interested in. This way we are manually injecting CDI bean in our resource class but the injected bean is managed bean instance so CDI has taken care of satisfying all its dependecies.

    This we we are doing manual injection only in Resource layer but CDI should work fine for layer down.

    Working code.

    @ApplicationScoped
    @Path("/ping")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public class PingResource {
    
        private DocumentService documentService = CDI.current().select(DocumentService.class).get();
    
    }
    

    Basically instead of @Inject manually query CDI container.