1

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?

Rakesh Prajapati
  • 1,078
  • 8
  • 17
  • Jersey has some optional modules that are needed for cdi integration. Check https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/modules-and-dependencies.html – areus Mar 02 '20 at 19:18
  • Another thing to check would be your beans.xml file. Liberty does some fancy stuff when the JAX-RS and CDI features are enabled together that you might need to handle with the beans.xml file - like discovery-mode="all", etc. – Andy McCright Mar 02 '20 at 19:24
  • @areus You are right, I think using jersey extension for CDI would help me here. I looked at the official documentation link you mentioned above. I don't see jersey extension for cdi2.0 for servlet container. I see one for cdi 2.0 SE but I think I should not use that in liberty runtime. Any idea ? – Rakesh Prajapati Mar 05 '20 at 21:15

1 Answers1

1

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.

Rakesh Prajapati
  • 1,078
  • 8
  • 17