GlassFishからWildFlyへの移植 (JAX-RS)

# 概要

GlassFishからWildFlyにJAX-RSのサンプルアプリケーションを移植してみました。

# 環境

* WildFly 8.0.0.Final
* GlassFish 3.1.2.2

# サンプルアプリケーション

web.xmlでJerseyの設定をしています。

```xml:pom.xml
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <type>jar</type>
        </dependency>
```

```xml:web.xml
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>
            com.sun.jersey.spi.container.servlet.ServletContainer
        </servlet-class>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
    
</web-app>
```

APIはこんな感じ。getter/setterは省略しています。

```java:Resources.java
@Path("resources")
public class Resources {
        
    @Path("get")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public ApiResponse get() {
        ApiResponse res = new ApiResponse();       
        res.setA("hoge");
        List<Child> clist = res.getC();
        Child c = new Child();
        c.setI(1);
        clist.add(c);
        return res;
    }

    public static class ApiResponse {
        private String a;
        private List<Child> c;

        public static class Child {
            private int i;
        }
    }
}
```

GlassFishにデプロイして、APIを叩くと結果が得られます。

```json:http://localhost:8080/rest/api/resources/get
{"a":"hoge","c":[{"i":1}]}
```

# WildFly向けの修正

とりあず、そのままWildFlyにデプロイするとエラーになります。

```
{"JBAS014671: Failed services" => {"jboss.deployment.unit.\"rest.war\".POST_MODULE" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"rest.war\".POST_MODULE: JBAS018733: Failed to process phase POST_MODULE of deployment \"rest.war\"
    Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException: java.lang.ClassNotFoundException: com.sun.jersey.spi.container.servlet.ServletContainer from [Module \"deployment.rest.war:main\" from Service Module Loader]
    Caused by: java.lang.ClassNotFoundException: com.sun.jersey.spi.container.servlet.ServletContainer from [Module \"deployment.rest.war:main\" from Service Module Loader]"}}
```

JAX-RSのモジュールがGlassFishはJersey、WildFlyはRESTEasyのため、web.xmlのjerseyの定義のところでClassNotFoundExceptionが発生しています。

web.xmlの記述を修正し、JerseyではなくRESTEasyを指定します。

```xml:web.xml
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <servlet>
        <servlet-name>resteasy</servlet-name>
        <servlet-class>
            org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>resteasy</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>resteasy.scan</param-name>
        <param-value>true</param-value>
    </context-param>            
    <context-param>
        <param-name>resteasy.servlet.mapping.prefix</param-name>
        <param-value>/api</param-value>
    </context-param>        
        
</web-app>
```

resteasy.scanでJAX-RSのResource (@GET、@POST、...)、Provider (@Provider) クラスが自動登録されます。

url-patternでパスを指定する場合は、resteasy.servlet.mapping.prefixの記述が必要になります。

# 補足

web.xmlでJAX-RSのリソースを定義する方法は、Servlet 3.0 ではそもそも deprecated です。今回は実在するプロジェクトの構成を真似て作ったのでこのようになっています。

RESTEasy のドキュメントの「3.8. javax.ws.rs.core.Application」にあるように、
Applicationクラスを使うのが推奨されるやり方です。

# 参考
* RESTEasy Documentation: http://docs.jboss.org/resteasy/docs/3.0.7.Final/userguide/html_single/index.html, 3.6. Standalone Resteasy in Older Servlet Containers