かんがるーさんの日記

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

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

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その81 )( eslint を 4.19.1 → 5.16.0 へ、windows-build-tools を 3.1.0 → 5.1.0 へ、jest を 23.4.1 → 24.7.1 へ、postcss-cli を 4.1.1 → 6.1.2 へバージョンアップする ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Gradle を 4.8.1 → 5.3.1 へ、Spring Boot を 2.0.4 → 2.1.4 へバージョンアップします。
    • 依存関係にあるモジュールも一部を除き最新バージョンにバージョンアップします。

参照したサイト・書籍

目次

  1. Gradle を 4.8.1 → 5.3.1 へバージョンアップする
  2. Spring Boot を 2.0.4 → 2.1.4 へバージョンアップする

手順

Gradle を 4.8.1 → 5.3.1 へバージョンアップする

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

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

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

f:id:ksby:20190413211524p:plain

gradlew --version コマンド実行時にファイルをダウンロードしていることを示す "Downloading" のメッセージが表示されませんでした。。。?  gradlew wrapper コマンドを実行してみると build.gradle にエラーがあるというメッセージが表示されます。

f:id:ksby:20190413224840p:plain

build.gradle の修正と gradlew wrapper コマンドを繰り返し、最終的には build.gradle の以下の点を変更しました。

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 "com.github.spotbugs" version "1.6.9"
    id "pmd"
    id "com.moowork.node" version "1.2.0"
    id "com.gorylenko.gradle-git-properties" version "1.5.1"
// Gradle 5.3 で internal API が変更されて gradle-processes が動かなくなったのでコメントアウトする
//    id "com.github.johnrengelman.processes" version "0.5.0"
    id "com.energizedwork.webdriver-binaries" version "1.4"
}

..........

// Gradle 5.3 で internal API が変更されて gradle-processes が動かなくなったのでコメントアウトする
//// for Geb + Spock Integration Test
//task startServer(type: com.github.jengelman.gradle.plugins.processes.tasks.JavaFork) {
//    jvmArgs = [
//            "-Dspring.profiles.active=develop",
//            "-Dlogging.level.root=OFF",
//            "-Dlogging.level.org.springframework.web=OFF",
//            "-Dlogging.level.jdbc.sqlonly=OFF",
//            "-Dlogging.level.jdbc.sqltiming=OFF",
//            "-Dlogging.level.jdbc.audit=OFF",
//            "-Dlogging.level.jdbc.resultset=OFF",
//            "-Dlogging.level.jdbc.resultsettable=OFF",
//            "-Dlogging.level.jdbc.connection=OFF"
//    ]
//    classpath += sourceSets.main.runtimeClasspath
//    main = "${mainClass}"
//    doLast {
//        Thread.sleep(15000)
//    }
//}
//task stopServer {
//    doLast {
//        startServer.processHandle.abort()
//    }
//}
webdriverBinaries {
    chromedriver "73.0.3683.68"
    geckodriver "0.24.0"
}
def drivers = ["chrome", "firefox"]
drivers.each { driver ->
    task "${driver}Test"(type: Test) {
        // 前回実行時以降に何も更新されていなくても必ず実行する
        outputs.upToDateWhen { false }
        systemProperty "geb.env", driver
        exclude "ksbysample/**"
// Gradle 5.3 で internal API が変更されて gradle-processes が動かなくなったのでコメントアウトする
//        dependsOn startServer
//        finalizedBy stopServer
    }
}
task gebTest {
    dependsOn drivers.collect { tasks["${it}Test"] }
    enabled = false
}
..........
  • SpotBugs の gradle plugin が 1.6.2 だと Gradle 5.3.1 に対応していないようなので 1.6.9 にバージョンアップしました。plugins block で id "com.github.spotbugs" version "1.6.2"id "com.github.spotbugs" version "1.6.9" に変更しています。
  • gradle-processes plugin の設定を記載している箇所でエラーが発生し、API changes with Gradle 5.3 という Issue も作成されていました。Gradle 5.3 で gradle-processes plugin が呼び出している internal API の仕様が変わったようです。gradle-processes plugin の設定を全てコメントアウトします。
    • plugins block で id "com.github.johnrengelman.processes" version "0.5.0"コメントアウトしました。
    • task startServer と task stopServer をコメントアウトしました。
    • Geb のテストタスクを動的生成している drivers.each { driver -> ... }dependsOn startServerfinalizedBy stopServerコメントアウトしました。

これで gradlew wrapper コマンドが正常終了するようになりました。また gradlew、gradlew.bat に DEFAULT_JVM_OPTS の設定が追加されたので set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"set DEFAULT_JVM_OPTS="-Xmx4096m" "-Xms4096m" に変更します。

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

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

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

f:id:ksby:20190413231123p:plain

Spring Boot を 2.0.4 → 2.1.4 へバージョンアップする

以下の方針でバージョンアップします。

  • Spring Boot を 2.0.4 → 2.1.4 にバージョンアップする。
  • Gradle の Plugin も com.github.spotbugs 以外は最新バージョンにする。
  • SpotBugs は gradle plugin(com.github.spotbugs) は 1.6.9、本体は 3.1.11 にする。
  • error-prone は現状維持。バージョンアップは JDK 11 に上げる時に行う。
  • checkstyle, pmd は後回し。
  • JUnit 5 の導入は後回し。

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

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

plugins {
    id "java"
    id "eclipse"
    id "idea"
    id "org.springframework.boot" version "2.1.4.RELEASE"
    id "io.spring.dependency-management" version "1.0.7.RELEASE"
    id "groovy"
    id "net.ltgt.errorprone" version "0.0.14"
    id "checkstyle"
    id "com.github.spotbugs" version "1.6.9"
    id "pmd"
    id "com.moowork.node" version "1.3.1"
    id "com.gorylenko.gradle-git-properties" version "2.0.0"
// Gradle 5.3 で internal API が変更されて gradle-processes が動かなくなったのでコメントアウトする
//    id "com.github.johnrengelman.processes" version "0.5.0"
    id "com.energizedwork.webdriver-binaries" version "1.4"
}

..........

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

    // for Doma 2
    domaGenRuntime
}

..........

spotbugs {
    // SpotBugs のレポートファイルは Firefox で見ると文字化けしない
    toolVersion = "3.1.11"
    ignoreFailures = true
    effort = "max"
    excludeFilter = file("${rootProject.projectDir}/config/spotbugs/spotbugs-exclude-filter.xml")
    spotbugsTest.enabled = false
}
tasks.withType(com.github.spotbugs.SpotBugsTask) {
    reports {
        xml.enabled = false
        html.enabled = true
    }
}

pmd {
    toolVersion = "6.6.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
    }
}

..........

dependencies {
    def spockVersion = "1.3-groovy-2.4"
    def domaVersion = "2.24.0"
    def lombokVersion = "1.18.6"
    def errorproneVersion = "2.3.1"
    def powermockVersion = "2.0.0"
    def seleniumVersion = "3.13.0"
    def spotbugsVersion = "3.1.11"

    // dependency-management-plugin によりバージョン番号が自動で設定されるもの
    // Appendix F. Dependency versions ( https://docs.spring.io/spring-boot/docs/2.1.4.RELEASE/reference/html/appendix-dependency-versions.html ) 参照
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-thymeleaf")
    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-actuator")
    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.flywaydb:flyway-core")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.springframework.security:spring-security-test")
    testImplementation("org.yaml:snakeyaml")

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

    // 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.3.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 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 "1.0.2-RELEASE"version "2.1.4-RELEASE" に変更します。今回から Spring Boot のバージョンに合わせます。
    • mainClass = "ksbysample.webapp.bootnpmgeb.Application" を削除します。
  • plugins block の以下の点を変更します。
    • id "org.springframework.boot" version "2.0.4.RELEASE"id "org.springframework.boot" version "2.1.4.RELEASE"
    • id "io.spring.dependency-management" version "1.0.6.RELEASE"id "io.spring.dependency-management" version "1.0.7.RELEASE"
    • id "com.moowork.node" version "1.2.0"id "com.moowork.node" version "1.3.1"
    • id "com.gorylenko.gradle-git-properties" version "1.5.1"id "com.gorylenko.gradle-git-properties" version "2.0.0"
  • configurations block に以下の2行を追加します。
    • testAnnotationProcessor.extendsFrom annotationProcessor
    • testImplementation.extendsFrom compileOnly
  • spotbugs block 内で toolVersion = "3.1.3"toolVersion = "3.1.11" に変更します。
  • pmdMain { ... } を追加します。
  • dependencies block の以下の点を変更します。
    • def spockVersion = "1.1-groovy-2.4"def spockVersion = "1.3-groovy-2.4"Geb が依存している groovy のバージョンが 2.4 なので、2.5 ではなく 2.4 にします)
    • def domaVersion = "2.19.2"def domaVersion = "2.24.0"
    • def lombokVersion = "1.18.0"def lombokVersion = "1.18.6"
    • def powermockVersion = "2.0.0-beta.5"def powermockVersion = "2.0.0"
    • def spotbugsVersion = "3.1.3"def spotbugsVersion = "3.1.11"
    • implementation("org.springframework.boot:spring-boot-starter-thymeleaf") に書いていた exclude group: "org.codehaus.groovy", module: "groovy" を削除します。
    • testImplementation("org.mockito:mockito-core") を削除します。
    • implementation("org.flywaydb:flyway-core:5.1.4")implementation("org.flywaydb:flyway-core:5.2.4")
    • implementation("com.google.guava:guava:25.1-jre")implementation("com.google.guava:guava:27.1-jre")
    • implementation("org.apache.commons:commons-lang3:3.7")implementation("org.apache.commons:commons-lang3:3.8.1")
    • testImplementation("org.dbunit:dbunit:2.5.4")testImplementation("org.dbunit:dbunit:2.6.0")
    • testImplementation("org.assertj:assertj-core:3.10.0")testImplementation("org.assertj:assertj-core:3.12.2")
    • testImplementation("com.icegreen:greenmail:1.5.7")testImplementation("com.icegreen:greenmail:1.5.10")
    • testImplementation("org.gebish:geb-spock:2.1")testImplementation("org.gebish:geb-spock:2.3.1")

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

src/main/java/ksbysample/webapp/bootnpmgeb/config/ApplicationConfig.java の以下の点も変更します。

    @Bean
    public Validator mvcValidator() {
        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
        localValidatorFactoryBean.setValidationMessageSource(this.messageSource);
        return localValidatorFactoryBean;
    }
  • public Validator mvcValidator()public Validator validator() に変更します。

clean タスク実行 → Rebuild Project 実行 → build タスク実行をしてみると、テストが大量に失敗しました。

f:id:ksby:20190414110553p:plain (.....途中省略.....) f:id:ksby:20190414110700p:plain

エラーの原因を調べるために Project Tool Window で src/test/groovy/ksbysample でコンテキストメニューを表示して「Run 'Tests in 'ksbysample''」を選択してテストを実行してみると以下のエラーメッセージが出ていました。Spring Session の AutoConfiguration クラス(org.springframework.boot.autoconfigure.session.JdbcSessionConfiguration$SpringBootJdbcHttpSessionConfiguration)で定義されている sessionEventHttpSessionListenerAdapter Bean が原因で BeanDefinitionOverrideException が発生しているとのこと。

  • Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'sessionEventHttpSessionListenerAdapter' defined in class path resource [org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration$SpringBootJdbcHttpSessionConfiguration.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.session.JdbcSessionConfiguration$SpringBootJdbcHttpSessionConfiguration; factoryMethodName=sessionEventHttpSessionListenerAdapter; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/session/JdbcSessionConfiguration$SpringBootJdbcHttpSessionConfiguration.class]] for bean 'sessionEventHttpSessionListenerAdapter': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration; factoryMethodName=sessionEventHttpSessionListenerAdapter; initMethodName=null; destroyMethodName=(inferred); defined in org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration] bound.

自分で定義していない Bean の override 定義はさすがに解消しようがないので Spring Boot 2.1 Release Notes - Bean Overriding に記載されている spring.main.allow-bean-definition-overriding=true の設定を application.properties に記述することにします。application.properties の内容は以下のようになります。

doma.dialect=org.seasar.doma.jdbc.dialect.H2Dialect

management.endpoints.web.exposure.include=health,info,loggers,shutdown,threaddump
management.endpoint.shutdown.enabled=true

spring.datasource.hikari.jdbc-url=jdbc:h2:mem:bootnpmgebdb
spring.datasource.hikari.username=sa
spring.datasource.hikari.password=
spring.datasource.hikari.driver-class-name=org.h2.Driver
spring.datasource.hikari.leak-detection-threshold=5000
spring.datasource.hikari.register-mbeans=true

spring.freemarker.cache=true
spring.freemarker.settings.number_format=computer
spring.freemarker.charset=UTF-8
spring.freemarker.enabled=false
spring.freemarker.prefer-file-system-access=false

spring.main.allow-bean-definition-overriding=true

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

spring.thymeleaf.mode=HTML

logging.level.root=INFO
logging.level.org.seasar.doma=ERROR

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

f:id:ksby:20190414114525p:plain

Tomcat を手動起動してから gebTest タスクを実行すると、こちらも BUILD SUCCESSFUL のメッセージが出力されました。これまで gebTest タスクの時は gradle-processes plugin で Tomcat自動起動・停止させていましたが、なくなると意外に不便ですね。。。

f:id:ksby:20190414115839p:plain

Headless モードを解除してブラウザを表示させて gebTest タスクを実行してみましたが、画面の表示等も特に問題はありませんでした。

履歴

2019/04/14
初版発行。