Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The JAX-RS 2.0 specification (JSR-339) mandates the support of CDI 1.1 (JSR-346) and Apache CXF starting from the version 3.0 introduces the initial support of this feature. As the starting point, the emphasis has been done on supporting embedded Jety 8/9 and Tomcat 7/8 containers as primary deployment (though other application servers will be supported in the future). 

...

At the moment, the integration of Apache CXF and CDI revolves around two key components, residing which reside in the new module called cxf-integration-cdi

...

If the Apache CXF application contains only either no instance of JAX-RS Application or only one single instance of JAX-RS Application (annotated with @ApplicationPath) with no singletons and classes defined, the following rules are being applied by JAXRSCdiResourceExtension in order to configure and publish the configured JAX-RS resources:

...

Code Block
java
java
@Path("/bookstore/")
public class BookStore {
    @Inject private BookStoreService service;
    
    @GET
    @Path("/books/{bookId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Book getBook(@PathParam("bookId") String id) {
        return service.get(id);
    }
}

Additional Configuration Capabilities

If you have a need to, you can configure the underlying JAXRSServerFactoryBean by implementing the interface JAXRSServerFactoryCustomizationExtension.  Instances of this extension can be located via ServiceLoader of as CDI beans.  You can use this to programmatically add new providers, or otherwise manipulate the runtime before the server is created.  An example of how this is used can be seen at SseTransportCustomizationExtension.

CDi Lifecycle for JAX-RS Context Objects

The CDI extension also supports the injection (via CDI) of @Context objects.  Any known object can be injected via CDI.  This happens automatically when the CDI extension is used, and a @Context is declared as a field on a resource class.  Note that this does allow you to inject your @Context objects in non-JAX-RS components as well.  The logic is in two parts:

  1. Rewriting injection points
    1. When an injection point is found that contains @Context two additional annotations are added
    2. These annotations are @Inject and @ContextResolved
    3. The use of @Inject will force the CDI runtime to take over the injection of the bean value, while @ContextResolved is simply a qualifier we apply to the injection point to avoid ambiguities
  2. Providing Beans
    1. For each of the built in @Context types, we register a bean that provides a @RequestScoped bean that resolves the value, by looking up the internal context value
    2. In addition, a user or intergrator can implement ContextClassProvider to register an additional class as context type to be resolved.

 

Deploying with embedded Jetty 8/9 (programmatic configuration)

With Jetty 8/9 it possible to create fully embeddable REST / JAX-RS servers without web.xml or WAR files involved. For Apache CXF applications which are using CDI 1.1, the CXFCdiServlet servlet should be used as a starting point. Following example demonstrates the necessary configuration points in order to create embedded  embedded Jetty 8/9 instance. As a CDI 1.1 implementatoinimplementation, JBoss Weld 2.0 is being used.

Code Block
java
java
System.setProperty("java.naming.factory.url", "org.eclipse.jetty.jndi");
System.setProperty("java.naming.factory.initial", "org.eclipse.jetty.jndi.InitialContextFactory");

// Register and map the dispatcher servlet
final Server server = new Server(<port>);
final ServletHolder servletHolder = new ServletHolder(new CXFCdiServlet());
final ServletContextHandler context = new ServletContextHandler();         
context.setContextPath(contextPath<context path>);          
context.addEventListener(new Listener());         
context.addEventListener(new BeanManagerResourceBindingListener());
context.addServlet(servletHolder, "/rest/*");
server.setHandler(context);
server.start();

...

Deploying with embedded Jetty 8/9 (WAR-based deployment) 

Another option to deploy Apache CXF application with CDI 1.1 support and embedded Jetty 8/9 is by using web.xml descriptor and WAR-like deployment structure. In this case, the Apache CXF application needs to declare CXFCdiServlet servlet (and its mappings) and, if required, CDI-specific listeners (in the example below the JBoss Weld 2.0 is being used as CDI 1.1 container).

Code Block
xml
xml
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <listener>
        <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
    </listener>

    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <display-name>CXF Servlet</display-name>
        <servlet-class>org.apache.cxf.cdi.CXFCdiServlet</servlet-class>    
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

    <resource-env-ref>
        <resource-env-ref-name>BeanManager</resource-env-ref-name>
        <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager
        </resource-env-ref-type>
    </resource-env-ref>
</web-app>

The server initialization in this case looks simpler.

Code Block
java
java
System.setProperty("java.naming.factory.url", "org.eclipse.jetty.jndi");
System.setProperty("java.naming.factory.initial", "org.eclipse.jetty.jndi.InitialContextFactory");

final Server server = new Server(<port>);
final WebAppContext context = new WebAppContext();
context.setContextPath(<context path>);
context.setWar(<path to WAR folder/file>);
context.setServerClasses(new String[] { "org.eclipse.jetty.servlet.ServletContextHandler.Decorator" });
        
HandlerCollection handlers = new HandlerCollection();
handlers.setHandlers(new Handler[] {context, new DefaultHandler()});
server.setHandler(handlers);
server.start();

Please notice, usage of Jetty-specific server classes ("org.eclipse.jetty.servlet.ServletContextHandler.Decorator") is very important to allow CDI 1.1 injections (backed by JBoss Weld 2.0) to work seamlessly across servlets / listeners / filters. It is not stricktly necessary for Apache CXF (everything will work as expected) but complex applications would definitely benefit from that.TODO : in progress

Deploying with embedded Tomcat 7/8 (WAR-based deployment) 

TODO : in progress

In case of embedded Tomcat 7/8, Apache CXF application with CDI 1.1 support could be deployed with web.xml descriptor and WAR-like deployment structure, similarly to Jetty 8/9 WAR-based deployment. Apache CXF application needs to declare CXFCdiServlet servlet (and its mappings) and, if required, CDI-specific listeners (in the example below the JBoss Weld 2.0 is being used as CDI 1.1 container).

Code Block
xml
xml
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <listener>
        <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
    </listener>

    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <display-name>CXF Servlet</display-name>
        <servlet-class>org.apache.cxf.cdi.CXFCdiServlet</servlet-class>    
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

    <resource-env-ref>
        <resource-env-ref-name>BeanManager</resource-env-ref-name>
        <resource-env-ref-type>javax.enterprise.inject.spi.BeanManager
        </resource-env-ref-type>
    </resource-env-ref>
</web-app>

Tomcat 7/8 server has a different API, by still quite simple initialization procedure.

Code Block
java
java
final Tomcat server = new Tomcat();
server.setPort(<port>);

final File base = createTemporaryDirectory();
server.setBaseDir(base.getAbsolutePath());    
    
server.getHost().setAppBase(base.getAbsolutePath());
server.getHost().setAutoDeploy(true);
server.getHost().setDeployOnStartup(true);
            
server.addWebapp(<context path>, <path to WAR folder/file>);   
server.start();

Future work

The Apache CXF team is committed to improve the CDI integration and to cover more deployment scenarios and wide range of application configurations and demands. However, by and large the CDI integration is implementation-independent and it is expected to work in JBoss WildFly or other EE containers.