かんがるーさんの日記

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

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その73 )( Spring Boot を 1.5.14 → 2.0.4 へバージョンアップする )

概要

記事一覧はこちらです。

感想 の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Spring Boot を 1系(1.5.14) → 2系(2.0.4) へバージョンアップします。

参照したサイト・書籍

目次

  1. build.gradle を変更する
  2. エラーの出ているクラスを変更する
    1. src/main/java/ksbysample/webapp/bootnpmgeb/config/ApplicationConfig.java
    2. src/main/java/ksbysample/webapp/bootnpmgeb/config/WebMvcConfig.java
    3. src/main/java/ksbysample/webapp/bootnpmgeb/config/WebSecurityConfig.java
  3. application.properties で spring.session.store-type の設定を hash_mapjdbc に変更する(hash_map はなくなりました)
  4. spring-session-jdbc を追加する
  5. Build Project(Ctrl+F9)を実行して出るエラーを取り除く
    1. org.hibernate.validator.constraints.NotEmptyjavax.validation.constraints.NotEmpty に変更する
  6. clean タスク → Rebuild Project → build タスクを実行する
  7. テストが失敗した原因を調査する
    1. java.lang.NoSuchMethodError: org.mockito.internal.handler.MockHandlerFactory.createMockHandler(Lorg/mockito/mock/MockCreationSettings;)Lorg/mockito/internal/InternalMockHandler;
  8. Tomcat を起動して、起動時に spring-boot-properties-migrator が出力するメッセージに対応する
    1. Key: security.basic.enabled、Reason: The security auto-configuration is no longer customizable.
  9. gebTest を実行してみる
  10. ブラウザで画面を表示して入力してみる
  11. 作成された jar ファイルの中身を確認する
  12. 本番稼働用ディレクトリに jar ファイルをコピーして動作確認する
  13. build.gradle から runtimeOnly("org.springframework.boot:spring-boot-properties-migrator") を削除する
  14. メモ書き

手順

build.gradle を変更する

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

buildscript {
    ext {
        group "ksbysample"
        version "1.0.2-RELEASE"
    }
}

plugins {
    id "java"
    id "eclipse"
    id "idea"
    id "org.springframework.boot" version "2.0.4.RELEASE"
    id "io.spring.dependency-management" version "1.0.6.RELEASE"
    id "groovy"
    id "net.ltgt.errorprone" version "0.0.14"
    id "checkstyle"
    id "findbugs"
    id "pmd"
    id "com.moowork.node" version "1.2.0"
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

wrapper {
    gradleVersion = '4.8.1'
    distributionType = Wrapper.DistributionType.ALL
}

[compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ['-Xlint:all,-options,-processing,-path']
compileJava.options.compilerArgs += [
        '-Xep:RemoveUnusedImports:WARN'
        , '-Xep:ParameterName:OFF'
]

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

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

configurations {
    // for Doma 2
    domaGenRuntime
}

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

findbugs {
    toolVersion = '3.0.1'
    sourceSets = [project.sourceSets.main]
    ignoreFailures = true
    effort = "max"
    excludeFilter = file("${rootProject.projectDir}/config/findbugs/findbugs-exclude.xml")
}

tasks.withType(FindBugs) {
    reports {
        xml.enabled = false
        html.enabled = true
    }
}

pmd {
    toolVersion = "6.5.0"
    sourceSets = [project.sourceSets.main]
    ignoreFailures = true
    consoleOutput = true
    ruleSetFiles = rootProject.files("/config/pmd/pmd-project-rulesets.xml")
    ruleSets = []
}

repositories {
    mavenCentral()
}

dependencyManagement {
    imports {
        // mavenBom は以下の URL のものを使用する
        // https://repo.spring.io/release/org/springframework/boot/spring-boot-starter-parent/2.0.4.RELEASE/
        // bomProperty に指定可能な property は以下の URL の BOM に記述がある
        // https://repo.spring.io/release/org/springframework/boot/spring-boot-dependencies/2.0.4.RELEASE/spring-boot-dependencies-2.0.4.RELEASE.pom
        mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
    }
}

dependencies {
    def spockVersion = "1.1-groovy-2.4"
    def domaVersion = "2.19.2"
    def lombokVersion = "1.18.0"
    def errorproneVersion = "2.3.1"
    def powermockVersion = "1.7.4"
    def seleniumVersion = "3.13.0"

    // dependency-management-plugin によりバージョン番号が自動で設定されるもの
    // Appendix F. Dependency versions ( https://docs.spring.io/spring-boot/docs/2.0.4.RELEASE/reference/html/appendix-dependency-versions.html ) 参照
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-thymeleaf") {
        exclude group: "org.codehaus.groovy", module: "groovy"
    }
    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")
    runtimeOnly("org.springframework.boot:spring-boot-devtools")
    implementation("org.springframework.session:spring-session-core")
    implementation("org.springframework.session:spring-session-jdbc")
    implementation("org.codehaus.janino:janino")
    implementation("org.apache.tomcat:tomcat-jdbc")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.springframework.security:spring-security-test")
    testImplementation("org.yaml:snakeyaml")
    testImplementation("org.mockito:mockito-core")

    // dependency-management-plugin によりバージョン番号が自動で設定されないもの、あるいは最新バージョンを指定したいもの
    implementation("com.integralblue:log4jdbc-spring-boot-starter:1.0.2")
    implementation("org.flywaydb:flyway-core:5.1.4")
    implementation("com.h2database:h2:1.4.192")
    implementation("com.github.rozidan:modelmapper-spring-boot-starter:1.0.0")
    implementation("com.google.guava:guava:25.1-jre")
    implementation("org.apache.commons:commons-lang3:3.7")
    testImplementation("org.dbunit:dbunit:2.5.4")
    testImplementation("org.assertj:assertj-core:3.10.0")
    testImplementation("org.spockframework:spock-core:${spockVersion}")
    testImplementation("org.spockframework:spock-spring:${spockVersion}")
    testImplementation("com.google.code.findbugs:jsr305:3.0.2")
    testImplementation("org.jsoup:jsoup:1.11.3")
    testImplementation("com.icegreen:greenmail:1.5.7")

    // for lombok
    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("com.h2database:h2:1.4.192")

    // 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 Geb + Spock
    testImplementation("org.gebish:geb-spock:2.1")
    testImplementation("org.seleniumhq.selenium:selenium-chrome-driver:${seleniumVersion}")
    testImplementation("org.seleniumhq.selenium:selenium-firefox-driver:${seleniumVersion}")
    testImplementation("org.seleniumhq.selenium:selenium-support:${seleniumVersion}")
    testImplementation("org.seleniumhq.selenium:selenium-api:${seleniumVersion}")
    testImplementation("org.seleniumhq.selenium:selenium-remote-driver:${seleniumVersion}")

    // for Spring Boot 2.0 Migration
    runtimeOnly("org.springframework.boot:spring-boot-properties-migrator")
}

..........
  • buildscript block の以下の点を変更します。
    • Web アプリのバージョン番号を version "1.0.1-RELEASE"version "1.0.2-RELEASE" に変更します。
    • Spring Boot のバージョン番号は plugins block の id "org.springframework.boot" のところで指定するようになるので、springBootVersion = "1.5.14.RELEASE" を削除します。
  • plugins block の以下の点を変更します。
    • // plugins {} block 内では ${springBootVersion} が使用できないので、バージョンを直接記述している のコメントを削除します。
    • id "org.springframework.boot" version "1.5.14.RELEASE"id "org.springframework.boot" version "2.0.4.RELEASE" に変更します。
    • id "io.spring.dependency-management" version "1.0.6.RELEASE" を追加します。
  • 明記しなくても問題ないので bootRepackage { ... } を削除します。
  • dependencyManagement block の以下の点を変更します。
    • mavenBom("org.springframework.boot:spring-boot-starter-parent:${springBootVersion}")mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES に変更します。
    • Appendix F. Dependency versions を見ると Thymeleaf のバージョンが 3.0.9.RELEASE になっているので、以下の5行を削除します。
      • bomProperty 'thymeleaf.version', '3.0.9.RELEASE'
      • bomProperty 'thymeleaf-extras-springsecurity4.version', '3.0.2.RELEASE'
      • bomProperty 'thymeleaf-layout-dialect.version', '2.2.2'
      • bomProperty 'thymeleaf-extras-data-attribute.version', '2.0.1'
      • bomProperty 'thymeleaf-extras-java8time.version', '3.0.1.RELEASE'
  • dependencies block の以下の点を変更します。
    • compile(...)implementation(...) に変更します。
    • Appendix F. Dependency versions を見ると spring-session は存在せず、spring-session-corespring-session-data-gemfire のように後ろに -... が付くようになっていました。implementation("org.springframework.session:spring-session")implementation("org.springframework.session:spring-session-core") に変更します。
    • Spring Boot 2 では HikariCP がデフォルトのコネクションプーリングに変わり、Tomcat JDBC Connection Pool はデフォルトでは入りません。今は HikariCP には変更しないので implementation("org.apache.tomcat:tomcat-jdbc") を追加して入れるようにします。
    • testImplementation("org.powermock:powermock-api-mockito:${powermockVersion}")testImplementation("org.powermock:powermock-api-mockito2:${powermockVersion}") に変更します。
    • Spring Boot 2.0 Migration Guide - Before You Start の記述に従い runtimeOnly("org.springframework.boot:spring-boot-properties-migrator") を追加します。

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

エラーの出ているクラスを変更する

src/main/java/ksbysample/webapp/bootnpmgeb/config/ApplicationConfig.java

f:id:ksby:20180731011156p:plain f:id:ksby:20180731012343p:plain

  • DataSourceBuilder クラスが import できずエラーが出ていました。import 文を削除した後、Alt+Enter を押して import し直します。

src/main/java/ksbysample/webapp/bootnpmgeb/config/WebMvcConfig.java

f:id:ksby:20180731012914p:plain

  • WebMvcConfigurerAdapter が非推奨になりました。WebMvcConfigurerAdapter クラスの JavaDoc の説明を読むと WebMvcConfigurer インターフェースに Java 8 のデフォルトメソッドで実装が追加されたので WebMvcConfigurer インターフェースを使用するよう記述されていました。extends WebMvcConfigurerAdapterimplements WebMvcConfigurer に変更します。

    f:id:ksby:20180731013237p:plain

  • SpringTemplateEngine クラスが import できずエラーが出ていました。import 文を削除した後、Alt+Enter を押して import class し直します。

src/main/java/ksbysample/webapp/bootnpmgeb/config/WebSecurityConfig.java

f:id:ksby:20180731013952p:plain

  • 28. Security から @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) の記述が削除されていたので、おそらく無くなったものと思われます。@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) を削除します。

application.properties で spring.session.store-type の設定を hash_mapjdbc に変更する(hash_map はなくなりました)

f:id:ksby:20180731015744p:plain

spring.session.store-typehash_map が指定できなくなっていました。実際選択可能な候補を表示させてみると hash_map がありません。

f:id:ksby:20180731020018p:plain

理由が書かれているのは Better detection of Spring Session store のページのようです。今回は hash_mapjdbc に変更して、spring-session-jdbc を入れることにします。

spring-session-jdbc を追加する

build.gradle に implementation("org.springframework.session:spring-session-jdbc") を追加します。

dependencies {
    ..........
    runtimeOnly("org.springframework.boot:spring-boot-devtools")
    implementation("org.springframework.session:spring-session-core")
    implementation("org.springframework.session:spring-session-jdbc")
    implementation("org.codehaus.janino:janino")
    ..........

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

src/main/resources/application.properties に以下の設定を追加します。

spring.session.store-type=jdbc
spring.session.jdbc.initialize-schema=embedded
spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-h2.sql
spring.session.jdbc.table-name=SPRING_SESSION
  • 以下の3行を追加します。
    • spring.session.jdbc.initialize-schema=embedded
    • spring.session.jdbc.schema=classpath:org/springframework/session/jdbc/schema-h2.sql
    • spring.session.jdbc.table-name=SPRING_SESSION
  • spring.session.jdbc.schema に設定する SQL ファイルは org.springframework.session:spring-session-jdbc のライブラリの下を見ると分かります。

    f:id:ksby:20180731052251p:plain

Build Project(Ctrl+F9)を実行して出るエラーを取り除く

org.hibernate.validator.constraints.NotEmptyjavax.validation.constraints.NotEmpty に変更する

Ctrl+F9 を押して Build Project を実行すると org.hibernate.validator.constraintsのorg.hibernate.validator.constraints.NotEmptyは非推奨になりました のメッセージが表示されました。

f:id:ksby:20180731233816p:plain

org.hibernate.validator.constraints.NotEmpty クラスのソースを見ると以下の画像の記述がありますので、javax.validation.constraints.NotEmpty に変更します。

f:id:ksby:20180731234056p:plain

変更したのは以下のソースです。import 文を削除した後、Alt+Enter で import し直しました。

  • src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput01Form.java
  • src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormNotEmptyRule.java
  • src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput03FormNotEmptyRule.java

clean タスク → Rebuild Project → build タスクを実行する

clean タスク → Rebuild Project → build タスクを実行してみると、以下の画像のような結果でした。

f:id:ksby:20180801214047p:plain f:id:ksby:20180801214147p:plain

  • FindBugsFindBugs rule violations were found. のメッセージが表示されました。
  • 147 tests completed, 1 failed とテストが1件失敗しました。

FindBugs の方は一旦後回しにして、まずはテストが失敗した原因を取り除きます。

テストが失敗した原因を調査する

java.lang.NoSuchMethodError: org.mockito.internal.handler.MockHandlerFactory.createMockHandler(Lorg/mockito/mock/MockCreationSettings;)Lorg/mockito/internal/InternalMockHandler;

build タスクの出力内容では原因が分からないので、Project Tool Window の src/test/groovy/ksbysample から「Run 'Tests in 'ksbysample''」を実行します。

f:id:ksby:20180801215014p:plain

失敗したテストは以下の画像のテストでした。java.lang.NoSuchMethodError: org.mockito.internal.handler.MockHandlerFactory.createMockHandler(Lorg/mockito/mock/MockCreationSettings;)Lorg/mockito/internal/InternalMockHandler; というエラーメッセージが出ています。

f:id:ksby:20180801215301p:plain

エラーメッセージで検索すると There is a issue, after I downgrade the Mockito version, it disappeared という Issue が見つかりました。PowerMock のバージョンを 2.0.0-beta.5 にすると直るようです。

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

dependencies {
    def spockVersion = "1.1-groovy-2.4"
    def domaVersion = "2.19.2"
    def lombokVersion = "1.18.0"
    def errorproneVersion = "2.3.1"
    def powermockVersion = "2.0.0-beta.5"
    def seleniumVersion = "3.13.0"
  • def powermockVersion = "1.7.4"def powermockVersion = "2.0.0-beta.5" に変更します。

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

clean タスク → Rebuild Project → build タスクを実行すると、今度は BUILD SUCCESSFUL が出力されました。

f:id:ksby:20180801220702p:plain

Tomcat を起動して、起動時に spring-boot-properties-migrator が出力するメッセージに対応する

Tomcat を起動すると以下のメッセージが表示されました。

f:id:ksby:20180801224201p:plain

また、少し放置していたら、1分毎に無効になったセッションを削除するための DELETE 文が実行されていました。なるほど、spring-session-jdbc だとこういう動作になるんですね。

f:id:ksby:20180801224436p:plain

Key: security.basic.enabled、Reason: The security auto-configuration is no longer customizable.

Spring Boot 2.0 Migration Guide - SecuritySpring Boot Security 2.0 を読んだ限りでは、application.properties から security.basic.enabled は設定できなくなり、設定するなら WebSecurityConfigurerAdapter の継承クラスで設定するとのこと。

試しに src/main/resources/application-develop.properties から security.basic.enabled=false の設定を削除した後 Tomcat を起動すると、Key: security.basic.enabled のメッセージは出力されなくなり、

f:id:ksby:20180801232830p:plain

H2 Console(http://localhost:8080/h2-console)にアクセスしても Basic 認証のダイアログは表示されませんでした。

f:id:ksby:20180801232446p:plain

gebTest を実行してみる

gebTest タスクを実行してみると、BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20180802002811p:plain

ブラウザで画面を表示して入力してみる

smtp4dev を起動した後、Tomcat を起動します。http://localhost:8080/inquiry/input/01/ にアクセスして画面からデータを入力してみます。

f:id:ksby:20180802003229p:plain f:id:ksby:20180802003323p:plain f:id:ksby:20180802003412p:plain f:id:ksby:20180802003450p:plain f:id:ksby:20180802003527p:plain

完了画面まで表示できました。またメールも問題なく送信されており、

f:id:ksby:20180802003557p:plain f:id:ksby:20180802003708p:plain

DB のデータも登録されていました。

f:id:ksby:20180802004036p:plain

作成された jar ファイルの中身を確認する

boot-npm-geb-sample-1.0.2-RELEASE.jar を開いてみると BOOT-INF の下に lib ディレクトリが作成されて、その下に外部ライブラリの jar ファイルが格納されていました。1.5系の時と違い、build.gradle に implementation で依存関係を記述しても jar ファイルの生成には問題ありませんでした。

f:id:ksby:20180802004248p:plain

本番稼働用ディレクトリに jar ファイルをコピーして動作確認する

以下の手順で動作することを確認しました。

  • C:\webapps\boot-npm-geb-sample\lib の下に boot-npm-geb-sample-1.0.2-RELEASE.jar をコピーする。
  • C:\webapps\boot-npm-geb-sample\bat\webapp_startup.bat 内の環境変数 WEBAPP_JAR の値を boot-npm-geb-sample-1.0.2-RELEASE.jar に変更する。
  • サービスではなくコマンドプロンプトから webapp_startup.bat を起動する。
  • C:\webapps\boot-npm-geb-sample\logs\boot-npm-geb-sample.log の最後に Started Application ... のログが出ることを確認する。
  • http://localhost:8080/inquiry/input/01/ にアクセスして画面が表示されることを確認する。

build.gradle から runtimeOnly("org.springframework.boot:spring-boot-properties-migrator") を削除する

バージョンアップ作業が終わりましたので、build.gradle に追加していた runtimeOnly("org.springframework.boot:spring-boot-properties-migrator") を削除します。

Spring Boot 2系へのバージョンアップは以上で完了です。

メモ書き

  • Spring Boot 2系から Flyway のバージョンが 5系に上がりましたが 、Flyway はバージョンアップ前から 5系を使用していたので今回は特に何もありませんでした。
  • Spring Boot 2系は Gradle 4.x 以降のみサポートされるので、Gradle が 3.x 以前の場合には Spring Boot を 2系にバージョンアップする前に Gradle のバージョンを 4.x に上げた方がよさそうです。
  • build.gradle の書き方がいろいろ変わります。一番変更が大きいファイルでした。
  • Spring Session が地味に仕様が変わっています(build.gradle に指定する artifactId の名前が違う、hash_map がなくなった)。

もう少し続きます。FindBugs で警告が出た箇所の確認、HikariCP への変更、及び Spring Boot Actuator の導入まで試してみる予定です。

履歴

2018/08/03
初版発行。