かんがるーさんの日記

最近自分が興味をもったものを調べた時の手順等を書いています。今は Spring Boot をいじっています。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その7 )( Error Prone を 2.3.4 → 2.4.0 へバージョンアップする )

概要

記事一覧はこちらです。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その6 )( PMD を 6.20.0 → 6.26.0 へバージョンアップする ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Error Prone を 2.3.4 → 2.4.0 へバージョンアップします。

参照したサイト・書籍

  1. Command-line flags
    https://errorprone.info/docs/flags

  2. Criteria for new checks
    https://errorprone.info/docs/criteria

目次

  1. build.gradle を変更する
  2. 警告の原因を取り除く
    1. 警告:[EmptyBlockTag] A block tag (@param, @return, @throws, @deprecated) has an empty description. Block tags without descriptions don't add much value for future readers of the code; consider removing the tag entirely or adding a description.
    2. 警告:[MissingSummary] A summary line is required on public/protected Javadocs.
    3. 警告:[InlineFormatString] Prefer to create format strings inline, instead of extracting them to a single-use constant
    4. 警告:[InvalidThrows] The documented method doesn't actually throw this checked exception.
    5. 警告:[JdkObsolete] StringBuffer performs synchronization that is usually unnecessary; prefer StringBuilder.
  3. 2.4.0 から追加された WARNING の check を有効にするには build.gradle に options.errorprone.errorproneArgs.add("-Xep:<checkName>") を記述する
  4. メモ書き

手順

build.gradle を変更する

plugins {
    id "java"
    id "eclipse"
    id "idea"
    id "org.springframework.boot" version "2.3.2.RELEASE"
    id "io.spring.dependency-management" version "1.0.9.RELEASE"
    id "groovy"
    id "checkstyle"
//    id "com.github.spotbugs" version "3.0.0"
    id "pmd"
    id "net.ltgt.errorprone" version "1.2.1"
    id "com.gorylenko.gradle-git-properties" version "2.2.3"
}

..........

[compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8"
[compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"]
tasks.withType(JavaCompile).configureEach {
    options.errorprone.disableWarningsInGeneratedCode = true
}
tasks.named("compileTestJava").configure {
    options.errorprone.enabled = false
}

..........

dependencies {
    def jdbcDriver = "org.postgresql:postgresql:42.2.14"
    def spockVersion = "1.3-groovy-2.5"
    def domaVersion = "2.26.0"
    def lombokVersion = "1.18.12"
    def errorproneVersion = "2.4.0"
    def powermockVersion = "2.0.7"
    def spotbugsVersion = "4.0.0-beta4"
    ..........
  • plugins block の以下の点を変更します。
    • id "net.ltgt.errorprone" version "1.1.1"id "net.ltgt.errorprone" version "1.2.1"
  • tbroyer / gradle-errorprone-plugin に記載されていた記述で、今回 build した時に自動生成されたコードに対しても Error Prone が警告を出したので tasks.withType(JavaCompile).configureEach { options.errorprone.disableWarningsInGeneratedCode = true } を追加します。
  • dependencies block の以下の点を変更します。
    • def errorproneVersion = "2.3.4"def errorproneVersion = "2.4.0"

Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると compileJava タスクで警告が 100個以上出ました(コンソールには 100個と出力されていますが警告が 100個以上あっても1度には 100個までしか出力されません)。

f:id:ksby:20200818002529p:plain

警告の原因を取り除く

警告:[EmptyBlockTag] A block tag (@param, @return, @throws, @deprecated) has an empty description. Block tags without descriptions don't add much value for future readers of the code; consider removing the tag entirely or adding a description.

Error Prone のマニュアルの EmptyBlockTag です。Javadoc で @param, @return, @throws, @deprecated の説明文を記述していないと警告が出るようになっていました。@throws の説明文を記述していなかったのが原因です。

f:id:ksby:20200818010123p:plain

@throws の説明文を追加します。

警告:[MissingSummary] A summary line is required on public/protected Javadocs.

Error Prone のマニュアルの MissingSummary です。public/protected の Javadoc で summary line を記述していないと警告が出るようになっていました。

f:id:ksby:20200818010727p:plain

summary line を記述します。

警告:[InlineFormatString] Prefer to create format strings inline, instead of extracting them to a single-use constant

Error Prone のマニュアルの InlineFormatString です。String.format で呼び出すフォーマット文字列を定数で定義していたのですが、inline で書くか helper メソッドを使用するよう警告が出ていました。正しい引数を渡しているかチェックしにくいので String.format とフォーマット文字列は近くに書くように、という指摘のようです。

f:id:ksby:20200818015808p:plain

今回は定数をやめて inline に変更します。

警告:[InvalidThrows] The documented method doesn't actually throw this checked exception.

Error Prone のマニュアルの InvalidThrows です。throws がないのに Javadoc に @throws を記述していたので警告が出ていました。

f:id:ksby:20200818020906p:plain

削除します。

警告:[JdkObsolete] StringBuffer performs synchronization that is usually unnecessary; prefer StringBuilder.

Error Prone のマニュアルの JdkObsolete です。指摘されたのは以下の箇所で、

f:id:ksby:20200819225119p:plain

HttpServletRequest#getRequestURL の戻り値の型が StringBuffer のためでした。

f:id:ksby:20200819232153p:plain

String 型を返す HttpServletRequest#getRequestURI に変更します。

2.4.0 から追加された WARNING の check を有効にするには build.gradle に options.errorprone.errorproneArgs.add("-Xep:<checkName>") を記述する

https://github.com/google/error-prone/releases/tag/v2.4.0 を見ると new checks に追加された check が記述されていますが、CheckedExceptionNotThrown が検知できるのか試してみたいと思い、 ksbysample.webapp.lending.ErrorProneCheck クラスを作成して以下の内容を記述した後、

f:id:ksby:20200820000038p:plain

compileJava タスクを実行しても何も検知されませんでした。

f:id:ksby:20200820000303p:plain

Error Prone のマニュアルを見ると SerSeverity.WARNING の check については、

f:id:ksby:20200820000921p:plain

build.gradle に options.errorprone.errorproneArgs.add("-Xep:<checkName>") の記述を追加しないと有効にならないからでした。

build.gradle に 'options.errorprone.errorproneArgs.add("-Xep:CheckedExceptionNotThrown")' を追加してから、

tasks.withType(JavaCompile).configureEach {
    options.errorprone.disableWarningsInGeneratedCode = true
    options.errorprone.errorproneArgs.add("-Xep:CheckedExceptionNotThrown")
}

compileJava タスクを実行すると今度は 警告:[CheckedExceptionNotThrown] This method cannot throw a checked exception that it claims to. This may cause consumers of the API to incorrectly attempt to handle, or propagate, this exception. のメッセージが出力されました。

f:id:ksby:20200820001543p:plain

メモ書き

これまで全然何もエラー・警告を出さなかったのに 2.4.0 にバージョンアップしたら急に警告が出るようになりました。しかも実装に関する警告よりも Javadoc の警告が出るようになったのが意外です。Checkstyle、PMD に加えて Error Prone も入れておけば Javadoc の記述漏れをかなり検知できるのではないでしょうか。

履歴

2020/08/20
初版発行。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その6 )( PMD を 6.20.0 → 6.26.0 へバージョンアップする )

概要

記事一覧はこちらです。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その5 )( Checkstyle を 8.28 → 8.35 へバージョンアップする ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • PMD を 6.20.0 → 6.26.0 へバージョンアップします。

参照したサイト・書籍

目次

  1. build.gradle を変更する
  2. 警告の原因を取り除く
    1. The initializer for variable '...' is never used (overwritten on line ...)

手順

build.gradle を変更する

pmd {
    toolVersion = "6.26.0"
    sourceSets = [project.sourceSets.main]
    ignoreFailures = true
    consoleOutput = true
    ruleSetFiles = rootProject.files("/config/pmd/pmd-project-rulesets.xml")
    ruleSets = []
}
  • toolVersion = "6.20.0"toolVersion = "6.26.0" に変更します。

Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると pmdMain タスクで警告が出ました。

f:id:ksby:20200815104254p:plain

警告の原因を取り除く

The initializer for variable '...' is never used (overwritten on line ...)

生成されたレポートファイル build/reports/pmd/main.html をブラウザで開くと2箇所指摘されており、どちらも Problem には The initializer for variable '...' is never used (overwritten on line ...) が表示されていました。

f:id:ksby:20200815104812p:plain

6.26.0 から追加された UnusedAssignment による警告でした。

  • 2箇所は、変数宣言時に = null と初期値をセットしていたが、その後の処理で必ず値がセットされるので警告が出ていたのが原因でした。変数宣言時に初期値をセットしている部分を削除します。
  • 1箇所はデータをロックするために select していた時に取得したデータを使用しないにもかかわらず変数にセットしていたのが原因でした。取得したデータを変数にセットしないように変更します。

変更後に clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると BUILD SUCCESSFUL が表示されました。

f:id:ksby:20200815105845p:plain

履歴

2020/08/15
初版発行。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その5 )( Checkstyle を 8.28 → 8.35 へバージョンアップする )

概要

記事一覧はこちらです。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その4 )( Release Notes を見て必要な箇所を変更する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Checkstyle を 8.28 → 8.35 へバージョンアップします。
    • 最新版の google_checks.xml の内容も反映します。

参照したサイト・書籍

  1. checkstyle / checkstyle
    https://github.com/checkstyle/checkstyle

  2. checkstyle/checkstyle - checkstyle/src/main/resources/google_checks.xml
    https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/google_checks.xml

目次

  1. build.gradle を変更する
  2. IntelliJ IDEA の CheckStyle-IDEA Plugin が使用する Checkstyle のバージョンを 8.34 に変更する
  3. 最新版の google_checks.xml から設定をコピーする

手順

build.gradle を変更する

checkstyle {
    configFile = file("${rootProject.projectDir}/config/checkstyle/google_checks.xml")
    toolVersion = "8.35"
    sourceSets = [project.sourceSets.main]
}
  • toolVersion = "8.28"toolVersion = "8.35" に変更します。

Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると BUILD SUCCESSFUL が表示されました。

f:id:ksby:20200812224944p:plain

IntelliJ IDEA の CheckStyle-IDEA Plugin が使用する Checkstyle のバージョンを 8.34 に変更する

CheckStyle-IDEA Plugin に指定できるバージョンが 8.34 までだったので 8.34 を指定します。

f:id:ksby:20200812225531p:plain

最新版の google_checks.xml から設定をコピーする

最新版の google_checks.xml から差分を反映します。。。が、2020/08/12 時点の google_checks.xml の差分を反映したところ checkstyleMain タスクでいくつかエラーが出て削除することがありました。

今回反映した内容を箇条書きで記述しておきます。

  • <module name="RightCurly"><property name="tokens">valueENUM_DEF, INTERFACE_DEF を追加しました。
  • <module name="SuppressionXpathSingleFilter">...</module> を追加しました。
  • <module name="WhitespaceAfter">...</module> を追加しました。
  • <module name="AbbreviationAsWordInName"><property name="tokens">value に PATTERN_VARIABLE_DEF を追加しました。
  • <module name="NoWhitespaceBefore"><property name="tokens">value から ELLIPSIS を削除し LABELED_STAT を追加しました。

以下の変更は checkstyleMain タスク実行時にエラーが出たので削除しました。Java 14 の機能向けの定義のようです。つまり google_checks.xml には Java 14 向けの定義も記述されるので Java 11 で開発する場合にはそのままでは使えない(エラーが出たものは取り除く必要がある)ということでした。

  • <module name="EmptyLineSeparator"><property name="tokens">value に RECORD_DEF を追加。
  • <module name="PatternVariableName">...</module> の追加。
  • <module name="AbbreviationAsWordInName"><property name="tokens">value に RECORD_DEF, RECORD_COMPONENT_DEF を追加。
  • <module name="MethodParamPad"><property name="tokens">value に RECORD_DEF を追加。
  • <module name="ParenPad"><property name="tokens">value に RECORD_DEF を追加。

変更後に clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると BUILD SUCCESSFUL が表示されました。

f:id:ksby:20200813001139p:plain

履歴

2020/08/13
初版発行。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その4 )( Release Notes を見て必要な箇所を変更する )

概要

記事一覧はこちらです。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その3 )( Spring Boot を 2.2.9 → 2.3.2 へバージョンアップする ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。

参照したサイト・書籍

  1. Spring BootのGraceful shutdownって内部でどうやって実現されているの?
    https://speakerdeck.com/kawakawaryuryu/spring-bootfalsegraceful-shutdowntutenei-bu-dedouyatuteshi-xian-sareteirufalse

  2. Spring BootのGraceful shutdown処理が内部でどう呼ばれているかソースコードリーディングしてみた結果
    https://qiita.com/kawakawaryuryu/items/bc92453f9c43d98c1a26

  3. Spring Boot 2.3 の Liveness & Readiness Probes 対応 について調べてみた
    https://speakerdeck.com/otty375/spring-boot-2-dot-3-liveness-and-readiness-probes

  4. Kubernetes Probes
    https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-kubernetes-probes

  5. Liveness and Readiness Probes with Spring Boot
    https://spring.io/blog/2020/03/25/liveness-and-readiness-probes-with-spring-boot

  6. Liveness and Readiness Probes in Spring Boot
    https://www.baeldung.com/spring-liveness-readiness-probes

  7. Kubernetes のヘルスチェック(Liveness Probe,Readiness Probe)を検証する
    https://qiita.com/toshihirock/items/c7e94e70c1c9650488df

目次

  1. server.shutdown=graceful を設定する
  2. management.endpoint.health.probes.enabled=true を設定する

手順

server.shutdown=graceful を設定する

Graceful shutdown によると 設定ファイルに server.shutdown=graceful を記述すれば Graceful shutdown をしてくれるようになったので、src/main/resources/application.properties に設定します。

..........
management.endpoint.health.show-details=always

server.shutdown=graceful

#spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration
spring.datasource.hikari.jdbc-url=jdbc:postgresql://localhost/ksbylending
..........

動作を確認するために src/main/java/ksbysample/webapp/lending/web/GracefulShutdownTestController.java を新規作成して以下の内容を記述します。http://localhost:8080/gracefulShutdownTest にアクセスすると 5分間 sleep してからレスポンスを返す Controller クラスです。Graceful shutdown が有効になっていれば、この URL にアクセスしてから Tomcat を停止しようとすると 30秒(spring.lifecycle.timeout-per-shutdown-phase のデフォルト値)待ってから停止するはず。

package ksbysample.webapp.lending.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * Spring Boot 2.3 から追加された Graceful shutdown の機能をテストするための Controller
 */
@Controller
public class GracefulShutdownTestController {

    /**
     * アクセス後 5分 sleep してからレスポンスを返す
     *
     * @return "OK"の文字列
     * @throws InterruptedException
     */
    @GetMapping("/gracefulShutdownTest")
    @ResponseBody
    public String index() throws InterruptedException {
        Thread.sleep(60_000 * 5);
        return "OK";
    }

}

src/main/java/ksbysample/webapp/lending/config/WebSecurityConfig.java.antMatchers("/gracefulShutdownTest/**").permitAll() の記述を追加して、認証不要にします。

    @Configuration
    public static class FormLoginWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    // 認証の対象外にしたいURLがある場合には、以下のような記述を追加します
                    // 複数URLがある場合はantMatchersメソッドにカンマ区切りで対象URLを複数列挙します
                    // .antMatchers("/country/**").permitAll()
                    ..........
                    .antMatchers("/sample/**").permitAll()
                    .antMatchers("/gracefulShutdownTest/**").permitAll()
                    .anyRequest().hasAnyRole("USER", "ADMIN", "APPROVER");
            ..........

Tomcat を起動して Graceful shutdown の機能を試してみると、

  • IntelliJ IDEA から起動した時は機能しません。すぐに Tomcat が停止します(停止は Navigation bar や Services Tool Window の Stop ボタンで行いました)。
  • jar ファイルを作成してコマンドラインすると、/gracefulShutdownTest にアクセスして 5秒後に Ctrl+C を押す → 30秒何も起こらない → バッチ ジョブを終了しますか (Y/N)? が表示される、という動きになりました。Graceful shutdown が機能しています。
2020-08-09 20:50:50.080  INFO 23156 --- [SpringContextShutdownHook] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
2020-08-09 20:50:50.709  INFO 23156 --- [SpringContextShutdownHook] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2020-08-09 20:50:50.714  INFO 23156 --- [SpringContextShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete
2020-08-09 20:51:20.717  INFO 23156 --- [SpringContextShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Failed to shut down 1 bean with phase value 2147483647 within timeout of 30000ms: [webServerGracefulShutdown]
2020-08-09 20:51:20.740  INFO 23156 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown aborted with one or more requests still active
..........
2020-08-09 20:51:22.954  INFO 23156 --- [SpringContextShutdownHook] o.s.a.r.l.SimpleMessageListenerContainer : Shutdown ignored - container is not active already
2020-08-09 20:51:22.955  INFO 23156 --- [SpringContextShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2020-08-09 20:51:22.963  INFO 23156 --- [SpringContextShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-08-09 20:51:22.977  INFO 23156 --- [SpringContextShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
2020-08-09 20:51:23.018  WARN 23156 --- [SpringContextShutdownHook] io.lettuce.core.RedisChannelHandler      : Connection is already closed
2020-08-09 20:51:23.018  WARN 23156 --- [SpringContextShutdownHook] io.lettuce.core.RedisChannelHandler      : Connection is already closed
2020-08-09 20:51:23.018  WARN 23156 --- [SpringContextShutdownHook] io.lettuce.core.RedisChannelHandler      : Connection is already closed
2020-08-09 20:51:23.048  INFO 23156 --- [SpringContextShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService
2020-08-09 20:51:23.049  WARN 23156 --- [SpringContextShutdownHook] io.lettuce.core.RedisChannelHandler      : Connection is already closed
  • nssm.exe でサービスに登録して起動した時に Graceful shutdown したい場合、登録時に「Shutdown」タブで「Generate Control-C」だけをチェックして「Timeout」に spring.lifecycle.timeout-per-shutdown-phase に設定した時間より長い時間をセットする必要があります(デフォルトでは全てチェックされていて「Timeout」に 1500 がセットされている)。

    f:id:ksby:20200810234708p:plain

    この設定にすると、サービス起動 → /gracefulShutdownTest にアクセスして 5秒後に「サービスの停止」リンククリック → 60秒何も起こらない(spring.lifecycle.timeout-per-shutdown-phase に設定された秒数ではなく nssm.exe で設定した Timeout の秒数) → サービスが停止する、という動きになりました。ログファイルを見ると Graceful shutdown が機能して Tomcat は 30秒後に停止していますが、サービスが停止するまでには nssm.exe で設定した Timeout の秒数を待つ必要があります(処理中のリクエストがなくてもnssm.exe で設定した Timeout の秒数を必ず待つようになります)。

2020-08-10 23:50:46.445  INFO 3384 --- [SpringContextShutdownHook] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
2020-08-10 23:50:46.979  INFO 3384 --- [SpringContextShutdownHook] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2020-08-10 23:50:46.983  INFO 3384 --- [SpringContextShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete
2020-08-10 23:51:16.987  INFO 3384 --- [SpringContextShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Failed to shut down 1 bean with phase value 2147483647 within timeout of 30000ms: [webServerGracefulShutdown]
2020-08-10 23:51:16.989  INFO 3384 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown aborted with one or more requests still active
..........
2020-08-10 23:51:19.272  INFO 3384 --- [SpringContextShutdownHook] o.s.a.r.l.SimpleMessageListenerContainer : Shutdown ignored - container is not active already
2020-08-10 23:51:19.273  INFO 3384 --- [SpringContextShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2020-08-10 23:51:19.283  INFO 3384 --- [SpringContextShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-08-10 23:51:19.297  INFO 3384 --- [SpringContextShutdownHook] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.
2020-08-10 23:51:19.357  INFO 3384 --- [SpringContextShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService
2020-08-10 23:51:19.358  WARN 3384 --- [SpringContextShutdownHook] io.lettuce.core.RedisChannelHandler      : Connection is already closed
  • ローカルで Docker で Tomcat を起動した場合、Commencing graceful shutdown. のログが出力されましたので Graceful shutdown が機能しています。
2020-08-11 00:15:11.433  INFO 1 --- [extShutdownHook] o.s.a.r.l.SimpleMessageListenerContainer : Waiting for workers to finish.
2020-08-11 00:15:12.174  INFO 1 --- [extShutdownHook] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2020-08-11 00:15:12.180  INFO 1 --- [extShutdownHook] o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete

management.endpoint.health.probes.enabled=true を設定する

Liveness and Readiness probes によると、アプリが実行中かどうか(liveness)、リクエストに応答できる準備が出来ているかどうか(readiness)を Actuator で取得できる機能が提供されたとのこと。Kubernetes 環境向けの機能なので、KubernetesContainer probes の説明が分かりやすいです。

Kubernetes の環境で実行しないとあまり意味はなさそうですが(Kubernetes 環境だと自動で設定されるらしい)、面白そうなので設定してみます。

src/main/resources/application.properties を以下のように変更します。

..........
management.endpoint.health.show-details=always
management.endpoint.health.probes.enabled=true
management.endpoint.health.group.liveness.include=livenessStateProbeIndicator,cacheCheck
management.endpoint.health.group.readiness.include=readinessStateProbeIndicator,cacheCheck

server.shutdown=graceful

..........
  • 以下の3行を追加します。
    • management.endpoint.health.probes.enabled=true
    • management.endpoint.health.group.liveness.include=livenessStateProbeIndicator,cacheCheck
    • management.endpoint.health.group.readiness.include=readinessStateProbeIndicator,cacheCheck
  • Liveness and Readiness probes には management.endpoint.health.probes.enabled=true の記述しかないのですが、他の2つも設定しないと /actuator/health/liveness、/actuator/health/readiness にアクセスした時に 404 Not Found が返ってきました。

Tomcat を起動してから http://localhost:8080/actuator/health/liveness にアクセスすると 200 OK と以下の画像のレスポンスが返ってきました。

f:id:ksby:20200812000549p:plain

http://localhost:8080/actuator/health/readiness も 200 OK が返ってきます。

f:id:ksby:20200812000744p:plain

履歴

2020/08/12
初版発行。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その3 )( Spring Boot を 2.2.9 → 2.3.2 へバージョンアップする )

概要

記事一覧はこちらです。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その2 )( Spring Boot を 2.2.2 → 2.2.9 へ、Gradle を 6.0.1 → 6.5.1 へバージョンアップする ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Spring Boot を 2.2.9 → 2.3.2 へバージョンアップします。

参照したサイト・書籍

目次

  1. Spring Initializr で 2.3.2 のプロジェクトを作成する
  2. build.gradle を変更する
  3. build タスク実行時に出るエラーを修正する

手順

Spring Initializr で 2.3.2 のプロジェクトを作成する

Spring Initializr で 2.3.2 のプロジェクトを作成して、生成された build.gradle を見て反映した方が良い点があるか確認します。

f:id:ksby:20200809110940p:plain f:id:ksby:20200809111033p:plain f:id:ksby:20200809111134p:plain f:id:ksby:20200809111217p:plain f:id:ksby:20200809111258p:plain f:id:ksby:20200809111349p:plain f:id:ksby:20200809111529p:plain ※リストの一番下の「PostgreSQL Driver」もチェックします。 f:id:ksby:20200809111642p:plain f:id:ksby:20200809111729p:plain f:id:ksby:20200809111838p:plain f:id:ksby:20200809111951p:plain

以下の build.gradle が作成されました。

plugins {
    id 'org.springframework.boot' version '2.3.2.RELEASE'
    id 'io.spring.dependency-management' version '1.0.9.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-data-redis'
    implementation 'org.springframework.boot:spring-boot-starter-freemarker'
    implementation 'org.springframework.boot:spring-boot-starter-mail'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.session:spring-session-data-redis'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'org.postgresql:postgresql'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    testImplementation 'org.springframework.security:spring-security-test'
}

test {
    useJUnitPlatform()
}

以下の点を build.gradle に反映します。

  • configurations block から以下の2行を削除します。
    • developmentOnly
    • runtimeClasspath.extendsFrom developmentOnly

build.gradle を変更する

buildscript {
    ext {
        group "ksbysample"
        version "2.3.2-RELEASE"
    }
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/release/" }
        gradlePluginPortal()
    }
}

plugins {
    id "java"
    id "eclipse"
    id "idea"
    id "org.springframework.boot" version "2.3.2.RELEASE"
    id "io.spring.dependency-management" version "1.0.9.RELEASE"
    id "groovy"
    id "checkstyle"
//    id "com.github.spotbugs" version "3.0.0"
    id "pmd"
    id "net.ltgt.errorprone" version "1.1.1"
    id "com.gorylenko.gradle-git-properties" version "2.2.3"
}

..........

configurations {
    compileOnly.extendsFrom annotationProcessor

    // annotationProcessor と testAnnotationProcessor、compileOnly と testCompileOnly を併記不要にする
    testAnnotationProcessor.extendsFrom annotationProcessor
    testImplementation.extendsFrom compileOnly

    // for Doma 2
    domaGenRuntime

    // for SpotBugs
    spotbugsStylesheets { transitive = false }
}

..........

dependencyManagement {
    imports {
        // mavenBom は以下の URL のものを使用する
        // https://repo.spring.io/release/org/springframework/boot/spring-boot-starter-parent/2.2.9.RELEASE/
        // bomProperty に指定可能な property は以下の URL の BOM に記述がある
        // https://repo.spring.io/release/org/springframework/boot/spring-boot-dependencies/2.2.9.RELEASE/spring-boot-dependencies-2.2.9.RELEASE.pom
        mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES) {
            // Spring Boot の BOM に定義されているバージョンから変更する場合には、ここに以下のように記述する
            // bomProperty "thymeleaf.version", "3.0.9.RELEASE"
            bomProperty "groovy.version", "2.5.12"
        }
        mavenBom("org.junit:junit-bom:5.6.2")
    }
}

dependencies {
    def jdbcDriver = "org.postgresql:postgresql:42.2.14"
    def spockVersion = "1.3-groovy-2.5"
    def domaVersion = "2.26.0"
    def lombokVersion = "1.18.12"
    def errorproneVersion = "2.3.4"
    def powermockVersion = "2.0.7"
    def spotbugsVersion = "4.0.0-beta4"

    // dependency-management-plugin によりバージョン番号が自動で設定されるもの
    // Appendix F. Dependency versions ( https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-dependency-versions.html ) 参照
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
    implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity5")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    implementation("org.springframework.boot:spring-boot-starter-freemarker")
    implementation("org.springframework.boot:spring-boot-starter-mail")
    implementation("org.springframework.boot:spring-boot-starter-security")
    implementation("org.springframework.boot:spring-boot-starter-data-redis")
    implementation("org.springframework.boot:spring-boot-starter-amqp")
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    developmentOnly("org.springframework.boot:spring-boot-devtools")
    compileOnly("org.springframework.boot:spring-boot-configuration-processor")
    implementation("org.springframework.session:spring-session-data-redis")
    implementation("org.springframework.retry:spring-retry")
    implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
    implementation("org.apache.commons:commons-lang3")
    implementation("org.codehaus.janino:janino")
    implementation("io.micrometer:micrometer-registry-prometheus")
    testImplementation("org.springframework.boot:spring-boot-starter-test") {
        exclude group: "org.junit.vintage", module: "junit-vintage-engine"
    }
    testImplementation("org.springframework.security:spring-security-test")
    testImplementation("org.yaml:snakeyaml")

    // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの
    runtimeOnly("${jdbcDriver}")
    implementation("com.integralblue:log4jdbc-spring-boot-starter:2.0.0")
    implementation("org.simpleframework:simple-xml:2.7.1")
    implementation("com.univocity:univocity-parsers:2.8.4")
    implementation("com.google.guava:guava:29.0-jre")
    implementation("org.flywaydb:flyway-core:6.5.3")
    testImplementation("org.dbunit:dbunit:2.7.0") {
        exclude group: "postgresql", module: "postgresql"
    }
    testImplementation("com.icegreen:greenmail:1.5.14")
    testImplementation("org.assertj:assertj-core:3.16.1")
    testImplementation("com.jayway.jsonpath:json-path:2.4.0")
    testImplementation("org.jsoup:jsoup:1.13.1")
    testImplementation("cglib:cglib-nodep:3.3.0")
    testImplementation("org.spockframework:spock-core:${spockVersion}")
    testImplementation("org.spockframework:spock-spring:${spockVersion}")

    // for lombok
    // testAnnotationProcessor、testCompileOnly を併記しなくてよいよう configurations で設定している
    annotationProcessor("org.projectlombok:lombok:${lombokVersion}")
    compileOnly("org.projectlombok:lombok:${lombokVersion}")

    // for Doma
    annotationProcessor("org.seasar.doma:doma:${domaVersion}")
    implementation("org.seasar.doma:doma:${domaVersion}")
    domaGenRuntime("org.seasar.doma:doma-gen:${domaVersion}")
    domaGenRuntime("${jdbcDriver}")

    // for JUnit 5
    // junit-jupiter で junit-jupiter-api, junit-jupiter-params, junit-jupiter-engine の3つが依存関係に追加される
    testImplementation("org.junit.jupiter:junit-jupiter")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")

    // for Error Prone ( http://errorprone.info/ )
    errorprone("com.google.errorprone:error_prone_core:${errorproneVersion}")
    compileOnly("com.google.errorprone:error_prone_annotations:${errorproneVersion}")

    // PowerMock
    testImplementation("org.powermock:powermock-module-junit4:${powermockVersion}")
    testImplementation("org.powermock:powermock-api-mockito2:${powermockVersion}")

    // for SpotBugs
//    compileOnly("com.github.spotbugs:spotbugs:${spotbugsVersion}") {
//        exclude group: "pull-parser", module: "pull-parser"
//    }
//    compileOnly("net.jcip:jcip-annotations:1.0")
    compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}")
//    testImplementation("com.google.code.findbugs:jsr305:3.0.2")
//    spotbugsStylesheets("com.github.spotbugs:spotbugs:${spotbugsVersion}")
//    spotbugsPlugins("com.h3xstream.findsecbugs:findsecbugs-plugin:1.10.1")
}

..........

Spring Boot 2.3.2 へのバージョンアップとして以下の点を変更します。

  • buildscript block の以下の点を変更します。
    • version "2.2.9-RELEASE"version "2.3.2-RELEASE"
  • plugins block の以下の点を変更します。
    • id "org.springframework.boot" version "2.2.9.RELEASE"id "org.springframework.boot" version "2.3.2.RELEASE"
  • configurations block から以下の2行を削除します。
    • developmentOnly
    • runtimeClasspath.extendsFrom developmentOnly

各種ライブラリのバージョンアップとして以下の点を変更します。

  • plugins block の以下の点を変更します。
    • id "com.gorylenko.gradle-git-properties" version "2.2.0"id "com.gorylenko.gradle-git-properties" version "2.2.3"
  • dependencyManagement block の以下の点を変更します。
    • mavenBom("org.junit:junit-bom:5.5.2")mavenBom("org.junit:junit-bom:5.6.2")
  • dependencies block の以下の点を変更します。
    • def jdbcDriver = "org.postgresql:postgresql:42.2.9"def jdbcDriver = "org.postgresql:postgresql:42.2.14"
    • def lombokVersion = "1.18.10"def lombokVersion = "1.18.12"
    • def powermockVersion = "2.0.4"def powermockVersion = "2.0.7"
    • implementation("com.google.guava:guava:28.1-jre")implementation("com.google.guava:guava:29.0-jre")
    • implementation("org.flywaydb:flyway-core:6.1.3")implementation("org.flywaydb:flyway-core:6.5.3")
    • testImplementation("org.dbunit:dbunit:2.6.0")testImplementation("org.dbunit:dbunit:2.7.0")
    • testImplementation("com.icegreen:greenmail:1.5.11")testImplementation("com.icegreen:greenmail:1.5.14")
    • testImplementation("org.assertj:assertj-core:3.14.0")testImplementation("org.assertj:assertj-core:3.16.1")
    • testImplementation("org.jsoup:jsoup:1.12.1")testImplementation("org.jsoup:jsoup:1.13.1")
    • Doma は domaGen タスクを変更する必要があるので後でバージョンアップします。

build タスク実行時に出るエラーを修正する

clean タスク実行 → Rebuild Project 実行。。。でエラーが出ました。パッケージjavax.validationは存在しません のエラーメッセージが出力されています。

f:id:ksby:20200809115730p:plain

Spring Boot 2.3 Release Notes の Validation Starter no longer included in web starters の記述に従い implementation("org.springframework.boot:spring-boot-starter-validation") を追加します。

dependencies {
    ..........
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-validation")

再度 Rebuild Project 実行を実行すると、今度は以下の警告が出ます。

f:id:ksby:20200809121807p:plain

1つ目は org.springframework.boot.web.servlet.error.ErrorControllerのgetErrorPath()は推奨されません で、ksbysample.webapp.lending.web.WebappErrorController クラスで getErrorPath メソッドを override していたのですが、

f:id:ksby:20200809122121p:plain

org.springframework.boot.web.servlet.error.ErrorController#getErrorPath メソッドを見ると Deprecated になっていました。エラーページの path は設定ファイルの server.error.path で設定することになったようです。

f:id:ksby:20200809125741p:plain

Spring Boot の Common Application properties のページを見ると server.error.path のデフォルト値は /error で ksbysample.webapp.lending.web.WebappErrorController#getErrorPath メソッドが返す値と同じですので、override している ksbysample.webapp.lending.web.WebappErrorController#getErrorPath メソッドに @SuppressWarnings("deprecation") を付与して警告が出ないようにします。

    @SuppressWarnings("deprecation")
    @Override
    public String getErrorPath() {
        return "/error";
    }

2つ目は org.junit.Assertの<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<? super T>)は推奨されません で、これは JUnit 4 の assertThat メソッドを呼び出していたことが原因でした。AssertJ の assertThat に変更します。

再度 clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると無事 "BUILD SUCCESSFUL" のメッセージが出力されました。

f:id:ksby:20200809130437p:plain

履歴

2020/08/09
初版発行。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その2 )( Spring Boot を 2.2.2 → 2.2.9 へ、Gradle を 6.0.1 → 6.5.1 へバージョンアップする )

概要

記事一覧はこちらです。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その1 )( 概要 ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Spring Boot のバージョンを 2.2 系の最新バージョンである 2.2.9 へ、Gradle のバージョンを 6.x 系の最新バージョンである 6.5.1 に上げて build できることを確認します。
    • 今回は問題がなければライブラリはバージョンアップしません。

参照したサイト・書籍

目次

  1. 2.3.x ブランチの作成
  2. Spring Boot を 2.2.2 → 2.2.9 にバージョンアップする
  3. Gradle を 6.0.1 → 6.5.1 にバージョンアップする

手順

2.3.x ブランチの作成

master から 2.3.x ブランチを、2.3.x から feature/135-issue ブランチを作成します。

Spring Boot を 2.2.2 → 2.2.9 にバージョンアップする

build.gradle の以下の点を変更します。

buildscript {
    ext {
        group "ksbysample"
        version "2.2.9-RELEASE"
    }
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/release/" }
        gradlePluginPortal()
    }
}

plugins {
    id "java"
    id "eclipse"
    id "idea"
    id "org.springframework.boot" version "2.2.9.RELEASE"
    id "io.spring.dependency-management" version "1.0.9.RELEASE"
    id "groovy"
    id "checkstyle"
    id "com.github.spotbugs" version "3.0.0"
    id "pmd"
    id "net.ltgt.errorprone" version "1.1.1"
    id "com.gorylenko.gradle-git-properties" version "2.2.0"
}

..........
  • buildscript block の以下の点を変更します。
    • version "2.2.2-RELEASE"version "2.2.9-RELEASE"
  • plugins block の以下の点を変更します。
    • id "org.springframework.boot" version "2.2.2.RELEASE"id "org.springframework.boot" version "2.2.9.RELEASE"
    • id "io.spring.dependency-management" version "1.0.8.RELEASE"id "io.spring.dependency-management" version "1.0.9.RELEASE"

Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、clean タスク実行 → Rebuild Project 実行。。。すると以下の画像のエラーが出ました。

f:id:ksby:20200808195347p:plain

Web で検索しても該当しそうな記事が見つかりません。

groovy の compile 時のエラーのようなので groovy のバージョンを確認したところ、2.2.2 の時は 2.5.8、2.2.9 の時は 2.5.13(https://mvnrepository.com/artifact/org.codehaus.groovy/groovy を見ると 2.5 系の最終バージョンの模様)でした。

build.gradle で groovy のバージョンを 2.5.12 にバージョンダウンすると Rebuild Project 実行時にエラーが出なくなりました。

dependencyManagement {
    imports {
        // mavenBom は以下の URL のものを使用する
        // https://repo.spring.io/release/org/springframework/boot/spring-boot-starter-parent/2.2.9.RELEASE/
        // bomProperty に指定可能な property は以下の URL の BOM に記述がある
        // https://repo.spring.io/release/org/springframework/boot/spring-boot-dependencies/2.2.9.RELEASE/spring-boot-dependencies-2.2.9.RELEASE.pom
        mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES) {
            // Spring Boot の BOM に定義されているバージョンから変更する場合には、ここに以下のように記述する
            // bomProperty "thymeleaf.version", "3.0.9.RELEASE"
            bomProperty "groovy.version", "2.5.12"
        }
        mavenBom("org.junit:junit-bom:5.5.2")
    }
}
  • dependencyManagement block に bomProperty "groovy.version", "2.5.12" を追加します。

build タスクを実行すると、今度は以下の画像のエラーが出ました。Caused by: org.dbunit.dataset.DataSetException Caused by: org.xml.sax.SAXNotSupportedException で大量のエラーが発生しています。

f:id:ksby:20200808202608p:plain

Project Tool Window で src/test でコンテキストメニューを表示して「Run 'All Tests'」を選択してテストを実行し、もう少し詳しいエラーメッセージを見てみると、以下のエラーメッセージが出力されていました。

f:id:ksby:20200808203335p:plain

java.lang.RuntimeException: org.dbunit.dataset.DataSetException: not supported setting property http://xml.org/sax/properties/lexical-handler

    at ksbysample.common.test.extension.db.TestDataExtension.after(TestDataExtension.java:129)
    at ksbysample.common.test.extension.db.TestDataExtension.afterEach(TestDataExtension.java:75)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAfterEachCallbacks$11(TestMethodTestDescriptor.java:245)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$12(TestMethodTestDescriptor.java:256)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeAllAfterMethodsOrCallbacks$13(TestMethodTestDescriptor.java:256)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAllAfterMethodsOrCallbacks(TestMethodTestDescriptor.java:255)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeAfterEachCallbacks(TestMethodTestDescriptor.java:244)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:141)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:69)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
    at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
    at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
    at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
    at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:69)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.dbunit.dataset.DataSetException: not supported setting property http://xml.org/sax/properties/lexical-handler
    at org.dbunit.dataset.xml.XmlProducer.buildException(XmlProducer.java:182)
    at org.dbunit.dataset.xml.FlatXmlProducer.produce(FlatXmlProducer.java:373)
    at org.dbunit.dataset.CachedDataSet.<init>(CachedDataSet.java:80)
    at org.dbunit.dataset.xml.FlatXmlDataSet.<init>(FlatXmlDataSet.java:110)
    at org.dbunit.dataset.xml.FlatXmlDataSetBuilder.buildInternal(FlatXmlDataSetBuilder.java:264)
    at org.dbunit.dataset.xml.FlatXmlDataSetBuilder.build(FlatXmlDataSetBuilder.java:111)
    at ksbysample.common.test.extension.db.TestDataExtension.restoreDb(TestDataExtension.java:207)
    at ksbysample.common.test.extension.db.TestDataExtension.after(TestDataExtension.java:126)
    ... 60 more
Caused by: org.xml.sax.SAXNotSupportedException: not supported setting property http://xml.org/sax/properties/lexical-handler
    at org.gjt.xpp.sax2.Driver.setProperty(Driver.java:204)
    at org.dbunit.dataset.xml.FlatDtdProducer.setLexicalHandler(FlatDtdProducer.java:132)
    at org.dbunit.dataset.xml.FlatXmlProducer.produce(FlatXmlProducer.java:358)
    ... 66 more

build.gradle で testImplementation("org.dbunit:dbunit:2.6.0")testImplementation("org.dbunit:dbunit:2.7.0") にバージョンアップしても状況は変わりません(一旦 2.6.0 に戻しました)。

Web で調べると The SAX parser pull-parser conflicts with Tomcat SAX parser という Issue が見つかりました。同じエラーメッセージが出ていますが、pull-parser-2.jar を削除すると解消したとのこと。Error Parsing /index.xhtml: not supported setting property http://xml.org/sax/properties/lexical-handler の記事も見つけました。dom4j の optional なので外しても問題ないようです。

gradlew dependencies を実行して pull-parser-2.jar に依存しているモジュールを探すと com.github.spotbugs:spotbugs:4.0.0-beta4 がヒットしました。

..........
+--- com.github.spotbugs:spotbugs:4.0.0-beta4
|    +--- org.ow2.asm:asm:7.1
|    +--- org.ow2.asm:asm-analysis:7.1
|    |    \--- org.ow2.asm:asm-tree:7.1
|    |         \--- org.ow2.asm:asm:7.1
|    +--- org.ow2.asm:asm-commons:7.1
|    |    +--- org.ow2.asm:asm:7.1
|    |    +--- org.ow2.asm:asm-tree:7.1 (*)
|    |    \--- org.ow2.asm:asm-analysis:7.1 (*)
|    +--- org.ow2.asm:asm-tree:7.1 (*)
|    +--- org.ow2.asm:asm-util:7.1
|    |    +--- org.ow2.asm:asm:7.1
|    |    +--- org.ow2.asm:asm-tree:7.1 (*)
|    |    \--- org.ow2.asm:asm-analysis:7.1 (*)
|    +--- org.apache.bcel:bcel:6.3.1
|    +--- net.jcip:jcip-annotations:1.0
|    +--- org.dom4j:dom4j:2.1.1 -> 2.1.3
|    |    +--- jaxen:jaxen:1.1.6 -> 1.2.0
|    |    +--- javax.xml.stream:stax-api:1.0-2
|    |    +--- net.java.dev.msv:xsdlib:2013.6.1
|    |    |    \--- relaxngDatatype:relaxngDatatype:20020414
|    |    +--- javax.xml.bind:jaxb-api:2.2.12 -> 2.3.1
|    |    |    \--- javax.activation:javax.activation-api:1.2.0
|    |    +--- pull-parser:pull-parser:2
|    |    \--- xpp3:xpp3:1.1.4c
|    +--- jaxen:jaxen:1.1.6 -> 1.2.0
|    +--- commons-lang:commons-lang:2.6
|    +--- org.slf4j:slf4j-api:1.8.0-beta4 -> 1.7.30
|    +--- net.sf.saxon:Saxon-HE:9.9.1-2
|    |    \--- com.ibm.icu:icu4j:63.1
|    \--- com.github.spotbugs:spotbugs-annotations:4.0.0-beta4
|         \--- com.google.code.findbugs:jsr305:3.0.2
..........

build.gradle で com.github.spotbugs:spotbugs:4.0.0-beta4 の依存関係から pull-parser:pull-parser:2 を除外してみます。

dependencies {
    ..........

    // for SpotBugs
    compileOnly("com.github.spotbugs:spotbugs:${spotbugsVersion}") {
        exclude group: "pull-parser", module: "pull-parser"
    }
    compileOnly("net.jcip:jcip-annotations:1.0")
    compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}")
    testImplementation("com.google.code.findbugs:jsr305:3.0.2")
    spotbugsStylesheets("com.github.spotbugs:spotbugs:${spotbugsVersion}")
    spotbugsPlugins("com.h3xstream.findsecbugs:findsecbugs-plugin:1.10.1")
}
  • exclude group: "pull-parser", module: "pull-parser" を追加します。

Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新してから、再び clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると今度は無事 "BUILD SUCCESSFUL" のメッセージが出力されました。

f:id:ksby:20200808222943p:plain

Gradle を 6.0.1 → 6.5.1 にバージョンアップする

build.gradle の wrapper タスクの記述を以下のように変更します。

wrapper {
    gradleVersion = "6.5.1"
    distributionType = Wrapper.DistributionType.ALL
}
  • gradleVersion = "6.0.1"gradleVersion = "6.5.1" に変更します。

コマンドプロンプトから gradlew wrapper --gradle-version 6.5.1gradlew --version コマンドを実行します。

f:id:ksby:20200808232307p:plain

gradle/wrapper/gradle-wrapper.properties は以下の内容になります。

distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

JVM を呼び出す時のメモリ割り当ての記述が元に戻るので、gradlew.bat 内の記述を set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"set DEFAULT_JVM_OPTS="-Xmx4096m" に変更します(gradlew も同じような変更をします)。

Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します(少し時間がかかります)。

clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると、spotbugsMain タスクでエラーになりました。'org.gradle.process.internal.worker.SingleRequestWorkerProcessBuilder org.gradle.process.internal.worker.WorkerProcessFactory.singleRequestWorker(java.lang.Class, java.lang.Class)' というエラーメッセージが出力されています。

f:id:ksby:20200809104256p:plain

SpotBugs は後でバージョンアップする予定なので今回はコメントアウトすることにします。

build.gradle で SpotBugs の記述をコメントアウトします。 ただしソース内で SpotBug s のアノテーションを記述しているところがあるので compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}") だけは残します。

..........

plugins {
    id "java"
    id "eclipse"
    id "idea"
    id "org.springframework.boot" version "2.2.9.RELEASE"
    id "io.spring.dependency-management" version "1.0.9.RELEASE"
    id "groovy"
    id "checkstyle"
//    id "com.github.spotbugs" version "3.0.0"
    id "pmd"
    id "net.ltgt.errorprone" version "1.1.1"
    id "com.gorylenko.gradle-git-properties" version "2.2.0"
}

..........

//spotbugs {
//    toolVersion = "4.0.0-beta4"
//    ignoreFailures = true
//    effort = "max"
//    spotbugsTest.enabled = false
//}
//tasks.withType(com.github.spotbugs.SpotBugsTask) {
//    reports {
//        xml.enabled = false
//        html.enabled = true
//        html.stylesheet = resources.text.fromArchiveEntry(configurations.spotbugsStylesheets, "color.xsl")
//    }
//}

..........

dependencies {
    ..........

    // for SpotBugs
//    compileOnly("com.github.spotbugs:spotbugs:${spotbugsVersion}") {
//        exclude group: "pull-parser", module: "pull-parser"
//    }
//    compileOnly("net.jcip:jcip-annotations:1.0")
    compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}")
//    testImplementation("com.google.code.findbugs:jsr305:3.0.2")
//    spotbugsStylesheets("com.github.spotbugs:spotbugs:${spotbugsVersion}")
//    spotbugsPlugins("com.h3xstream.findsecbugs:findsecbugs-plugin:1.10.1")
}

再び clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると今度は無事 "BUILD SUCCESSFUL" のメッセージが出力されました。

f:id:ksby:20200809105026p:plain

履歴

2020/08/09
初版発行。

Spring Boot 2.2.x の Web アプリを 2.3.x へバージョンアップする ( その1 )( 概要 )

概要

記事一覧はこちらです。

  • 「Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る」で作成した Web アプリケーション ( ksbysample-webapp-lending ) の Spring Boot のバージョンを 2.2.2 → 2.3.x へバージョンアップします。
  • 進め方は以下の方針とします。
    • Git のブランチは 2.3.x を作成して、そちらで作業します。Spring Boot のバージョンと合わせます。
    • Spring Boot のバージョンを 2.2 系の最新バージョンである 2.2.9 へ、Gradle のバージョンを 6.x 系の最新バージョンである 6.5.1 に上げて build できることを確認します。この時点ではライブラリはバージョンアップしません。
    • Spring Boot のバージョン番号を 2.3.x にします。
      • Spring Initializr で 2.3.x のプロジェクトを作成して、修正した方がよさそうな点があれば反映します。
      • ライブラリは最新バージョンにアップデートします。ただし、この時点では checkstyle, spotbugs, pmd, Error Prone のバージョンは上げません。
    • プロジェクトを build し直してエラーが出る点があれば修正し、まずはここまでで動くようにします。
    • その後で 2.3 系ではこう書くべきという点があるか確認し、変更した方がよいところを変更します。
    • checkstyle, spotbugs, pmd, Error Prone を1つずつ最新バージョンに上げます。変更した方がよいところがあれば変更します。
    • docker-compose で使用している image を最新バージョンに上げます。  
       

2.3 の Release Notes はこちらです。

Spring Boot 2.3 Release Notes
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.3-Release-Notes

履歴

2020/08/08
初版発行。