2018/07/04

事例から学ぶ、Java SE 11移行

このエントリーをはてなブックマークに追加

Java SE 11のリリースまで3か月を切りました。みなさん、移行の準備は進んでいますでしょうか。

Java SE 11は、新しいリリースモデルになってはじめてのLTSになるバージョンです。なので、Java 9や10はすっ飛ばして、Java 11に移行することを考えている方も多いと思います。

しかし、Java 11への移行はいろいろ大変です。

今回は簡単なサンプルをベースにJava 11への移行を考えてみます。

Jersey + Grizzly

Jerseyは、JAX-RSのRIです。ということは、私よりもこれ読んでいる人の方が絶対に詳しいはずw

そのJerseyのUser GuideのGetting Startedに書いてあるサンプルを題材にしてみましょう。

このサンプルはMavenで勝手に作ってくれます。以下はGetting Startedからの引用です。

mvn archetype:generate -DarchetypeArtifactId=jersey-quickstart-grizzly2 \
-DarchetypeGroupId=org.glassfish.jersey.archetypes -DinteractiveMode=false \
-DgroupId=com.example -DartifactId=simple-service -Dpackage=com.example \
-DarchetypeVersion=2.27

さて、とりあえず、コンパイルしてみましょう。

C:\jersey-sample\simple-service>mvn compile
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< com.example:simple-service >---------------------
[INFO] Building simple-service 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ simple-service ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory C:\jersey-sample\simple-service\src\main\resources
[INFO]
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ simple-service ---
[INFO] Compiling 2 source files to C:\jersey-sample\simple-service\target\classes
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.721 s
[INFO] Finished at: 2018-07-04T19:15:21+09:00
[INFO] ------------------------------------------------------------------------
C:\jersey-sample\simple-service>

依存しているライブラリがなければ、ダウンロードするログが出るはずですが、コンパイルは成功するはずです。

では、実行してみましょう。

C:\jersey-sample\simple-service>mvn exec:java
[INFO] Scanning for projects...
[INFO] 
[INFO] ---------------------< com.example:simple-service >---------------------
[INFO] Building simple-service 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] >>> exec-maven-plugin:1.2.1:java (default-cli) > validate @ simple-service >>>
[INFO] 
[INFO] <<< exec-maven-plugin:1.2.1:java (default-cli) < validate @ simple-service <<<
[INFO] 
[INFO] 
[INFO] --- exec-maven-plugin:1.2.1:java (default-cli) @ simple-service ---
7月 04, 2018 7:29:51 午後 org.glassfish.jersey.internal.Errors logErrors
警告: The following warnings have been detected: WARNING: HK2 service reification failed for [org.glassfish.jersey.message.internal.DataSourceProvider] with an exception:
MultiException stack 1 of 2
java.lang.NoClassDefFoundError: javax/activation/DataSource
 at java.base/java.lang.Class.getDeclaredConstructors0(Native Method)
 at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3114)
  <<以下、省略>>

NoClassDefFoundErrorで実行できませんでした。

このサンプルはJava 8までは普通に実行できます。でも、Java 11で実行できないのはJava EE (Jakarta EE)関連のAPIが削除されてしまったためです。

上の実行例でNoClassDefFoundErrorが出ているのは、javax.activation.DataSourceクラスがないためですが、このクラスはJavaBean Activation Framework (JAF) APIに含まれています。

他にも、JAXBのクラスもNoClassDefFoundErrorが出ています。

しかし、このサンプルのソースコードは、JAFもJAXBも使っていません。これらを使っているのは、JerseyやGrizzlyなのです。

だから、コンパイルは通るのに、実行はできないわけです。

JAXBは使っていないと安心されているかもしれませんが、多くのライブラリでJAXBやJAFを使っています。これが落とし穴になるわけですね。

解決法

では、Java 11で動作するようにしてみましょう。

今回はモジュールアプリケーションではないので、比較的簡単です。つまり、クラスパスに不足しているライブラリを追加するだけでOKです。

実際には、pom.xmlにJAXBとJAFへの依存を記述していきます。

変更したpom.xmlを以下に示します。赤字のところが変更した部分です。

<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>simple-service</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>simple-service</name>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jersey</groupId>
                <artifactId>jersey-bom</artifactId>
                <version>${jersey.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-grizzly2-http</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
     <artifactId>jaxb-api</artifactId>
     <version>2.3.0</version>
        </dependency>      
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
     <artifactId>jaxb-impl</artifactId>
     <version>2.3.0.1</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
     <artifactId>javax.activation-api</artifactId>
     <version>1.2.0</version>
        </dependency>

        <!-- uncomment this to get JSON support:
         <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-binding</artifactId>
        </dependency>
        -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.9</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <inherited>true</inherited>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.6.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>com.example.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <properties>
        <jersey.version>2.27</jersey.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
</project>

 

pluginのところの変更はバージョンを最新にしただけです。

重要なのは<dependencies>の部分。

依存しているライブラリとして

  • jaxb-api
  • jaxb-impl
  • javax.activation-api

を追加しています。

これでビルドしなおしてから、実行してみましょう。

C:\jersey-sample\simple-service>mvn exec:java
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------< com.example:simple-service >---------------------
[INFO] Building simple-service 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ simple-service ---
7月 04, 2018 20:24:38 午後 org.glassfish.grizzly.http.server.NetworkListener start
情報: Started listener bound to [localhost:8080]
7月 04, 2018 20:24:38 午後 org.glassfish.grizzly.http.server.HttpServer start
情報: [HttpServer] Started.
Jersey app started with WADL available at http://localhost:8080/myapp/application.wadl
Hit enter to stop it...

ここまで表示されたら、ブラウザでもcurlでもいいので、http://localhost:8080/myapp/myresourceにアクセスしてみてください。Got it!と表示されるはずです。

 

まとめ

  • Java 11では、ほんとにJAXB、JAF、JAX-WSなどが削除されました
  • 使っていないと思っていても、意外に使われているのがJAXBとJAF
  • モジュールアプリケーションでなければ、クラスパスにJAXBとJAFのJarを追加するだけ
  • Mavenであれば、pom.xmlの<dependencies>にJAXBとJAFを追加する

 

モジュールアプリケーションの場合はどうするのかについては、需要があれば書こうと思います。

0 件のコメント: