Jaybanuan's Blog

どうせまた調べるハメになることをメモしていくブログ

Tomcat 8でJAX-RS 2.0 (さらにCDIも利用)

はじめに

CDIを利用したJAX-RS 2.0のアプリを作成し、Tomcat 8で実行するサンプル。 web.xmlレスの情報が少ないので、まとめておく。 ビルドにはJDK 8とMaven 3を利用。 また、JAX-RS 2.0の実装としてJerseyを、CDIの実装としてWeldを利用。 実行にはServlet 3.0に対応したTomcat 7以降(ここで試したのはTomcat 8)が必要。

ディレクトリ構成

.
|-- pom.xml
`-- src
    `-- main
        |-- java
        |   `-- redj
        |       `-- hello
        |           `-- cdi
        |               `-- jersey
        |                   |-- ApplicationConfig.java
        |                   |-- Greeting.java
        |                   `-- GreetingResource.java
        `-- resources
            `-- META-INF
                `-- beans.xml

ソース

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>redj</groupId>
    <artifactId>hello-cdi-jersey</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>2.22.1</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.ext.cdi</groupId>
            <artifactId>jersey-cdi1x</artifactId>
            <version>2.22.1</version>
        </dependency>
        
        <dependency>
            <groupId>org.jboss.weld.servlet</groupId>
            <artifactId>weld-servlet-core</artifactId>
            <version>2.3.2.Final</version>
        </dependency>
    </dependencies>
</project>

weld-servlet-coreには、WebコンテナでCDIを実現するServletが含まれている。 jersey-cdi1xは、Jersey内のCDIの実装をHK2からCDIに切り替える。

src/main/java/redj/hello/cdi/jersey/Greeting.java

package redj.hello.cdi.jersey;

import javax.enterprise.context.RequestScoped;

@RequestScoped
public class Greeting {

    public String sayHello(String name) {
        return "hello," + name + "!";
    }
}

src/main/java/redj/hello/cdi/jersey/GreetingResource.java

package redj.hello.cdi.jersey;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;

@Path("greeting/{name}")
public class GreetingResource {

    @Inject
    private Greeting greeting;

    @GET
    @Produces("text/plain")
    public String sayHello(@PathParam("name") String name) {
        return greeting.sayHello(name);
    }
}

src/main/java/redj/hello/cdi/jersey/ApplicationConfig.java

package redj.hello.cdi.jersey;

import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("hello-cdi-jersey")
public class ApplicationConfig extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> classes = new HashSet<>();
        classes.add(GreetingResource.class);

        return classes;
    }
}

src/main/resources/META-INF/beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans/>

weld-servlet-coreでCDIを有効化している場合、Managed Beanを全てアノテーションで定義していたとしても空のbeans.xmlが必要になる。

https://docs.jboss.org/weld/reference/latest/en-US/html/environments.html

In general, an implicit bean archive does not have to contain a beans.xml descriptor. However, such a bean archive is not supported by Weld Servlet, i.e. it’s excluded from discovery.

ビルド

$ mvn clean install

デプロイ

$ cp target/hello-cdi-jersey-1.0-SNAPSHOT.war $CATALINA_HOME/webapps/

実行

$ curl http://localhost:8080/hello-cdi-jersey-1.0-SNAPSHOT/hello-cdi-jersey/greeting/world
hello,world!

参考