いしぐめも

プログラミングとかしたことを書きます。

Java 8 から Java 17 への移行メモ

私が携わっているOSS「Personium」のJava 8からの移行に係るトラブルに対しての対処を書いていきます。Personiumでは Java 8 → Java 11 → Java 17 というステップで移行を進めていく方針になっていて、今回は「Java 11 → Java 17」を行った際のメモです。よって「Java 8 → Java 11」で取り切れなかった不具合を含んでいる可能性も多分にありますのでご了承ください。

目次

Unsupported class file major version 61

こんなエラーが出まくりました。

Caused by: java.lang.IllegalArgumentException: Unsupported class file major version 61
        at org.jacoco.agent.rt.internal_1f1cc91.asm.ClassReader.<init>(ClassReader.java:184)
        at org.jacoco.agent.rt.internal_1f1cc91.asm.ClassReader.<init>(ClassReader.java:166)
        at org.jacoco.agent.rt.internal_1f1cc91.asm.ClassReader.<init>(ClassReader.java:152)
        at org.jacoco.agent.rt.internal_1f1cc91.core.internal.instr.InstrSupport.classReaderFor(InstrSupport.java:247)
        at org.jacoco.agent.rt.internal_1f1cc91.core.instr.Instrumenter.instrument(Instrumenter.java:86)
        at org.jacoco.agent.rt.internal_1f1cc91.core.instr.Instrumenter.instrument(Instrumenter.java:118)

上記は jacoco のバージョンが低い時に出たエラーなんですが、surefireのバージョンが低いことでも同様のエラーが発生しました。

というわけで、こちらの問題に対しては pom.xmlJava 17 対応の jacoco, surefire のバージョンを記載してあげることで解決しました。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
</plugin>
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.7</version>
</plugin>

(バージョンは一例です。)

java.lang.reflect.InaccessibleObjectException

こういうやつです。

java.lang.reflect.InaccessibleObjectException: Unable to make field protected volatile java.io.InputStream java.io.FilterInputStream.in accessible: module java.base does not "opens java.io" to unnamed module @hogehoge

どうも調べるとJava 17ではより高位なAPIがあるので、今までのローレベルなAPIは叩くなよという例外だそうです。

とはいっても、テストではゴリゴリそのAPIを使ってしまっているみたいで仕方ないのでテスト時オプションで例外的に許可してあげます。以下のように surefire の実行時引数に --add-opens で必要なパッケージを列挙します。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
        <argLine>
            --add-opens=java.base/java.io=ALL-UNNAMED
            --add-opens=java.base/java.lang=ALL-UNNAMED
        </argLine>
    </configuration>
</plugin>

文法的なものはドキュメント(Java Platform, Standard Edition Oracle JDK 9移行ガイド, リリース9)を参照していただくとして、例外の書式が以下だったとすると、

module <MODULE> does not "opens <PACKAGE>" to <TARGET_MODULE>

以下のように書けば素直に消えてくれるはずです。(TARGET_MODULEがunnamed moduleだった場合)

--add-opens=<MODULE>/<PACKAGE>=ALL-UNNAMED

ただこの、ワイルドカードが使えないみたいで、java.util java.util.regex java.util.zip など複数パッケージに対して行う必要がある場合は以下のように愚直に書いていくしか無さそうでした(やり方あったら教えてください)。

--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.base/java.util.regex=ALL-UNNAMED
--add-opens=java.base/java.util.zip=ALL-UNNAMED

コレ、1件解決したら次の1件、といった感じで芋づる式に出てくるので根気よく対処しましょう。ゆくゆくは根本対処を何かしたいところ・・・

It is forbidden to use algorithm ... 問題

SHA-1使ってたコードが軒並み動かなくなった問題です。

It is forbidden to use algorithm http://www.w3.org/2000/09/xmldsig#rsa-sha1 when secure validation is enabled

こちらは別記事にしたのでそちらをどうぞ。

yoh1496.hatenablog.com

Jerseyのバージョンが古すぎる

今まで Jersey 1.10とかいう化石のようなものを使っていたので、以下のようなエラーが出てしまっていました。

java.lang.IllegalArgumentException
    at jersey.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:170)
    at jersey.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:153)
    at jersey.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:424)

というわけで一気に2系の2.36まであげました。

1から2への移行ということで、Jersey Test Frameworkの仕様も変わっていましたが、Grizzly + Servlet を使ったテストを実装するにあたって以下のサイトがとても参考になりました。

vividcode.hatenablog.com

終わりに

以上が、PersoniumをJDK17に移行させるにあたって詰まった主な内容でした。どなたかの参考になれば幸いです。