この記事は、Java Advent Calendar 2019 15日目の記事です。
はじめに
Java8の無償サポートが2019年1月に切れてから一年ほど放置してましたが、
今回時間ができたので8以降初のLTSであるJava11への更新を行いました
その時のメモです
と書き始めようとしましたが、OpenJDK8は2023年6月までサポートされるらしいので、
OracleJDKからOpenJDKに変えるだけでよかったのでは......
でもやってしまったので記録しときます
JDKのアップデート
AdoptOpenJDK11をインストール
以下のコマンドを入れると最新のJDKがインストールされる
brew cask install adoptopenjdk
しかし、現状ではJDK13が入ってしまうので、LTS版であるJDK11を入れるにはバージョンを指定する必要がある
ということで公開されているバージョンを検索
$ brew search adoptopenjdk
==> Casks
adoptopenjdk adoptopenjdk11-openj9-jre adoptopenjdk12-openj9 adoptopenjdk13-jre adoptopenjdk8 adoptopenjdk8-openj9-large
adoptopenjdk10 adoptopenjdk11-openj9-jre-large adoptopenjdk12-openj9-jre adoptopenjdk13-openj9 adoptopenjdk8-jre adoptopenjdk9
adoptopenjdk11 adoptopenjdk11-openj9-large adoptopenjdk12-openj9-jre-large adoptopenjdk13-openj9-jre adoptopenjdk8-openj9
adoptopenjdk11-jre adoptopenjdk12 adoptopenjdk12-openj9-large adoptopenjdk13-openj9-jre-large adoptopenjdk8-openj9-jre
adoptopenjdk11-openj9 adoptopenjdk12-jre adoptopenjdk13 adoptopenjdk13-openj9-large adoptopenjdk8-openj9-jre-large
今回入れたいのはJDK11なので、以下のコマンドでバージョンを指定してインストール
brew cask install adoptopenjdk11
すでに通っているPATHをJDK11に変更
export JAVA_HOME=`/usr/libexec/java_home -v 11`
バージョンを確認
$ java -version
openjdk version "11.0.5" 2019-10-15
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.5+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.5+10, mixed mode)
IntelliJのProjectSDKにJDK11を指定
Command + ; でProjectStructureを開き、ProjectSDKとProjectLunguageLebelにJDK11を指定
Gradleをアップデート
Gradle4.4はJDK11に対応していないため、アップデートする必要がある
5.0以降のバージョンは対応しているようだが、折角なので現在の最新である6.0.1にしてみる
gradle-wrapper.propertiesの更新
gradle/wrapper/gradle-wrapper.properties に記載されているバージョンを更新すればプロジェクトに適用されるGradleのバージョンが変更される
今回は以下の 4.4 の部分を 6.0.1 に変更するだけ
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip
gradlewを更新
それだけだとgradlewに変更が伝播しないので、gradlewを生成し直す
./gradlew wrapper
gradle.buildを更新
各種フレームワーク・ライブラリをJDK11に対応したものに変更していく
基本的には全てgradle.buildに記載されているので、それを修正していけばよい
Javaのバージョン指定を変更
各指定の意味は公式に記載されているので、必要な物を指定する
sourceCompatibility = 11
targetCompatibility = 11
Gradle6系の記載方法に変更
jarの指定方法が変更になっているので更新
詳細は公式を参照のこと
jar {
baseName = 'example'
version = '1.0.0-SNAPSHOT'
}
上記だったものを以下に変更
bootJar {
archiveBaseName = "example"
archiveVersion = "1.0.0-SNAPSHOT"
}
SpiringBootのバージョンを変更
Java11を利用するにはSpringBoot2.1.x以上が必要
折角なので現在の最新である2.2.2にしてみる
基本的には公式のマイグレーションガイドに従えばいい
buildscript {
ext {
springBootVersion = '1.5.13.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
SpringBootが自動で依存関係管理プラグインを適用しなくなったので、プラグインも追加する
apply plugin: 'io.spring.dependency-management'
メインクラスの指定方法が変わっているので、それも変更
springBoot {
mainClassName = "jp.co.example.Application"
}
ライブラリのバージョンを更新
MavenRepositoryを見ながらライブラリのバージョンを更新していく
SpringBoot周りのライブラリ
SpringBoot周りのライブラリはバージョンを変数で指定しておくと楽
ただし、一部SpringBootのバージョンと異なる場合があるので注意が必要
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
compile("org.springframework.boot:spring-boot-starter-jdbc:${springBootVersion}")
compile("org.springframework.boot:spring-boot-starter-security:${springBootVersion}")
compile("org.springframework.boot:spring-boot-starter-actuator:${springBootVersion}")
testCompile("org.springframework.boot:spring-boot-starter-test:${springBootVersion}")
testCompile("org.springframework.security:spring-security-test:5.2.1.RELEASE")
}
lombok
依存関係の指定方法が変わっているため、普通にバージョンだけ指定して更新するとビルド時にlombokで自動生成されるメソッドが見つからないとエラーが出る
公式を参考にして、以下の指定を追加する
compileOnly('org.projectlombok:lombok:1.18.10')
annotationProcessor('org.projectlombok:lombok:1.18.10')
また、@Valueを使っていると、Jacksonでのデシリアライズがうまく機能しないエラーが発生する
project直下に lombok.config というファイルを作って以下を記載することで回避できる
その他の設定については公式のマイグレーションガイドに記載がある
lombok.addJavaxGeneratedAnnotation = false
lombok.addLombokGeneratedAnnotation = true
lombok.noArgsConstructor.extraPrivate = false
lombok.anyConstructor.addConstructorProperties = true
config.stopBubbling = true
jjwt
一部のアルゴリズムを利用する際にJava11で廃止されたAPIに依存しているため、
Java8時点で利用していてJava11に移行してきた場合、依存関係を追加する必要がある
公式を参考に以下を追加する
compile('javax.xml.bind:jaxb-api:2.3.0')
compile('com.sun.xml.bind:jaxb-core:2.3.0')
compile('com.sun.xml.bind:jaxb-impl:2.3.0')
その他
よしなに更新する
dependencies 以外で指定しているライブラリについても忘れず更新すること
jacoco の更新を忘れて時間を無駄にしました
Java11で廃止になったAPIに対応する
この記事を参考に廃止になったAPIを修正していく
SpringBoot2.0で廃止になったクラスを修正する
ビルドしてみるとSpringBoot周りで廃止されたクラスが複数出てくるので、それを修正していく
公式のマイグレーションガイドを参考にする
今回はエラーメッセージを制御していた org.springframework.boot.autoconfigure.web 周りのクラスだけが対象だった
以下のメソッドを
@RequestMapping(value = "/error")
public ErrorResponse error(HttpServletRequest request, HttpServletResponse response) {
ServletRequestAttributes attributes = new ServletRequestAttributes(request);
Throwable error = errorAttributes.getError(attributes);
return convertException(error);
}
こうする
@RequestMapping(value = "/error")
public ErrorResponse error(WebRequest request) {
Throwable error = errorAttributes.getError(request);
return convertException(error);
}
テストしてみる
ここまでやるととりあえずビルドが通るようになるので、テストを回してデグレが起きていないか確認する
今回は特に問題なさそう
Warnの解消は後回しにして、とりあえずJDK11対応済みのアプリをDockerに固めてデプロイすることを目指す
Dockerfileを変更する
Dockerfileはベースイメージの変更だけでよい
どのイメージを選択すればいいかはこの記事が参考になる
今回はおすすめの通り、adoptopenjdk/openjdk11:alpine-slim を選択する
FROM adoptopenjdk/openjdk11:alpine-slim
その他
CircleCIの設定を変更する
CI/CDツールを利用している場合はそちらの設定も忘れず変更すること
テスト環境構築時のベースイメージの指定等、忘れがち
SpringBootActuator
SpringBootActuatorで自動生成される全てのエンドポイントに/actuatorのprefixが追加されているので注意が必要
特に /health を利用しているとデプロイがうまくいかなくなる
その他の変更点はこの記事が参考になる
さいごに
以上の修正でとりあえずデプロイできる状態にはなっているはずです
何か問題が起きれば適宜追記していきます
「こっちの書き方の方が正しい」「これだとバグる可能性がある」等あれば是非教えてください
参考
mac上にhomebrewでAdoptOpenJDK11をインストール
Gradle wrapper のバージョン更新についてのメモ
Spring Boot 1.5.10 → Spring Boot 2.0.0 にしたときの覚書
Spring Boot 2.0 Migration Guide
Java 11 リリース後のオススメ Docker イメージを考える
Spring Boot 2.0のActuator、とりあえず動かすために知っておきたい変更点3つ
Javaエンジニアが Java 11 リリースに向けて備えておくべきこと
ObjectMapper can't deserialize without default constructor after upgrade to Spring Boot 2