かんがるーさんの日記

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

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その7 )( Gradle を 5.2 → 5.2.1 へ、Spring Boot を 2.1.2 → 2.1.3 へバージョンアップする )

概要

記事一覧はこちらです。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その6 )( Thymeleaf テンプレートの html タグの属性を変更し、メトリックスのタグの定義場所を変更する ) の続きです。

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

参照したサイト・書籍

目次

  1. gradle を 5.2 → 5.2.1 へバージョンアップする
  2. Spring Boot を 2.1.2 → 2.1.3 へバージョンアップする

手順

gradle を 5.2 → 5.2.1 へバージョンアップする

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

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

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

f:id:ksby:20190217221405p:plain

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

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

gradlew、gradlew.bat の DEFAULT_JVM_OPTS の設定が -Xmx64m に戻っているので -Xmx4096m に変更します。

Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します(画面キャプチャはなし)。

Spring Boot を 2.1.2 → 2.1.3 へバージョンアップする

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

buildscript {
    ext {
        group "ksbysample"
        version "2.1.3-RELEASE"
    }
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/release/" }
        maven { url "https://plugins.gradle.org/m2/" }
    }
}

plugins {
    id "java"
    id "eclipse"
    id "idea"
    id "org.springframework.boot" version "2.1.3.RELEASE"
    id "io.spring.dependency-management" version "1.0.6.RELEASE"
    id "groovy"
    id "checkstyle"
    id "com.github.spotbugs" version "1.6.9"
    id "pmd"
// compileエラーが出るので error-prone を一旦コメントアウトする 
//    id "net.ltgt.errorprone" version "0.0.16"
    id "de.undercouch.download" version "3.4.3"
    id "com.gorylenko.gradle-git-properties" version "2.0.0"
}

..........

dependencies {
    def jdbcDriver = "org.postgresql:postgresql:42.2.5"
    def spockVersion = "1.2-groovy-2.5"
    def domaVersion = "2.23.0"
    def lombokVersion = "1.18.6"
    def errorproneVersion = "2.3.1"
    def powermockVersion = "2.0.0"
    def spotbugsVersion = "3.1.11"

    ..........
  • buildscript block 内で version "2.1.2-RELEASE"version "2.1.3-RELEASE" に変更します。
  • plugins block 内で id "org.springframework.boot" version "2.1.2.RELEASE"id "org.springframework.boot" version "2.1.3.RELEASE" に変更します。
  • dependencies block 内の以下の点を変更します。
    • def lombokVersion = "1.18.4"def lombokVersion = "1.18.6" に変更します。
    • implementation("com.zaxxer:HikariCP:3.3.0") を削除します。

Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

clean タスク実行 → Rebuild Project 実行 → build タスクを実行して、"BUILD SUCCESSFUL" のメッセージが出力されることを確認します。

f:id:ksby:20190217230809p:plain

履歴

2019/02/17
初版発行。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その6 )( Thymeleaf テンプレートの html タグの属性を変更し、メトリックスのタグの定義場所を変更する )

概要

記事一覧はこちらです。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その5 )( テストが大量に失敗する原因を解消する2 ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Thymeleaf テンプレートの html タグに記述している属性から不要なものを削除し、xmlns:sec の記述を変更します。
    • メトリックスの application label を定義する場所を変更します。

参照したサイト・書籍

  1. Google「言語指定にlangは使うな」/公式発言
    https://seopack.jp/seoblog/20161111-use-hreflang/

  2. What is the difference between HTML lang tag and HTML hreflang tag?
    https://webmasters.stackexchange.com/questions/105998/what-is-the-difference-between-html-lang-tag-and-html-hreflang-tag

  3. 多言語サイトはrel=”altrenate” hreflang=”x”で管理しよう
    https://seopack.jp/internal-seo/crawler-measures/multilingual-site-hreflang.php

  4. Search Console ヘルプ - ページのローカライズ版について Google に知らせる
    https://support.google.com/webmasters/answer/189077?hl=ja

  5. xmlns:sec is no longer available
    https://github.com/thymeleaf/thymeleaf-extras-springsecurity/issues/52

  6. Spring Boot 2.1 Release Notes - Micrometer
    https://github.com/spring-projects/spring-booT/wiki/Spring-Boot-2.1-Release-Notes#micrometer

目次

  1. Thymeleaf テンプレートの xmlns="http://www.w3.org/1999/xhtml" を削除する
  2. xmlns:sec の記述を xmlns:sec="http://www.thymeleaf.org/extras/spring-security" に変更する
  3. メトリックスの application label を application.properties の management.metrics.tags.application で定義するよう変更する

手順

Thymeleaf テンプレートの xmlns="http://www.w3.org/1999/xhtml" を削除する

現在 Thymeleaf テンプレートの html タグに以下のように属性を記述しているのですが、

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">

xmlns="http://www.w3.org/1999/xhtml" は Thymeleaf のバージョンが 2 系のころの記述で 3 系になったら不要になったので削除します。

また IntelliJ IDEA で html を作成すると以下のように記述されたファイルが作成されるので lang="ja" を記述しようと思ったのですが、

<!DOCTYPE html>
<html lang="en">

"html lang" で Google で検索してみたら Google「言語指定にlangは使うな」/公式発言 というページを見つけました。他にも調べてみたところ、

  • lang 属性は信頼性がないので Google は参照していない。
  • 多言語ページを作成しているならば <link rel="alternate" href="..." hreflang="...(ja 等)" /> を記述する。ただし ccTLD(国別コードトップレベルドメイン)の場合は不要。

らしいので lang="ja" は記述しないことにします。

xmlns:sec の記述を xmlns:sec="http://www.thymeleaf.org/extras/spring-security" に変更する

xmlns:sec の記述について src/main/resources/templates/loginsuccess.html では、

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.w3.org/1999/xhtml">

src/main/resources/templates/common/mainparts.html では、

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

と記述しています。おそらく前者は IntelliJ IDEA で自動補完したもの、後者はどこかの Web サイトを見てコピペしたものでしょう。

IntelliJ IDEA でタグの候補が表示されるのは xmlns:sec="http://www.thymeleaf.org/extras/spring-security" なので、この記述に変更します。変更すると以下のように候補が表示されます。

f:id:ksby:20190217163552p:plain

メトリックスの application label を application.properties の management.metrics.tags.application で定義するよう変更する

Spring Boot Statistics でメトリックスを表示する時に使用する application label を

f:id:ksby:20190217193527p:plain

今は docker/prometheus/prometheus.yml で以下のように定義していますが、

- job_name: 'spring-actuator'
  metrics_path: '/actuator/prometheus'
  scrape_interval: 15s
  basic_auth:
    username: actuator
    password: xxxxxxxx
  static_configs:
  # Docker で起動した Prometheus からローカルPCで起動している Spring Boot のアプリケーション
  # にアクセスする。docker-compose.yml の extra_hosts に定義した PC のホスト名 app を設定する。
  - targets: ['app:8080']
    labels:
      application: 'lending'

Spring Boot 2.1 Release Notes - Micrometer を見ると application.properties に management.metrics.tags.~= の形式で定義できるようになったので、定義場所を変更します。

docker/prometheus/prometheus.yml から labels の定義を削除した後、

- job_name: 'spring-actuator'
  metrics_path: '/actuator/prometheus'
  scrape_interval: 15s
  basic_auth:
    username: actuator
    password: xxxxxxxx
  static_configs:
  # Docker で起動した Prometheus からローカルPCで起動している Spring Boot のアプリケーション
  # にアクセスする。docker-compose.yml の extra_hosts に定義した PC のホスト名 app を設定する。
  - targets: ['app:8080']

src/main/resources/application.properties に management.metrics.tags.application=lending の定義を追加します。

host.ip.address=172.31.16.1
doma.dialect=org.seasar.doma.jdbc.dialect.PostgresDialect

management.endpoints.web.exposure.include=health,info,loggers,prometheus
management.metrics.tags.application=lending

docker-compose up -d でサーバを起動した後、Tomcat を起動してから Grafana を見ると Application に「lending」が表示されています。

f:id:ksby:20190217194918p:plain

履歴

2019/02/17
初版発行。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( 番外編 )( Spring Initializr で作成したプロジェクトで Thymeleaf テンプレートのコード補完を有効にするには? )

概要

記事一覧はこちらです。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その3 )( build.gradle を変更する ) で作成した demo プロジェクトで SampleController と sample.html(Thymeleaf テンプレート)を作成して単純な文字列を表示するサンプルを作成してみたのですが、th: タグの候補が表示されなかったのでその調査をしたメモ書きです。

参照したサイト・書籍

目次

  1. th: タグの候補が表示されるようにするには?

手順

th: タグの候補が表示されるようにするには?

src/main/resources/templates ディレクトリの下に sample.html を作成して th: タグを記入した後 Ctrl+Space を押すと以下の画像のような状態になります。

f:id:ksby:20190217095542p:plain

Alt+Enter で xmlns:th を自動補完させますが、その後もなぜか th: タグの補完が表示されません。

f:id:ksby:20190217095828p:plain

IntelliJ IDEA で Thymeleaf の自動補完ができなくなったのかな?と思いましたが、ksbysample-webapp-lending プロジェクトの Thymeleaf テンプレートで試してみると th: タグの候補が表示されます。

f:id:ksby:20190217100310p:plain

プロジェクトの設定か何かと思って「Project Structure」ダイアログを表示させて違いを探したり IntelliJ IDEA 2018.3 Help - Thymeleaf のページを見て設定してみたりしたのですが、全然解決しません。

結論ですが、IntelliJ IDEA が自動補完した xmlns:th の URL が間違っていたためでした。xmlns:th="http://www.w3.org/1999/xhtml"xmlns:th="http://www.thymeleaf.org" に変更すると th: タグの候補が表示されるようになります。

f:id:ksby:20190217103318p:plain

IntelliJ IDEA が自動補完してくれるからといって必ず正しいとは限らないんですね。。。 すっかり信頼していたのでなかなか気付けませんでした。

履歴

2019/02/17
初版発行。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( 番外編 )( IntelliJ IDEA の Class Diagram 生成機能メモ書き )

概要

記事一覧はこちらです。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その4 )( テストが大量に失敗する原因を解消する ) で mvcValidator bean を定義しているクラスを探している時に Class Diagram を生成したのですが、これまで使ったことがない機能を知ったのでメモ書きとして残しておきます。

  • Class Diagram は最初は依存関係が表示されていない。クラスの中でフィールドで定義して使用している場合そのままだと何も関係を示す線が表示されないが、「Show Dependencies」ボタンを押すと関係が分かる線が表示されるようになる。
  • 「Add Class to Diagram...」メニューで生成済の Class Diagram に別のクラスを追加できる。
  • 「Show Implementations」で指定したクラスを継承しているクラスや指定したインターフェースを実装しているクラスを、 「Show Parents」で継承元クラスや実装しているインターフェースを表示できる。

参照したサイト・書籍

目次

  1. mvcValidator bean を定義しているクラスの Class Diagram を生成する
  2. 生成済の Class Diagram に別のクラスを追加する+依存関係を表示する
  3. クラスが実装しているインターフェースを表示する(この方法で継承元クラスも表示できる)
  4. インターフェースを実装しているクラスを表示する

手順

mvcValidator bean を定義しているクラスの Class Diagram を生成する

mvcValidator bean を定義している箇所を「Find in Path」で探すと以下のクラスで定義されていることが分かります。

f:id:ksby:20190216001611p:plainf:id:ksby:20190216001653p:plain
  • org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport#mvcValidator
  • org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration#mvcValidator

クラス間の関係がよく分からなかったので Class Diagram を作成します。後者の org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration#mvcValidator に @Override アノテーションが付与されているので、こちらをベースに作成します。

mvcValidator メソッドにマウスカーソルを移動してコンテキストメニューを表示した後、「Diagrams」-「Show Diagram...」メニューを選択します。

f:id:ksby:20190216002656p:plain

Class Diagram が生成されてクラスの関係が分かりました。

f:id:ksby:20190216003457p:plain

生成済の Class Diagram に別のクラスを追加する+依存関係を表示する

Class Diagram 上で WebMvcConfigurationSupport と EnableWebMvcConfiguration の間に DelegatingWebMvcConfiguration が表示されているのでソースを表示させてみると、フィールドで WebMvcConfigurerComposite クラスのインスタンスを生成しているので、このクラスを作成した Class Diagram に追加してみます。

f:id:ksby:20190216003804p:plain

Class Diagram の何もないところでコンテキストメニューを表示した後、「Add Class to Diagram...」メニューを選択します。

f:id:ksby:20190216004130p:plain

「Enter class name to add」ダイアログが表示されるので追加したクラス名 WebMvcConfigurerComposite を入力します。該当するクラスが表示されるので、今回は1つだけ表示されている WebMvcConfigurerComposite クラスを選択します。

f:id:ksby:20190216004313p:plain

Class Diagram に WebMvcConfigurerComposite クラスが追加されますが、DelegatingWebMvcConfiguration クラスとの間に何の線も引かれずこのままでは関係が分かりません。

f:id:ksby:20190216004638p:plain

Class Diagram の上に表示されているボタンから「Show Dependencies」ボタンをクリックします。

f:id:ksby:20190216005052p:plain

そうすると DelegatingWebMvcConfiguration クラスが WebMvcConfigurerComposite クラスを生成していること、1対1の関係であることを示す線が表示されます。

f:id:ksby:20190216005310p:plain

クラスが実装しているインターフェースを表示する(この方法で継承元クラスも表示できる)

WebMvcConfigurerComposite クラスのソースを見ると WebMvcConfigurer インターフェースを実装していることが分かります。WebMvcConfigurer インターフェースを Class Diagram に追加してみます。

f:id:ksby:20190216010651p:plain

Class Diagram 上で WebMvcConfigurerComposite クラスを選択してからコンテキストメニューを表示した後、「Show Parents」メニューを選択します。

f:id:ksby:20190216010953p:plain

継承元クラスや実装しているインターフェースが表示されるので、今回は WebMvcConfigurer インターフェースを選択します。

f:id:ksby:20190216011629p:plain

Class Diagram 上に WebMvcConfigurer インターフェースが表示されます。

f:id:ksby:20190216011900p:plain

インターフェースを実装しているクラスを表示する

WebMvcConfigurer インターフェースを実装しているクラスが他にあるか調べて表示させてみます。

Class Diagram 上で WebMvcConfigurer インターフェースを選択してからコンテキストメニューを表示した後、「Show Implementations」メニューを選択します。

f:id:ksby:20190216013220p:plain

WebMvcConfigurer インターフェースを実装しているクラスのリストが表示されます。今回は3クラス選択してみます(Ctrlキーを押しながらクリックすると複数選択できます)。

f:id:ksby:20190216013404p:plain

Class Diagram 上に選択したクラスが表示されます。

f:id:ksby:20190216013712p:plain

履歴

2019/02/16
初版発行。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その5 )( テストが大量に失敗する原因を解消する2 )

概要

記事一覧はこちらです。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その4 )( テストが大量に失敗する原因を解消する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • ksbysample.webapp.lending.SampleHelperTest$異常処理のテスト.SampleHelper_encryptを呼ぶとRuntimeExceptionをthrowする テストメソッドだけ gradle の build タスクから実行された時には成功するのに IntelliJ IDEA の「Run ‘All Tests’」から実行された時には失敗するので、その原因を調査します。

参照したサイト・書籍

  1. Difference between AppClassloader and SystemClassloader
    https://stackoverflow.com/questions/34650568/difference-between-appclassloader-and-systemclassloader

目次

  1. gradle の build タスクから実行された時には成功するが IntelliJ IDEA の「Run ‘All Tests’」から実行された時に失敗する原因とは?
  2. Spring Boot 2.0.8 に切り戻して確認してみる
  3. Spring Boot 2.1.2 に切り替えて「JUnit」の「Shorten command line」の設定を「JAR manifest」にして確認する

手順

gradle の build タスクから実行された時には成功するが IntelliJ IDEA の「Run ‘All Tests’」から実行された時に失敗する原因とは?

まずは状況をまとめてみます。失敗する ksbysample.webapp.lending.SampleHelperTest$異常処理のテスト.SampleHelper_encryptを呼ぶとRuntimeExceptionをthrowする テストメソッドは以下の実装になっており、

  • ksbysample.webapp.lending.SampleHelperTest テストクラスは groovy で書かれている。
  • SampleHelperTest クラスの中に Spock で書かれたテストクラス「正常処理のテスト」と JUnit4 で書かれたテストクラス「異常処理のテスト」が混在している。SampleHelperTest クラスには @RunWith(Enclosed) アノテーションが付与されている。
  • JUnit4 で書かれたテストクラス「異常処理のテスト」は PowerMock を使用して static メソッドのテストをしている。

エラーメッセージ Caused by: java.lang.NullPointerException at org.thymeleaf.spring5.util.SpringVersionUtils.<clinit>(SpringVersionUtils.java:52) からエラーの発生箇所を確認すると、以下の赤枠の部分で NullPointerException が発生しています。

f:id:ksby:20190213003906p:plain

赤枠の行に breakpoint を設定してテストを debug 実行してみると、

f:id:ksby:20190213004948p:plain

breakpoint で処理が止まり、Debug Tool Window の Variables に「SpringVersion.class」と「SpringVersion.class.getPackage()」を表示させてみると以下の結果でした。

f:id:ksby:20190213010416p:plain

  • SpringVersion.class はインスタンスが生成されている。classLoader は JavassitMockClassLoader で、parent が Launcher$AppClassLoader。
  • SpringVersion.class.getPackage() は null だったので、SpringVersion.class.getPackage().getName() を呼べば NullPointerException が発生する。

今度は breakpoint はそのままで、gradle の build タスクを debug 実行してみます(Gradle Tool Window に表示されている build タスクでコンテキストメニューを表示して「Debug ...」メニューを選択します)。

f:id:ksby:20190213011406p:plain

普段は表示されない Connected to the target VM, address: '127.0.0.1:56365', transport: 'socket'Connected to the VM started by ':test' (localhost:56488). Open the debugger session tab のメッセージが表示されて test タスクが実行された後、

f:id:ksby:20190213011945p:plain

breakpoint で処理が止まるので、Debug Tool Window の Variables に「SpringVersion.class」と「SpringVersion.class.getPackage()」を表示させてみると以下の結果でした。

f:id:ksby:20190213011849p:plain

  • SpringVersion.class はインスタンスが生成されている。classLoader は Launcher$AppClassLoader。
  • SpringVersion.class.getPackage() は null ではなく package 名が返ってきている。

「Run ‘All Tests’」からテストを実行した時は org.thymeleaf.spring5.util.SpringVersionUtils の classLoader が JavassitMockClassLoader(おそらく https://github.com/powermock/powermock/blob/release/2.x/powermock-core/src/main/java/org/powermock/core/classloader/javassist/JavassistMockClassLoader.java)になっていてい Mock 化されており SpringVersion.class.getPackage() が null を返すため、ということでしょうか。。。?

Spring Boot 2.0.8 に切り戻して確認してみる

Spring Boot のバージョンを 2.1.2 に上げる前は ksbysample.webapp.lending.SampleHelperTest$異常処理のテスト.SampleHelper_encryptを呼ぶとRuntimeExceptionをthrowする テストメソッドは成功していたはずなので、一旦 master ブランチに切り替えて確認してみます。

master ブランチに切り替えてから Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、テストを実行すると 2.1.2 にバージョンアップした後と同じ理由で失敗しました。

f:id:ksby:20190214031645p:plain

以前は成功していたはずなのになぜ?。。。と思ったのですが、よく考えたら Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その4 )( テストが大量に失敗する原因を解消する ) の時に「Run/Debug Configurations」の画面で「JUnit」の「Shorten command line」の設定を「classpath file」に変更していたので、それが原因かもしれません。元の「user-local default: none」の設定に戻してみます。

f:id:ksby:20190214032155p:plain

再度テストを実行すると今度は成功しました。どうも「classpath file」の設定だと PowerMock を使用したテストで失敗することがあるという結論のようです。

f:id:ksby:20190214032400p:plain

ただし「user-local default: none」の設定でテストが成功することが分かっても、この設定では Spring Boot を 2.1.2 に上げた時に Command line is too long. のメッセージが表示されてテストが実行できません。「Shorten command line」の設定には「JAR manifest」もあるので、そちらに設定を変更して試してみます。

f:id:ksby:20190214032858p:plain

テストを実行すると成功しました。

f:id:ksby:20190214033058p:plain

ということで ksbysample.webapp.lending.SampleHelperTest$異常処理のテスト.SampleHelper_encryptを呼ぶとRuntimeExceptionをthrowする テストメソッドが失敗したのは「Run/Debug Configurations」の画面で「JUnit」の「Shorten command line」の設定を「classpath file」にしたからという結論でした。「JAR manifest」にすると成功するので、今度はこの設定で Spring Boot 2.1.2 に上げた状態に切り替えて試してみます。

Spring Boot 2.1.2 に切り替えて「JUnit」の「Shorten command line」の設定を「JAR manifest」にして確認する

Spring Boot 2.1.2 へのバージョンアップの作業をしているブランチに切り替えてから Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新した後、テストを実行してみると今度は成功しました。

f:id:ksby:20190214034316p:plain

Project Tool Window の src/test から「Run ‘All Tests’」を実行すると今度は全てのテストが成功しました!

f:id:ksby:20190214034910p:plain

「Shorten command line」の設定は「classpath file」の方が良さそうに思えたのですが「JAR manifest」の方が良かったようです。ただし PowerMock のテストでしかエラーになっていないので、普通はどちらでも良いのかもしれません。

履歴

2019/02/14
初版発行。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その4 )( テストが大量に失敗する原因を解消する )

概要

記事一覧はこちらです。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その3 )( build.gradle を変更する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • テストが大量に失敗するようになったので、原因を調査し解消します。

参照したサイト・書籍

  1. IntelliJ IDEA 2017.3 EAP: Configurable command line shortener and more
    https://blog.jetbrains.com/idea/2017/10/intellij-idea-2017-3-eap-configurable-command-line-shortener-and-more/

目次

  1. 現状を確認する
  2. エラーの詳細を調べるために Run ‘All Tests’ を実行する。。。が Command line is too long. のメッセージが表示されてテストが実行できないので解消する
  3. ApplicationConfig クラスに定義している mvcValidator bean を単純に削除してよいか確認する
  4. mvcValidator の BeanDefinitionOverrideException が出ないようにし、かつ日本語のメッセージを messages_ja_JP.properties から取得できるようにするには?
  5. unittest の時には devtools の AutoConfiguration が実行されないようにする

手順

現状を確認する

まずは現在の状況をまとめます。build タスクを実行すると以下のように出力されており、

f:id:ksby:20190210080649p:plain (.....途中省略.....) f:id:ksby:20190210080800p:plain

  • 141 tests completed, 119 failed, 1 skipped と出力されている。
  • 失敗しているテストはほとんど java.lang.IllegalStateException Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException というエラーが出力されている。
ksbysample.webapp.lending.helper.library.LibraryHelperTest > testGetSelectedLibrary_図書館が選択されていない場合 FAILED
    java.lang.IllegalStateException
        Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException

エラーの詳細を調べるために Run ‘All Tests’ を実行する。。。が Command line is too long. のメッセージが表示されてテストが実行できないので解消する

エラーの詳細を出力するために Project Tool Window で src/test を選択した後、コンテキストメニューを表示して「Run ‘All Tests’」を選択します。。。が、Error running 'All in ksbysample-webapp-lending_test': Command line is too long. Shorten command line for All in ksbysample-webapp-lending_test or also for JUnit default configuration. というメッセージが表示されて実行できませんでした。

f:id:ksby:20190210081757p:plain

2.0.x までは問題なかったのですが、2.1.x にすると Command line is too long. になるようです。実際に実行しようとしている Command line の文字列を調べる方法がないか調べてみましたが分かりませんでした。ただし Edit Configuration で JUnit の設定を変更すれば解決できるようなので、設定を変更して解消します。

メインメニューから「Run」-「Edit Configurations...」を選択します。

「Run/Debug Configurations」画面が表示されます。画面左側のリストから「Templates」-「JUnit」を選択した後、画面右側の「Shorten command line」にデフォルトでは「user-local default: none」が選択されているので「JAR manifest」か「classpath file」を選択します。

f:id:ksby:20190210120253p:plain

選択肢の説明は IntelliJ IDEA 2017.3 EAP: Configurable command line shortener and more に書かれてあります。個人的には「classpath file」の設定が好みなので、こちらを選択します。

設定後に「Run ‘All Tests’」を実行すると、今度はテストが実行されました。見事にほとんどのテストが失敗していますが。。。

f:id:ksby:20190210122032p:plain

とりあえずこれでエラーの詳細が確認できるようになりました。エラー時に出力されているメッセージを確認すると以下のものでした。

Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'mvcValidator' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration; factoryMethodName=mvcValidator; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]] for bean 'mvcValidator': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=applicationConfig; factoryMethodName=mvcValidator; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [ksbysample/webapp/lending/config/ApplicationConfig.class]] bound.

これは Spring Boot 2.1 Release Notes - Bean Overriding に記述されているもので、src/main/java/ksbysample/webapp/lending/config/ApplicationConfig.java で mvcValidator bean を定義しているのですが、既に定義されている bean を上書きしようとしてエラーになっているようです。

既に定義されている mvcValidator bean は org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration#mvcValidator でした。

f:id:ksby:20190211094327p:plain

IntelliJ IDEA で EnableWebMvcConfiguration クラス関連の Diagram を作成してみると以下のようになります。

f:id:ksby:20190211095833p:plain

src/main/java/ksbysample/webapp/lending/config/ApplicationConfig.java の mvcValidator bean は以下のように実装しています。以前はこの実装がないと ValidationMessages.properties を削除して messages.properties だけにできなかったのですが削除してよいか確認します。

    /**
     * Controller クラスで直接 {@link Validator} を呼び出すために Bean として定義している
     * また Hibernate Validator のメッセージを ValidationMessages.properties ではなく
     * messages.properties に記述できるようにするためにも使用している
     *
     * @return new {@link LocalValidatorFactoryBean}
     */
    @Bean
    public Validator mvcValidator() {
        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
        localValidatorFactoryBean.setValidationMessageSource(this.messageSource);
        return localValidatorFactoryBean;
    }

ApplicationConfig クラスに定義している mvcValidator bean を単純に削除してよいか確認する

ksbysample-webapp-lending Web アプリケーションには Spring Boot で書籍の貸出状況確認・貸出申請する Web アプリケーションを作る ( 番外編 )( Spring MVC メモ書き ) で実装した Bean Validation 検証用の画面が存在するので、これを利用して確認します。

最初に src/main/java/ksbysample/webapp/lending/config/ApplicationConfig.java から mvcValidator bean の定義を削除します。

削除後 Tomcat を起動してから http://localhost:8080/springMvcMemo/beanValidationGroup にアクセスします。

f:id:ksby:20190210193434p:plain

「データ更新」ボタンを押すと ID が必須になっているのでエラーメッセージが出るはず。。。なのですが、HV000030: No validator could be found for constraint 'javax.validation.constraints.NotBlank' validating type 'java.lang.Long'. Check configuration for 'id' というエラーメッセージが表示されました。

f:id:ksby:20190210193634p:plain

原因を調べたところ Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その3 )( build.gradle を変更する ) の時に src/main/java/ksbysample/webapp/lending/web/springmvcmemo/EditFormChecker.javaprivate Long id; に付与するアノテーションを org.hibernate.validator.constraints.NotBlank → javax.validation.constraints.NotBlank に変更したのですが、前者は Long 型でも問題なかったのですが後者は CharSequence 型でないと動作しないためでした。

以下2つのソースの private Long id; に付与するアノテーション@NotBlank@NotNull(javax.validation.constraints.NotNull) に変更します。

  • src/main/java/ksbysample/webapp/lending/web/springmvcmemo/EditFormChecker.java
  • src/main/java/ksbysample/webapp/lending/web/springmvcmemo/SendmailFormChecker.java

また src/main/resources/messages_ja_JP.properties のエラーメッセージの定義も変更が必要なので以下のように変更します。

# Bean Validation 用メッセージ
error.size.max = {max}文字以内で入力して下さい。
javax.validation.constraints.NotBlank.message=必須の入力項目です。
javax.validation.constraints.NotNull.message=必須の入力項目です。
org.hibernate.validator.constraints.Email.message=メールアドレスを入力して下さい。
typeMismatch.java.lang.Long=数値を入力して下さい。
  • javax.validation.constraints.NotBlank.message=必須の入力項目です。 を追加します。
  • org.hibernate.validator.constraints.NotBlank.message=必須の入力項目です。 を削除します。

変更後に Tomcat を再起動して画面を表示し直してから「データ更新」ボタンを押すと今度はエラーメッセージが出ましたが、日本語ではなく Bean Validation のアノテーションのデフォルトメッセージ(英語)が表示されました。

f:id:ksby:20190210195703p:plain

どうしたら日本語のメッセージを表示できるかいろいろ試してみたところ、

  • messages.properties、messages_ja_JP.properties は全く参照されない。
  • ValidationMessages.properties(ValidationMessages_ja_JP.properties でも可)に javax.validation.constraints.NotBlank.message/javax.validation.constraints.NotNull.message という項目名でメッセージを定義すれば日本語のメッセージが表示される。ただし native2ascii で変換した後の文字列を記述する必要がある。変換しない UTF-8 の文字列だと文字化けする。
javax.validation.constraints.NotBlank.message=\u5FC5\u9808\u306E\u5165\u529B\u9805\u76EE\u3067\u3059\u3002
javax.validation.constraints.NotNull.message=\u5FC5\u9808\u306E\u5165\u529B\u9805\u76EE\u3067\u3059\u3002

上のように定義しておけば日本語でエラーメッセージが表示されます。

f:id:ksby:20190210204555p:plain

ValidationMessages.properties を止めて messages.properties にまとめたのに今更 ValidationMessages.properties を復活させたくはないので、mvcValidator bean を単純に削除するのは止めます。

mvcValidator の BeanDefinitionOverrideException が出ないようにし、かつ日本語のメッセージを messages_ja_JP.properties から取得できるようにするには?

結論を言うと以下のように変更します。

  • mvcValidator が bean 名で重複していて BeanDefinitionOverrideException が発生しているので、mvcValidator → validator に変更する。
  • 戻り値の型を org.springframework.validation.Validator にしているが、javax.validation.Validator インターフェースあるいはその実装クラスを返すようにしておくと org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration#mvcValidator 内で validator bean を使用するように処理してくれる。LocalValidatorFactoryBean クラスは javax.validation.Validator インターフェースの実装クラスなので、戻り値の型を org.springframework.validation.Validator → LocalValidatorFactoryBean に変更する。

    f:id:ksby:20190211210332p:plain

変更後の src/main/java/ksbysample/webapp/lending/config/ApplicationConfig.java に定義している validator bean は以下のようになります。戻り値の型とメソッド名を変更しただけです。

    /**
     * javax.validation や Hibernate Validator のメッセージを ValidationMessages.properties ではなく
     * messages.properties に記述できるようにするために定義している
     *
     * @return new {@link LocalValidatorFactoryBean}
     */
    @Bean
    public LocalValidatorFactoryBean validator() {
        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
        localValidatorFactoryBean.setValidationMessageSource(this.messageSource);
        return localValidatorFactoryBean;
    }

また src/main/java/ksbysample/webapp/lending/web/springmvcmemo/BeanValidationGroupController.java の以下の点を変更します。

@Controller
@RequestMapping("/springMvcMemo/beanValidationGroup")
public class BeanValidationGroupController {

    private static final String THYMELEAF_TEMPLATE = "springmvcmemo/beanValidationGroup";

    private final Validator validator;

    /**
     * @param validator ???
     */
    public BeanValidationGroupController(Validator validator) {
        this.validator = validator;
    }
  • フィールドに定義している private final Validator mvcValidator;private final Validator validator; に変更します。

src/main/test/ksbysample/webapp/lending/values/validation/ValuesEnumValidatorTest.java も同じ変更を行います。

@RunWith(SpringRunner.class)
@SpringBootTest
public class ValuesEnumValidatorTest {

    ..........

    private Validator validator;

    @Before
    public void setup() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }
  • フィールドに定義している private Validator mvcValidator;private Validator validator; に変更します。

Tomcat を再起動して http://localhost:8080/springMvcMemo/beanValidationGroup に再度アクセスして画面を表示した後「データ更新」ボタンを押すと、今度はエラーメッセージが日本語で表示されました。

f:id:ksby:20190211212821p:plain

ここまでの修正で build タスクは "BUILD SUCCESSFUL" のメッセージが出るようになりましたが、

f:id:ksby:20190211224310p:plain

Project Tool Window の src/test から「Run ‘All Tests’」を実行すると1件だけテストが失敗します。java.lang.IllegalStateException: Error processing condition on org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration というエラーメッセージが出ています。

f:id:ksby:20190211224753p:plain

unittest の時には devtools の AutoConfiguration が実行されないようにする

java.lang.IllegalStateException: Error processing condition on org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration のエラーは以下のようなエラーが出ているのですが、

java.lang.IllegalStateException: Failed to load ApplicationContext
    ..........
Caused by: java.lang.IllegalStateException: Error processing condition on org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:64)
    at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$TrackedConditionEvaluator.shouldSkip(ConfigurationClassBeanDefinitionReader.java:447)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$TrackedConditionEvaluator.shouldSkip(ConfigurationClassBeanDefinitionReader.java:436)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:128)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:117)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:327)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:232)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:275)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:95)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:691)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:528)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:316)
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:127)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
    ... 52 more
Caused by: java.lang.NullPointerException
    at org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration$DevToolsDataSourceCondition.getMatchOutcome(DevToolsDataSourceAutoConfiguration.java:182)
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
    ... 69 more

unittest の時に devtools は不要なので、無効になるよう設定を変更してそれでエラーが出なくなるなら良しとします。AutoConfiguration で設定しているようなので devtools の AutoConfiguration を調べて無効にします。

DevToolsDataSourceAutoConfiguration クラスを見ると package は org.springframework.boot.devtools.autoconfigure でした。org.springframework.boot.devtools.autoconfigure package 内に AutoConfiguration のクラスは LocalDevToolsAutoConfiguration、RemoteDevToolsAutoConfiguration、DevToolsDataSourceAutoConfiguration の3つがありましたので、

f:id:ksby:20190211232959p:plain

src/main/resources/application-unittest.properties の spring.autoconfigure.exclude に , org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration, org.springframework.boot.devtools.autoconfigure.RemoteDevToolsAutoConfiguration, org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration を追加して無効にします。

spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration, org.springframework.boot.devtools.autoconfigure.LocalDevToolsAutoConfiguration, org.springframework.boot.devtools.autoconfigure.RemoteDevToolsAutoConfiguration, org.springframework.boot.devtools.autoconfigure.DevToolsDataSourceAutoConfiguration

logging.level.root=OFF

再度「Run ‘All Tests’」を実行すると先程と同じテストでエラーが出ていましたが、

f:id:ksby:20190211234703p:plain

今度はエラーの内容が以下のものに変わっていました。

java.lang.IllegalStateException: Failed to load ApplicationContext
    ..........
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'webMvcConfig': Unsatisfied dependency expressed through method 'configureThymeleafSpringTemplateEngine' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'templateEngine' defined in class path resource [org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration$ThymeleafDefaultConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.thymeleaf.spring5.SpringTemplateEngine]: Factory method 'templateEngine' threw exception; nested exception is java.lang.ExceptionInInitializerError
    ..........
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'templateEngine' defined in class path resource [org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration$ThymeleafDefaultConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.thymeleaf.spring5.SpringTemplateEngine]: Factory method 'templateEngine' threw exception; nested exception is java.lang.ExceptionInInitializerError
    ..........
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.thymeleaf.spring5.SpringTemplateEngine]: Factory method 'templateEngine' threw exception; nested exception is java.lang.ExceptionInInitializerError
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622)
    ... 83 more
Caused by: java.lang.ExceptionInInitializerError
    at org.thymeleaf.spring5.dialect.SpringStandardDialect.<clinit>(SpringStandardDialect.java:143)
    at org.thymeleaf.spring5.SpringTemplateEngine.<clinit>(SpringTemplateEngine.java:59)
    at org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafDefaultConfiguration.templateEngine(ThymeleafAutoConfiguration.java:156)
    at org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafDefaultConfiguration$$EnhancerBySpringCGLIB$$b3eec7c4.CGLIB$templateEngine$0(<generated>)
    at org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafDefaultConfiguration$$EnhancerBySpringCGLIB$$b3eec7c4$$FastClassBySpringCGLIB$$9a6ac718.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363)
    at org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration$ThymeleafDefaultConfiguration$$EnhancerBySpringCGLIB$$b3eec7c4.templateEngine(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
    ... 84 more
Caused by: java.lang.NullPointerException
    at org.thymeleaf.spring5.util.SpringVersionUtils.<clinit>(SpringVersionUtils.java:52)
    ... 97 more

失敗しているテストは PowerMock を使って static メソッドをテストしているものなのですが、gradle の build タスクからだとテストが成功するが IntelliJ IDEA から実行すると失敗するようです。

長くなったので一旦ここで止めて、次回へ続きます。

履歴

2019/02/12
初版発行。

Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その3 )( build.gradle を変更する )

概要

記事一覧はこちらです。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その3 )( build.gradle を変更する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • build.gradle を変更します。
      • Spring Initializr で 2.1.2 のプロジェクトを作成して、変更した方がよい点があれば反映します。
      • Spring Boot のバージョンを 2.0.8 → 2.1.2 に変更します。
      • ライブラリは最新バージョンにアップデートします。

参照したサイト・書籍

目次

  1. Spring Initializr で 2.1.2 のプロジェクトを作成する
  2. build.gradle を変更する
  3. Rebuild Project 実行時に出るエラーを修正する
    1. java: org.springframework.boot.web.client.RestTemplateBuilderのsetConnectTimeout(int)は非推奨になりました/setReadTimeout(int)は非推奨になりました
  4. build タスク実行時に出るエラーを修正する
    1. エラー: BaseTestSqlは繰返し可能な注釈型ではありません/エラー: TestDataは繰返し可能な注釈型ではありません
    2. spring-boot-test-2.1.2.RELEASE.jar(/org/springframework/boot/test/context/SpringBootTest.class): 警告:タイプ'ExtendWith'内に注釈メソッド'value()'が見つかりません: org.junit.jupiter.api.extension.ExtendWithのクラス・ファイルが見つかりません
  5. メモ書き&次回は。。。

手順

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

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

f:id:ksby:20190209014309p:plain f:id:ksby:20190209014403p:plain f:id:ksby:20190209014702p:plain f:id:ksby:20190209014752p:plain f:id:ksby:20190209014835p:plain f:id:ksby:20190209015041p:plain f:id:ksby:20190209015125p:plain f:id:ksby:20190209015254p:plain f:id:ksby:20190209015329p:plain f:id:ksby:20190209015720p:plain f:id:ksby:20190209015809p:plain

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

buildscript {
    ext {
        springBootVersion = '2.1.2.RELEASE'
    }
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

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

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.flywaydb:flyway-core'
    implementation 'org.springframework.retry:spring-retry'
    implementation 'org.springframework.session:spring-session-data-redis'
    runtimeOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'org.postgresql:postgresql'
    compileOnly 'org.springframework.boot:spring-boot-configuration-processor'
    compileOnly 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.security:spring-security-test'
}

今回は反映した方が良さそうな点はありませんでした。

build.gradle を変更する

build.gradle を以下のように変更します。

buildscript {
    ext {
        group "ksbysample"
        version "2.1.2-RELEASE"
    }
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/release/" }
        maven { url "https://plugins.gradle.org/m2/" }
    }
}

plugins {
    id "java"
    id "eclipse"
    id "idea"
    id "org.springframework.boot" version "2.1.2.RELEASE"
    id "io.spring.dependency-management" version "1.0.6.RELEASE"
    id "groovy"
    id "checkstyle"
    id "com.github.spotbugs" version "1.6.9"
    id "pmd"
    id "net.ltgt.errorprone" version "0.0.16"
    id "de.undercouch.download" version "3.4.3"
    id "com.gorylenko.gradle-git-properties" version "2.0.0"
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

wrapper {
    gradleVersion = "5.2"
    distributionType = Wrapper.DistributionType.ALL
}

[compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8"
[compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = [
        "-Xlint:all,-options,-processing,-path"
        , "-Xep:RemoveUnusedImports:WARN"
        , "-Xep:InsecureCryptoUsage:OFF"
        , "-Xep:ParameterName:OFF"
]

// for Doma 2
// JavaクラスとSQLファイルの出力先ディレクトリを同じにする
processResources.destinationDir = compileJava.destinationDir
// コンパイルより前にSQLファイルを出力先ディレクトリにコピーするために依存関係を逆転する
compileJava.dependsOn processResources

springBoot {
    buildInfo()
}

idea {
    module {
        inheritOutputDirs = false
        outputDir = file("$buildDir/classes/main/")
    }
}

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

    // for Doma 2
    domaGenRuntime
}

checkstyle {
    configFile = file("${rootProject.projectDir}/config/checkstyle/google_checks.xml")
    toolVersion = "8.17"
    sourceSets = [project.sourceSets.main]
}

spotbugs {
    toolVersion = "3.1.11"
    ignoreFailures = true
    effort = "max"
    spotbugsTest.enabled = false
}
tasks.withType(com.github.spotbugs.SpotBugsTask) {
    reports {
        xml.enabled = false
        html.enabled = true
    }
}

pmd {
    toolVersion = "6.11.0"
    sourceSets = [project.sourceSets.main]
    ignoreFailures = true
    consoleOutput = true
    ruleSetFiles = rootProject.files("/config/pmd/pmd-project-rulesets.xml")
    ruleSets = []
}
pmdMain {
    def backupLoggerLevel
    doFirst {
        backupLoggerLevel = logger.context.level
        logger.context.level = LogLevel.QUIET
    }
    doLast {
        logger.context.level = backupLoggerLevel
    }
}

repositories {
    mavenCentral()
}

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

dependencies {
    def jdbcDriver = "org.postgresql:postgresql:42.2.5"
    def spockVersion = "1.2-groovy-2.5"
    def domaVersion = "2.23.0"
    def lombokVersion = "1.18.4"
    def errorproneVersion = "2.3.1"
    def powermockVersion = "2.0.0"
    def spotbugsVersion = "3.1.11"

    // 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")
    runtimeOnly("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")
    testImplementation("org.springframework.security:spring-security-test")
    testImplementation("org.yaml:snakeyaml")

    // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの
    runtimeOnly("${jdbcDriver}")
    implementation("com.integralblue:log4jdbc-spring-boot-starter:1.0.2")
    implementation("org.simpleframework:simple-xml:2.7.1")
    implementation("com.univocity:univocity-parsers:2.8.1")
    implementation("com.google.guava:guava:27.0.1-jre")
    implementation("org.flywaydb:flyway-core:5.2.4")
    implementation("com.zaxxer:HikariCP:3.3.0")
    testImplementation("org.dbunit:dbunit:2.6.0")
    testImplementation("com.icegreen:greenmail:1.5.9")
    testImplementation("org.assertj:assertj-core:3.11.1")
    testImplementation("com.jayway.jsonpath:json-path:2.4.0")
    testImplementation("org.jsoup:jsoup:1.11.3")
    testImplementation("cglib:cglib-nodep:3.2.10")
    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 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}")
    compileOnly("net.jcip:jcip-annotations:1.0")
    compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}")
    testImplementation("com.google.code.findbugs:jsr305:3.0.2")
}
  • buildscript block の ext block 内で version "2.0.8-RELEASE"version "2.1.2-RELEASE" に変更します。
  • plugins block の以下の点を変更します。
    • id "org.springframework.boot" version "2.0.8.RELEASE"id "org.springframework.boot" version "2.1.2.RELEASE"
    • id "com.github.spotbugs" version "1.6.8"id "com.github.spotbugs" version "1.6.9"
    • id "com.gorylenko.gradle-git-properties" version "2.0.0-beta1"id "com.gorylenko.gradle-git-properties" version "2.0.0"
  • checkstyle block で toolVersion = "8.16"toolVersion = "8.17" に変更します。
  • spotbugs で toolVersion = "3.1.10"toolVersion = "3.1.11" に変更します。
  • pmd で toolVersion = "6.10.0"toolVersion = "6.11.0" に変更します。
  • dependencyManagement block から bomProperty "groovy.version", "2.5.4" を削除します。
  • dependencies block の以下の点を変更します。
    • def domaVersion = "2.21.0"def domaVersion = "2.23.0"
    • def spotbugsVersion = "3.1.10"def spotbugsVersion = "3.1.11"
    • implementation("com.univocity:univocity-parsers:2.7.6")implementation("com.univocity:univocity-parsers:2.8.1")

変更後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると、特にエラーは出ずに更新されました。

Rebuild Project 実行時に出るエラーを修正する

clean タスク実行 → Rebuild Project 実行 をするとエラーが出るので修正します。

f:id:ksby:20190209023252p:plain

java: org.springframework.boot.web.client.RestTemplateBuilderのsetConnectTimeout(int)は非推奨になりました/setReadTimeout(int)は非推奨になりました

エラーが出たのは src/main/java/ksbysample/webapp/lending/service/calilapi/CalilApiService.java の以下の箇所でした。

f:id:ksby:20190209024706p:plain

RestTemplateBuilder#setConnectTimeout, setReadTimeout の引数が int 型のメソッドは非推奨となり Duration 型で指定するメソッドに変わったためでした。Spring Boot 2.1 Release Notes - Deprecations in Spring Boot 2.1 に記述があります。引数に渡している定数 CONNECT_TIMEOUT、READ_TIMEOUT を int 型から Duration 型に変更します。

f:id:ksby:20190209025351p:plain

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

build タスク実行をするとエラーが出るので修正します。

f:id:ksby:20190209030329p:plain f:id:ksby:20190209030415p:plain

エラー: BaseTestSqlは繰返し可能な注釈型ではありません/エラー: TestDataは繰返し可能な注釈型ではありません

こちらから先に対応します。エラーが出たのは src/test/java/ksbysample/webapp/lending/TestDataResourceTest.java の以下の箇所でした。

f:id:ksby:20190209031051p:plain f:id:ksby:20190209031232p:plain

調べてみると、

  • @Repeatable アノテーションが付いている他の繰返し可能な注釈型を見ましたが、違いがあるようには見えませんでした。
  • demo プロジェクトに BaseTestSql、BaseTestSqlList のファイルをコピーしてテストクラスを作成して付与してみましたが、再現せず。
  • そもそも動かないのではなくて compile が通らない。
  • gradlew build --stacktrace --debug を実行してみると以下のログが出力されていました。
17:18:41.054 [INFO] [org.gradle.api.internal.tasks.compile.incremental.IncrementalCompilerDecorator] Full recompilation is required because no incremental change information is available. This is usually caused by clean builds or changing compiler arguments.
17:18:41.055 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Build operation 'Compile Java for :compileTestJava' started
17:18:41.062 [DEBUG] [org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler] Compiler arguments: -source 1.8 -target 1.8 -d D:\project-springboot\ksbysample-webapp-lending\build\classes\java\test -encoding UTF-8 -g -sourcepath  -processorpath C:\Users\root\.gradle\caches\modules-2\files-2.1\org.projectlombok\lombok\1.18.4\7103ab519b1cdbb0642ad4eaf1db209d905d0f96\lombok-1.18.4.jar;C:\Users\root\.gradle\caches\modules-2\files-2.1\org.seasar.doma\doma\2.23.0\f5340b3f807100eaa28e725cf9ec891df6441a9c\doma-2.23.0.jar -s D:\project-springboot\ksbysample-webapp-lending\build\generated\sources\annotationProcessor\java\test -XDuseUnsharedTable=true -classpath D:\project-springboot\ksbysample-webapp-lending\build\classes\java\main;.....(長いので classpath は途中省略する).....C:\Users\root\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.11.1\268f0fe4df3eefe052b57c87ec48517d64fb2a10\log4j-api-2.11.1.jar -Xlint:all,-options,-processing,-path -Xep:RemoveUnusedImports:WARN -Xep:InsecureCryptoUsage:OFF -Xep:ParameterName:OFF D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\helper\SimpleRequestBuilder.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\helper\TestHelper.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\matcher\CustomModelResultMatchers.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\matcher\ErrorsResultMatchers.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\matcher\HtmlResultMatchers.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\AssertOptions.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\BaseTestData.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\BaseTestSql.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\BaseTestSqlList.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\DbUnitUtils.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\NoUseTestDataResource.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\TableDataAssert.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\TestData.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\TestDataList.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\TestDataLoader.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\TestDataResource.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\TestSql.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\TestSqlExecutor.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\db\TestSqlList.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\mail\MailServerResource.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\common\test\rule\mockmvc\SecurityMockMvcResource.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\test\Item.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\test\ItemTypeStringToCodeConversion.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\test\StringToLocalDateTimeConversion.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\test\UniVocityParsersTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\helper\library\LibraryHelperTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\helper\mail\EmailHelperTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\helper\mail\Mail001HelperTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\helper\mail\Mail002HelperTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\helper\mail\Mail003HelperTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\helper\message\MessagesPropertiesHelperTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\helper\url\UrlAfterLoginHelperTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\helper\user\UserHelperTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\listener\rabbitmq\InquiringStatusOfBookQueueListenerTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\security\LendingUserDetailsHelperTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\security\LendingUserDetailsServiceTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\security\LendingUserDetailsTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\service\calilapi\CalilApiServiceTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\service\file\BooklistCsvFileServiceTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\service\queue\InquiringStatusOfBookQueueServiceTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\service\UserInfoServiceTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\TestDataResourceTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\values\validation\ValuesEnumValidatorTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\admin\library\AdminLibraryControllerTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\admin\library\AdminLibraryServiceTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\booklist\BooklistControllerTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\booklist\BooklistServiceTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\booklist\UploadBooklistFormValidatorTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\confirmresult\ConfirmresultControllerTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\ExceptionHandlerAdviceTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\lendingapp\LendingappControllerTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\lendingapp\LendingappFormValidatorTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\lendingapproval\LendingapprovalControllerTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\lendingapproval\LendingapprovalFormValidatorTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\LoginControllerTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\web\WebappErrorControllerTest.java D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\webapi\library\LibraryControllerTest.java
17:18:41.063 [INFO] [net.ltgt.gradle.errorprone.ErrorProneCompiler] Compiling with error-prone compiler
17:18:41.064 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Build operation 'Resolve files of :errorprone' started
17:18:41.064 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Completing Build operation 'Resolve files of :errorprone'
17:18:41.064 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Build operation 'Resolve files of :errorprone' completed
17:18:44.293 [ERROR] [system.err] C:\Users\root\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-test\2.1.2.RELEASE\89b227adbba0d6e9b85a2fde9119ef00428a45e3\spring-boot-test-2.1.2.RELEASE.jar(/org/springframework/boot/test/context/SpringBootTest.class): 警告:タイプ'ExtendWith'内に注釈メソッド'value()'が見つかりません: org.junit.jupiter.api.extension.ExtendWithのクラス・ファイルが見つかりません
17:18:44.493 [ERROR] [system.err] C:\Users\root\.gradle\caches\modules-2\files-2.1\org.springframework.boot\spring-boot-test\2.1.2.RELEASE\89b227adbba0d6e9b85a2fde9119ef00428a45e3\spring-boot-test-2.1.2.RELEASE.jar(/org/springframework/boot/test/context/SpringBootTest.class): 警告:タイプ'ExtendWith'内に注釈メソッド'value()'が見つかりません: org.junit.jupiter.api.extension.ExtendWithのクラス・ファイルが見つかりません
17:18:44.495 [ERROR] [system.err] D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\TestDataResourceTest.java:24: エラー: BaseTestSqlは繰返し可能な注釈型ではありません
17:18:44.495 [ERROR] [system.err]     @BaseTestSql(order = 2, sql = "update library_forsearch set formal = '図書館サンプル' where systemid = 'Kanagawa_Sample'")
17:18:44.495 [ERROR] [system.err]     ^
17:18:44.495 [ERROR] [system.err] D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\TestDataResourceTest.java:37: エラー: BaseTestSqlは繰返し可能な注釈型ではありません
17:18:44.495 [ERROR] [system.err]         @BaseTestSql(sql = "update user_info set username = 'tanaka jiro' where user_id = 1")
17:18:44.495 [ERROR] [system.err]         ^
17:18:44.495 [ERROR] [system.err] D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\TestDataResourceTest.java:86: エラー: TestDataは繰返し可能な注釈型ではありません
17:18:44.496 [ERROR] [system.err]         @TestData(order = 2, value = "web/confirmresult/testdata/001")
17:18:44.496 [ERROR] [system.err]         ^
17:18:44.496 [ERROR] [system.err] D:\project-springboot\ksbysample-webapp-lending\src\test\java\ksbysample\webapp\lending\TestDataResourceTest.java:97: エラー: TestDataは繰返し可能な注釈型ではありません
17:18:44.496 [ERROR] [system.err]         @TestData(order = 1, value = "web/confirmresult/testdata/001")
17:18:44.496 [ERROR] [system.err]         ^
17:18:44.510 [ERROR] [system.err] エラー4個
17:18:44.510 [ERROR] [system.err] 警告2個
17:18:44.518 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Completing Build operation 'Compile Java for :compileTestJava'
17:18:44.518 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Build operation 'Compile Java for :compileTestJava' completed
17:18:44.518 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Completing Build operation 'Execute compile for :compileTestJava'
17:18:44.519 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Build operation 'Execute compile for :compileTestJava' completed
17:18:44.519 [DEBUG] [org.gradle.api.internal.tasks.execution.DefaultTaskFingerprinter] Fingerprinting property destinationDir (Output) for task ':compileTestJava'
17:18:44.520 [DEBUG] [org.gradle.api.internal.tasks.execution.DefaultTaskFingerprinter] Fingerprinting property options.annotationProcessorGeneratedSourcesDirectory (Output) for task ':compileTestJava'
17:18:44.520 [DEBUG] [org.gradle.internal.execution.impl.steps.CacheStep] Not storing result of task ':compileTestJava' in cache because the execution failed
17:18:44.521 [DEBUG] [org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter] Removed task artifact state for {} from context.
17:18:44.521 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Completing Build operation 'Task :compileTestJava'
17:18:44.521 [DEBUG] [org.gradle.internal.operations.DefaultBuildOperationExecutor] Build operation 'Task :compileTestJava' completed
17:18:44.521 [INFO] [org.gradle.execution.plan.DefaultPlanExecutor] :compileTestJava (Thread[Execution worker for ':' Thread 3,5,main]) completed. Took 4.223 secs.

Compiling with error-prone compiler というログがあります。error-prone を入れていない demo プロジェクトでは再現していないので、原因は error-prone かもしれません。

build.gradle を以下のように変更して error-prone を外してみます。

plugins {
    id "java"
    id "eclipse"
    id "idea"
    id "org.springframework.boot" version "2.1.2.RELEASE"
    id "io.spring.dependency-management" version "1.0.6.RELEASE"
    id "groovy"
    id "checkstyle"
    id "com.github.spotbugs" version "1.6.9"
    id "pmd"
// compileエラーが出るので error-prone を一旦コメントアウトする 
//    id "net.ltgt.errorprone" version "0.0.16"
    id "de.undercouch.download" version "3.4.3"
    id "com.gorylenko.gradle-git-properties" version "2.0.0"
}

..........

[compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8"
[compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = [
        "-Xlint:all,-options,-processing,-path"
// compileエラーが出るので error-prone を一旦コメントアウトする 
//        , "-Xep:RemoveUnusedImports:WARN"
//        , "-Xep:InsecureCryptoUsage:OFF"
//        , "-Xep:ParameterName:OFF"
]

..........

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

    // for Error Prone ( http://errorprone.info/ )
// compileエラーが出るので error-prone を一旦コメントアウトする 
//    errorprone("com.google.errorprone:error_prone_core:${errorproneVersion}")
//    compileOnly("com.google.errorprone:error_prone_annotations:${errorproneVersion}")

    ..........

build タスク実行をすると ...は繰返し可能な注釈型ではありません のエラーは出なくなりました。ただし 警告:タイプ'ExtendWith'内に注釈メソッド'value()'が見つかりません のエラーが4つに増えて、大量のテストが失敗していました。

f:id:ksby:20190209175010p:plain

error-prone は Java SE を 11 にバージョンアップした後に対応することにし、しばらくコメントアウトしたままにします。

spring-boot-test-2.1.2.RELEASE.jar(/org/springframework/boot/test/context/SpringBootTest.class): 警告:タイプ'ExtendWith'内に注釈メソッド'value()'が見つかりません: org.junit.jupiter.api.extension.ExtendWithのクラス・ファイルが見つかりません

Spring Boot 2.1 Release Notes - JUnit 5All @…​Test annotations are meta-annotated with @ExtendWith(SpringExtension.class) so this redundant part of the setup can be removed if you’re using JUnit 5. という記述があり @SpringBootTest アノテーションが付いていると @ExtendWith(SpringExtension.class) が自動で付くようになったらしいです。

いろいろ試してみたところ以下の結論でした。

  • JUnit 5 のアノテーションである @ExtendWith(SpringExtension.class) が自動で付くようになったが JUnit 4 → JUnit 5 にバージョンアップしていないため必要なライブラリが存在しない。
  • [compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs-Xlint:all を指定しているので、compile 時の警告が出力される。
  • つまり compilerArgs に -Xlint:all を指定するのを止めるか、JUnit 5 にバージョンアップしない限りこの警告は消えない。

今回どこかで JUnit 5 にバージョンアップして警告が出ないようにします。

メモ書き&次回は。。。

今回の調査中に以下の点に気づいたのでメモ書きとして残しておきます。

  • @ComponentScan に @Repeatable が付与されていることに気づきました。このアノテーションは複数付与可能だったんですね。
  • 以前 @Repeatable のサンプルを見て BaseTestSql、BaseTestSqlList を別々のクラス&ファイルで実装したのですが、他の @Repeatable が付与されたアノテーションの実装を見ていたところ List のクラスを別ファイルではなくインナークラスに定義しているものを見かけました。別ファイルにしなくても定義できるようです。

次回は大量のテストが失敗しているのを修正します。

履歴

2019/02/09
初版発行。