かんがるーさんの日記

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

Gradle で Multi-project を作成する ( その4 )( lib+webappx2編、Multi-project の設定ファイルと Spring Boot ベースの Web アプリケーション(メイン)のプロジェクトを作成する )

概要

記事一覧はこちらです。

Gradle で Multi-project を作成する ( その3 )( lib+cmdapp編、Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Gradle で Spring を使用しないライブラリ+Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)の Multi-project を作成します。
    • 2回に分けて書きます。
    • Spring を使用しないライブラリは lib+cmdapp 編で作成した sample-lib プロジェクトをそのままコピーして利用します。
    • Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)は新規に作成します。

参照したサイト・書籍

目次

  1. 方針
  2. gradle-multiprj-lib-webapp2 ディレクトリを作成する
  3. gradle-multiprj-lib-cmdapp プロジェクトからファイルをコピーする
  4. IntelliJ IDEA で gradle-multiprj-lib-webapp2 プロジェクトをオープンする
  5. clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う
  6. Spring Boot ベースの Web アプリケーション(メイン)のプロジェクトを作成する
    1. IntelliJ IDEA で sample-webapp プロジェクトを作成する
    2. sample-webapp プロジェクトから不要なファイルを削除する
    3. settings.gradle に sample-webapp プロジェクトの include 文を追加する
    4. gradle-multiprj-lib-webapp2 プロジェクトの build.gradle にサブプロジェクトの Web アプリケーション共通の設定を追加し、sample-webapp プロジェクトの build.gradle を削除する
    5. SampleController クラスを新規作成して仮実装する
  7. 続く。。。

手順

方針

gradle-multiprj-lib-webapp2
├ sample-lib    <-- Spring を使用しないライブラリの Project
├ sample-stubapp    <-- Spring Boot ベースの Web アプリケーション(スタブ)の Project
└ sample-webapp    <-- Spring Boot ベースの Web アプリケーション(メイン)の Project
  • Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)の Project では Profile は作成しません。
  • テスティングフレームワークは全ての Project で JUnit 5 と Spock を使用できるようにします。
  • checkstyle, spotbugs, pmd, error-prone は今回は導入しません。
  • Spring Boot ベースの Web アプリケーション(メイン)では 8080番ポートを、Spring Boot ベースの Web アプリケーション(スタブ)では 9080番ポートを使用します。
  • Web アプリケーションが2つあるので、
    • build.gradle の共通の設定は各サブプロジェクトの build.gradle ではなく gradle-multiprj-lib-webapp2 の build.gradle に記述します。
    • IntelliJ IDEA の Run Dashboard から Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)を起動できるようにします。

gradle-multiprj-lib-webapp2 ディレクトリを作成する

ksby/ksbysample-boot-miscellaneous の repository を checkout している D:\project-springboot\ksbysample-boot-miscellaneous の下に gradle-multiprj-lib-webapp2 ディレクトリを作成します。

f:id:ksby:20190421091351p:plain

gradle-multiprj-lib-cmdapp プロジェクトからファイルをコピーする

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-cmdapp\ から以下のファイルをコピーします。

settings.gradle は以下の内容に変更します。

rootProject.name = 'gradle-multiprj-lib-webapp2'
include 'sample-lib'

コピー後、コマンドプロンプトから gradlew wrapper コマンドを実行します。

f:id:ksby:20190421092716p:plain

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-webapp2\ の下には以下のディレクトリ・ファイルがある状態になります。

f:id:ksby:20190421092840p:plain

IntelliJ IDEA で gradle-multiprj-lib-webapp2 プロジェクトをオープンする

gradle-multiprj-lib-webapp2 プロジェクトをオープンします。

f:id:ksby:20190421093232p:plain

オープン後 Project Tool Window は以下のようになり、

f:id:ksby:20190421093449p:plain

Gradle Tool Window は以下のようになります。

f:id:ksby:20190421094634p:plain

gradle-multiprj-lib-cmdapp プロジェクトの時は gradle-multiprj-lib-cmdapp(root) と表示されていたのですが、今回は Tasks と表示されていますね。。。 Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新しても変わりませんでした。

gradle-multiprj-lib-cmdapp プロジェクトをオープンしてみるとこちらも Tasks に変わっていました。どうも IntelliJ IDEA を 2019.1 にバージョンアップしたのが原因のようです。

f:id:ksby:20190421095118p:plain

※Project SDK は default の設定で JDK 11 を使うように設定済なので、今回は変更の手順は書きません。

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う

ここまでで build タスクが正常に終了するか確認します。clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190421095554p:plain

sample-lib/build/libs の下に sample-lib-1.0.0-RELEASE.jar も生成されており、問題ないようです。

f:id:ksby:20190421100521p:plain

Spring Boot ベースの Web アプリケーション(メイン)のプロジェクトを作成する

IntelliJ IDEA で sample-webapp プロジェクトを作成する

IntelliJ IDEA から Spring Initializr を利用して Spring Boot ベースの Web アプリケーションのプロジェクトを作成します。

f:id:ksby:20190421105255p:plain f:id:ksby:20190421154449p:plain f:id:ksby:20190421105540p:plain f:id:ksby:20190421105611p:plain ※DevTools と Web の2つをチェックします。

f:id:ksby:20190421105709p:plain f:id:ksby:20190421105820p:plain

作成後 IntelliJ IDEA のウィンドウが開きますが、何もせずに閉じます。

sample-webapp プロジェクトから不要なファイルを削除する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-webapp2\sample-webapp\ の下には以下のディレクトリ・ファイルがありますが、

f:id:ksby:20190421111036p:plain

src ディレクトリと build.gradle 以外を削除します。削除すると以下の状態になります。

f:id:ksby:20190421111404p:plain

settings.gradle に sample-webapp プロジェクトの include 文を追加する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-webapp2 の下の settings.gradle に include 'sample-webapp' を追加します。

rootProject.name = 'gradle-multiprj-lib-webapp2'
include 'sample-lib'
include 'sample-webapp'

追加後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると sample-webappIntelliJ IDEA 209.1 から左側に : が付かなくなったようです)が追加されます。

f:id:ksby:20190421150647p:plain

また sample-webapp 起動用の Run/Debug Configuration も自動で追加されます。

f:id:ksby:20190421162742p:plain

gradle-multiprj-lib-webapp2 プロジェクトの build.gradle にサブプロジェクトの Web アプリケーション共通の設定を追加し、sample-webapp プロジェクトの build.gradle を削除する

gradle-multiprj-lib-webapp2 プロジェクトの build.gradle を以下のように変更します。今回は Spring Boot ベースの Web アプリケーションを2つ作成するので、共通の設定は各サブプロジェクトの build.gradle に記述するのではなく gradle-multiprj-lib-webapp2 の build.gradle に記述するようにします。

buildscript {
    repositories {
        mavenCentral()
        maven { url "https://plugins.gradle.org/m2/" }
        maven { url "https://repo.spring.io/release/" }
    }
    dependencies {
        classpath "io.spring.gradle:dependency-management-plugin:1.0.7.RELEASE"
        classpath "org.springframework.boot:spring-boot-gradle-plugin:2.1.4.RELEASE"
    }
}

allprojects {
    repositories {
        mavenCentral()
    }
}

subprojects {
    group "ksby.ksbysample-boot-miscellaneous"
    version "1.0.0-RELEASE"

    apply plugin: "java"
    apply plugin: "groovy"
    apply plugin: "io.spring.dependency-management"

    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11

    [compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8"
    [compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"]

    dependencyManagement {
        imports {
            mavenBom("org.junit:junit-bom:5.4.2")
        }
    }

    dependencies {
        def assertjVersion = "3.12.2"
        def spockVersion = "1.3-groovy-2.5"

        // for Spock
        testImplementation("org.spockframework:spock-core:${spockVersion}")
        testImplementation("org.spockframework:spock-spring:${spockVersion}")

        // for JUnit 5 + AssertJ
        // junit-jupiter で junit-jupiter-api, junit-jupiter-params, junit-jupiter-engine の3つが依存関係に追加される
        testCompile("org.junit.jupiter:junit-jupiter")
        testRuntime("org.junit.platform:junit-platform-launcher")
        testImplementation("org.assertj:assertj-core:${assertjVersion}")
    }

    def jvmArgsDefault = [
            "-ea",
            "-Dfile.encoding=UTF-8",
            "-Dsun.nio.cs.map=x-windows-iso2022jp/ISO-2022-JP"
    ]
    def jvmArgsAddOpens = [
            "--add-opens=java.base/java.io=ALL-UNNAMED",
            "--add-opens=java.base/java.lang=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.ref=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
            "--add-opens=java.base/java.net=ALL-UNNAMED",
            "--add-opens=java.base/java.security=ALL-UNNAMED",
            "--add-opens=java.base/java.util=ALL-UNNAMED"
    ]
    def printTestCount = { desc, result ->
        if (!desc.parent) { // will match the outermost suite
            println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
        }
    }

    task testJUnit4AndSpock(type: Test) {
        jvmArgs = jvmArgsDefault +
                jvmArgsAddOpens

        testLogging {
            afterSuite printTestCount
        }
    }
    test.dependsOn testJUnit4AndSpock
    test {
        jvmArgs = jvmArgsDefault +
                jvmArgsAddOpens

        // for JUnit 5
        useJUnitPlatform()

        testLogging {
            afterSuite printTestCount
        }
    }
}

configure(subprojects.findAll { it.name ==~ /^(sample-webapp)$/ }) {
    apply plugin: "org.springframework.boot"

    dependencyManagement {
        imports {
            mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
        }
    }

    dependencies {
        implementation("org.springframework.boot:spring-boot-starter-web")
        runtimeOnly("org.springframework.boot:spring-boot-devtools")
        testImplementation("org.springframework.boot:spring-boot-starter-test")
    }
}
  • buildscript の以下の点を変更します。
    • repositories に maven { url "https://repo.spring.io/release/" } を追加します。
    • dependencies に classpath "org.springframework.boot:spring-boot-gradle-plugin:2.1.4.RELEASE" を追加します。
  • configure(subprojects.findAll { it.name ==~ /^(sample-webapp)$/ }) { ... } の設定を追加します。

sample-webapp プロジェクトの build.gradle に残す設定はないのでファイルを削除します。

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

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

f:id:ksby:20190421163648p:plain

Project Tool Window を見ると以下のディレクトリ構成になっています。sample-webapp/build/libs の下に sample-webapp-1.0.0-RELEASE.jar が生成されています。

f:id:ksby:20190421165042p:plain

SampleController クラスを新規作成して仮実装する

Controller クラスが1つもないので /sample にアクセスしたら "sample-webapp" の文字を返す SampleController クラスを作成します。現時点では仮実装で、sample-stubapp を作成したら、sample-stubapp 内に実装する WebAPI を呼び出すように変更します。

sample-webapp/src/main/java/ksbysample/webapp/samplewebapp/SampleController.java を新規作成し、以下の内容を記述します。

package ksbysample.webapp.samplewebapp;

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

@Controller
@RequestMapping("/sample")
public class SampleController {

    @RequestMapping
    @ResponseBody
    public String index() {
        return "sample-webapp";
    }

}

Rebuild Project してエラーが出ないことを確認した後、sample-webapp の Tomcat を起動します。

f:id:ksby:20190421170027p:plain f:id:ksby:20190421170133p:plain

http://localhost:8080/sample にアクセスして "sample-webapp" の文字が出力されることを確認します。

f:id:ksby:20190421170325p:plain

確認後 Tomcat を停止します。

続く。。。

次回は sample-stubapp プロジェクト(こちらが sample-lib の StrNumUtils クラスを呼び出します)を作成した後、sample-webapp の SampleController クラスを本実装して Multi-project を完成させます。

履歴

2019/04/21
初版発行。

AdoptOpenJDK を 11.0.2+9 → 11.0.3+7 へ、IntelliJ IDEA を 2018.3.6 → 2019.1.1 へバージョンアップ

AdoptOpenJDK を 11.0.2+9 → 11.0.3+7 へバージョンアップする

※ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。

  1. https://adoptopenjdk.net/?variant=openjdk11&jvmVariant=hotspot を見ると 11.0.3+7 がダウンロードできるようになっていましたので、11.0.3+7 へバージョンアップします。

    f:id:ksby:20190420203120p:plain

  2. OpenJDK11U-jdk_x64_windows_hotspot_11.0.3_7.msi をダウンロードして D:\Java\jdk1.8.0_202 へインストールした後、環境変数 JAVA_HOME のパスを D:\Java\jdk-11.0.3+7 へ変更します。

    コマンドプロンプトから java -version を実行し、11.0.3 に変更されていることを確認します。

    f:id:ksby:20190420204951p:plain

  3. IntelliJ IDEA を再起動した後、プロジェクトで使用する JDK を 11.0.3+7 へ変更します。

  4. 開いているプロジェクトを閉じて「Welcome to IntelliJ IDEA」ダイアログを表示します。

  5. ダイアログ下部の「Configure」-「Project Defaults」-「Project Structure」を選択します。

    f:id:ksby:20190420205826p:plain

  6. 「Default Project Structure」ダイアログが表示されます。画面左側で「Project Settings」-「Project」を選択後、画面右側の「Project SDK」の「New...」ボタンをクリックし、表示されるメニューから「JDK」を選択します。

    f:id:ksby:20190420210014p:plain

  7. 「Select Home Directory for JDK」ダイアログが表示されます。D:\Java\jdk-11.0.3+7 を選択した後、「OK」ボタンをクリックします。

    f:id:ksby:20190420210123p:plain

  8. 「Default Project Structure」ダイアログに戻るので、今度は「Project SDK」の「Edit」ボタンをクリックします。

    f:id:ksby:20190420210241p:plain

  9. 画面左側で「Platform Settings」-「SDKs」が選択された状態になるので、画面右上の入力フィールドで "11" → "11.0.3+7" へ変更します。

    f:id:ksby:20190420210435p:plain

  10. 次に中央のリストから「11.0.2+9」を選択した後、リストの上の「-」ボタンをクリックして削除します。

    f:id:ksby:20190420210645p:plain

  11. 「OK」ボタンをクリックして「Default Project Structure」ダイアログを閉じます。

  12. 「Welcome to IntelliJ IDEA」ダイアログに戻ったら、ksbysample-webapp-lending プロジェクトを開きます。

  13. IntelliJ IDEA のメイン画面が開いたら、メニューから「File」-「Project Structure...」を選択します。

  14. 「Project Structure」ダイアログが表示されます。以下の画像の状態になっているので、

    f:id:ksby:20190420210927p:plain

    「Project SDK」を選択し直します。「Project SDK」を「11.0.3+7」に変更すると「Project language level」も自動で「SDK default (11 - Local variable syntax for lambda pa」が選択されました。

    f:id:ksby:20190420211210p:plain

  15. 「OK」ボタンをクリックして「Project Structure」ダイアログを閉じます。

  16. メイン画面に戻ると画面右下に「Indexing...」の表示が出るので、終了するまで待ちます。

    f:id:ksby:20190420211312p:plain

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

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

    f:id:ksby:20190420212245p:plain

  19. Project Tool Window で src/test/groovy/ksbysample、src/test/java/ksbysample でコンテキストメニューを表示して「Run 'Tests in 'ksbysample'' with Coverage」を選択し、テストが全て成功することを確認します。

    f:id:ksby:20190420213038p:plain f:id:ksby:20190420213501p:plain

  20. 特に問題は発生しませんでした。11.0.3+7 で開発を進めます。

IntelliJ IDEA を 2018.3.6 → 2019.1.1 へバージョンアップする

IntelliJ IDEA の 2019.1.1 がリリースされているのでバージョンアップします。

※ksbysample-webapp-lending プロジェクトを開いた状態でバージョンアップしています。

  1. IntelliJ IDEA のメインメニューから「Help」-「Check for Updates...」を選択します。

  2. IDE and Plugin Updates」ダイアログが表示されます。左下に「Update and Restart」ボタンが表示されていますので、「Update and Restart」ボタンをクリックします。

    f:id:ksby:20190420223100p:plain

  3. Plugin の update も表示されました。このまま「Update and Restart」ボタンをクリックします。

    f:id:ksby:20190420223214p:plain

  4. Patch がダウンロードされて IntelliJ IDEA が再起動します。

  5. メジャーバージョンアップなので起動時に「Import IntelliJ IDEA Settings From...」ダイアログが表示されます。「Previous version」を選択した状態で「OK」ボタンをクリックします。

    f:id:ksby:20190420224212p:plain

  6. IntelliJ IDEA が起動すると画面下部に「Indexing…」のメッセージが表示されますので、終了するまで待機します。

    f:id:ksby:20190420224826p:plain

  7. IntelliJ IDEA のメインメニューから「Help」-「About」を選択し、2019.1.1 へバージョンアップされていることを確認します。

  8. Gradle Tool Window を見ると今回のバージョンからまた何も表示されなくなっていました。

    f:id:ksby:20190420225049p:plain

    左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると、いつものツリーが表示されました。

    f:id:ksby:20190420225209p:plain

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

    f:id:ksby:20190420231747p:plain

  10. Project Tool Window で src/test/groovy/ksbysample、src/test/java/ksbysample でコンテキストメニューを表示して「Run 'Tests in 'ksbysample'' with Coverage」を選択し、テストが全て成功することを確認します。

    f:id:ksby:20190420232213p:plain f:id:ksby:20190420232631p:plain

  11. 最後に C:\Users\root.IntelliJIdea2018.3 を削除します。

Gradle で Multi-project を作成する ( その3 )( lib+cmdapp編、Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成する )

概要

記事一覧はこちらです。

Gradle で Multi-project を作成する ( その2 )( lib+cmdapp編、Multi-project の設定ファイルと Spring を使用しないライブラリのプロジェクトを作成する ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Gradle で Spring を使用しないライブラリ+Spring Boot ベースのコマンドラインアプリケーションの Multi-project を作成します。
    • 今回は Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成して Multi-project を完成させます。

参照したサイト・書籍

目次

  1. Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成する
    1. IntelliJ IDEA で sample-cmdapp プロジェクトを作成する
    2. .gitignore に設定を追加する
    3. sample-cmdapp プロジェクトから不要なファイルを削除する
    4. settings.gradle に sample-cmdapp プロジェクトの include 文を追加する
    5. sample-cmdapp プロジェクトの build.gradle から不要な記述を削除し、sample-lib プロジェクトへの依存関係を追加する
    6. SampleCmdappApplication クラスに CommandLineRunner インターフェースを実装する
  2. clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う
  3. java -jar sample-cmdapp-1.0.0-RELEASE.jar コマンドを実行してみる
  4. まとめ

手順

Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成する

IntelliJ IDEA で sample-cmdapp プロジェクトを作成する

IntelliJ IDEA から Spring Initializr を利用して Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成します。

f:id:ksby:20190420084840p:plain f:id:ksby:20190420085057p:plain f:id:ksby:20190420085206p:plain ※シンプルなコマンドアプリケーションなので何もチェックしません。

f:id:ksby:20190420085319p:plain

作成後 IntelliJ IDEA のウィンドウが開きますが、何もせずに閉じます。

.gitignore に設定を追加する

sample-cmdapp プロジェクトの下に作成された .gitignore から ### STS ###### IntelliJ IDEA ###### NetBeans ###### VS Code ### の設定をコピーして、ルートディレクトリの .gitignore に追加します。

# Ignore Gradle project-specific cache directory
.gradle

# Ignore Gradle build output directory
build

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
/out/

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

### VS Code ###
.vscode/

sample-cmdapp プロジェクトから不要なファイルを削除する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-cmdapp\sample-cmdapp\ の下には以下のディレクトリ・ファイルがありますが、

f:id:ksby:20190420085717p:plain

src ディレクトリと build.gradle 以外は不要なので削除します。削除すると以下の状態になります。

f:id:ksby:20190420090738p:plain

settings.gradle に sample-cmdapp プロジェクトの include 文を追加する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-cmdapp の下の settings.gradle に include 'sample-cmdapp' を追加します。

rootProject.name = 'gradle-multiprj-lib-cmdapp'
include 'sample-lib'
include 'sample-cmdapp'

追加後、Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すると :sample-cmdapp が追加されます。

f:id:ksby:20190420091403p:plain

sample-cmdapp プロジェクトの build.gradle から不要な記述を削除し、sample-lib プロジェクトへの依存関係を追加する

sample-cmdapp プロジェクトの build.gradle を以下の内容に変更します。

plugins {
    id "org.springframework.boot" version "2.1.4.RELEASE"
}

dependencyManagement {
    imports {
        mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
    }
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter")
    testImplementation("org.springframework.boot:spring-boot-starter-test")

    implementation project(":sample-lib")
}

sample-cmdapp の設定はプロジェクトのルートディレクトリにある build.gradle に project(':sample-cmdapp') { ... } で記述することも可能ですが、その場合 plugins { ... } が使えなくなるので sample-cmdapp の下に build.gradle を残してこの中に設定を記述することにします。

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

SampleCmdappApplication クラスに CommandLineRunner インターフェースを実装する

sample-cmdapp/src/main/java/ksbysample/cmdapp/samplecmdapp/SampleCmdappApplication.java を以下のように変更します。

package ksbysample.cmdapp.samplecmdapp;

import ksbysample.lib.samplelib.StrNumUtils;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SampleCmdappApplication implements CommandLineRunner {

    public static void main(String[] args) {
        SpringApplication.run(SampleCmdappApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println("★★★ " + StrNumUtils.plus("1", "2"));
    }

}

クラスに implements CommandLineRunner を追加し run メソッドを実装します。run メソッド内で sample-lib プロジェクトの StrNumUtils クラスを呼び出すようにします。

次にテストクラスを作成します。Spring Initializr でプロジェクトを作成したので sample-cmdapp/src/test/java/ksbysample/cmdapp/samplecmdapp/SampleCmdappApplicationTests.java が作成されていますが、このテストはファイル毎削除して Spock で作り直します。

f:id:ksby:20190420093746p:plain f:id:ksby:20190420093816p:plain

cmdapp/src/test/groovy/ksbysample/cmdapp/samplecmdapp/SampleCmdappApplicationTest.groovy が新規作成されますので、以下の内容を記述します。

package ksbysample.cmdapp.samplecmdapp

import spock.lang.Specification

class SampleCmdappApplicationTest extends Specification {

    def "sample-cmdapp を実行すると'★★★ 3'が出力される"() {
        setup:
        def buf = new ByteArrayOutputStream(1024)
        System.out = new PrintStream(buf)

        when:
        SampleCmdappApplication.main()

        then:
        buf.toString().contains("★★★ 3")
    }

}

ここまでで以下のディレクトリ構成になります。

f:id:ksby:20190420101420p:plain

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う

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

f:id:ksby:20190420094611p:plain

各プロジェクトの build/libs ディレクトリの下に sample-cmdapp-1.0.0-RELEASE.jar、sample-lib-1.0.0-RELEASE.jar が作成されています。

f:id:ksby:20190420101620p:plain

sample-cmdapp-1.0.0-RELEASE.jar を zip ソフトで開いてみると BOOT-INF/lib の下に sample-lib-1.0.0-RELEASE.jar が入っていることも確認できます。

f:id:ksby:20190420101947p:plain

java -jar sample-cmdapp-1.0.0-RELEASE.jar コマンドを実行してみる

Multi-project で作成した sample-cmdapp-1.0.0-RELEASE.jar が問題なく動作することをコマンドラインから確認してみます。

コマンドラインから java -jar sample-cmdapp-1.0.0-RELEASE.jar コマンドを実行すると "★★★ 3" が出力されることが確認できました。

f:id:ksby:20190420102448p:plain

まとめ

  • Multi-project ではルートディレクトリの build.gradle の subprojects { ... } に共通の設定を記述する。plugin の設定だけ plugins { ... } が使えないので apply plugin: "..." で記述すること。
  • Spring を使用しないライブラリのサブプロジェクトを作成したい時はサブプロジェクトのディレクトリを作成した後、settings.gradle に include '<サブプロジェクトのディレクトリ名>' を書いてから IntelliJ IDEA の Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すればよい(おそらくコマンドだと gradle wrapper だと思われる)。
  • Spring Boot ベースのコマンドラインアプリケーションのサブプロジェクトを作成したい時は Spring Initializr でサブプロジェクトを作成してから src, build.gradle 以外を削除し、settings.gradle に include '<サブプロジェクトのディレクトリ名>' を書いてから IntelliJ IDEA の Gradle Tool Window の左上にある「Refresh all Gradle projects」ボタンをクリックして更新すればよい。
  • サブプロジェクトの build.gradle の設定はサブプロジェクトのディレクトリの下に build.gradle を置いてその中に記述するか、ルートディレクトリの build.gradle に project(':<サブプロジェクトのディレクトリ名>') { ... } の形式で記述する。

Multi-project を初めて作ってみましたが、Gradle Guides の Creating Multi-project Builds に基本は書かれているので、これを読めば何とか作れるものですね。

履歴

2019/04/20
初版発行。

Gradle で Multi-project を作成する ( その2 )( lib+cmdapp編、Multi-project の設定ファイルと Spring を使用しないライブラリのプロジェクトを作成する )

概要

記事一覧はこちらです。

Gradle で Multi-project を作成する ( その1 )( 概要 ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Gradle で Spring を使用しないライブラリ+Spring Boot ベースのコマンドラインアプリケーションの Multi-project を作成します。
    • 2回に分けて書きます。
    • 今回は Multi-project のための各種設定ファイルとSpring を使用しないライブラリのプロジェクトを作成します。

参照したサイト・書籍

  1. Gradle Guides - Creating Multi-project Builds
    https://guides.gradle.org/creating-multi-project-builds/

  2. The Gradle Wrapper
    https://docs.gradle.org/5.0/userguide/gradle_wrapper.html#sec:wrapper_generation

  3. Authoring Multi-Project Builds
    https://docs.gradle.org/current/userguide/multi_project_builds.html

目次

  1. 方針
  2. gradle-multiprj-lib-cmdapp ディレクトリを作成する
  3. Spring Initializr で作成したプロジェクトから Gradle Wrapper のファイルをコピーする
  4. Gradle を最新バージョンにする
  5. gradlew init を実行する
  6. build.gradle に subproject 共通の設定を追加する
  7. Spring を使用しないライブラリのプロジェクトを作成する
    1. sample-lib ディレクトリを作成する
    2. settings.gradle に sample-lib プロジェクトの include 文を追加する
  8. IntelliJ IDEA で gradle-multiprj-lib-cmdapp プロジェクトをオープンする
  9. Project SDK を JDK 11 に設定する
  10. StrNumUtils クラスを追加する
  11. clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う
  12. 続く。。。

手順

方針

gradle-multiprj-lib-cmdapp
├ sample-cmdapp    <-- Spring Boot ベースのコマンドラインアプリケーションの Project
└ sample-lib    <-- Spring を使用しないライブラリの Project
  • Spring Boot ベースのコマンドラインアプリケーションの Project では Profile は作成しません。
  • テスティングフレームワークは全ての Project で JUnit 5 と Spock を使用できるようにします。
  • checkstyle, spotbugs, pmd, error-prone は今回は導入しません。

gradle-multiprj-lib-cmdapp ディレクトリを作成する

ksby/ksbysample-boot-miscellaneous の repository を checkout している D:\project-springboot\ksbysample-boot-miscellaneous の下に gradle-multiprj-lib-cmdapp ディレクトリを作成します。

f:id:ksby:20190418224918p:plain

Spring Initializr で作成したプロジェクトから Gradle Wrapper のファイルをコピーする

IntelliJ IDEA で Spring Initializr の新規 Gradle プロジェクトを作成します。

f:id:ksby:20190418225523p:plain

ここから以下のディレクトリ・ファイルを D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-cmdapp の下にコピーします。

f:id:ksby:20190418225827p:plain

Gradle を最新バージョンにする

コピーした gradle/wrapper/gradle-wrapper.properties を見ると Gradle のバージョンは 5.2.1 だったのですが、https://gradle.org/releases/ を見ると Gradle の最新バージョンは 5.4 なので 5.4 にバージョンアップします。

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

f:id:ksby:20190420003041p:plain

gradle/wrapper/gradle-wrapper.properties を見ると 5.4 になっています。

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

gradlew init を実行する

gradlew init コマンドを実行します。選択肢は 1: basic1: groovy を選択し、Project name は何も入力せずに Enter キーを押します。

f:id:ksby:20190418231310p:plain

gradle-multiprj-lib-cmdapp ディレクトリの下は以下のようになり、

f:id:ksby:20190418231535p:plain

生成された .gitignore、build.gradle、settings.gradle は以下の内容になっています。

■.gitignore

# Ignore Gradle project-specific cache directory
.gradle

# Ignore Gradle build output directory
build

■build.gradle

/*
 * This file was generated by the Gradle 'init' task.
 *
 * This is a general purpose Gradle build.
 * Learn how to create Gradle builds at https://guides.gradle.org/creating-new-gradle-builds/
 */

■settings.gradle

/*
 * This file was generated by the Gradle 'init' task.
 *
 * The settings file is used to specify which projects to include in your build.
 *
 * Detailed information about configuring a multi-project build in Gradle can be found
 * in the user manual at https://docs.gradle.org/5.4/userguide/multi_project_builds.html
 */

rootProject.name = 'gradle-multiprj-lib-cmdapp'

build.gradle に subproject 共通の設定を追加する

build.gradle に subproject 共通の設定を追加します。以下の内容に変更します。

buildscript {
    repositories {
        mavenCentral()
        maven { url "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath "io.spring.gradle:dependency-management-plugin:1.0.7.RELEASE"
    }
}

allprojects {
    repositories {
        mavenCentral()
    }
}

subprojects {
    group "ksby.ksbysample-boot-miscellaneous"
    version "1.0.0-RELEASE"

    apply plugin: "java"
    apply plugin: "groovy"
    apply plugin: "io.spring.dependency-management"

    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11

    [compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8"
    [compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"]

    dependencyManagement {
        imports {
            mavenBom("org.junit:junit-bom:5.4.2")
        }
    }

    dependencies {
        def assertjVersion = "3.12.2"
        def spockVersion = "1.3-groovy-2.5"

        // for Spock
        testImplementation("org.spockframework:spock-core:${spockVersion}")
        testImplementation("org.spockframework:spock-spring:${spockVersion}")

        // for JUnit 5 + AssertJ
        // junit-jupiter で junit-jupiter-api, junit-jupiter-params, junit-jupiter-engine の3つが依存関係に追加される
        testCompile("org.junit.jupiter:junit-jupiter")
        testRuntime("org.junit.platform:junit-platform-launcher")
        testImplementation("org.assertj:assertj-core:${assertjVersion}")
    }

    def jvmArgsDefault = [
            "-ea",
            "-Dfile.encoding=UTF-8",
            "-Dsun.nio.cs.map=x-windows-iso2022jp/ISO-2022-JP"
    ]
    def jvmArgsAddOpens = [
            "--add-opens=java.base/java.io=ALL-UNNAMED",
            "--add-opens=java.base/java.lang=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.ref=ALL-UNNAMED",
            "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
            "--add-opens=java.base/java.net=ALL-UNNAMED",
            "--add-opens=java.base/java.security=ALL-UNNAMED",
            "--add-opens=java.base/java.util=ALL-UNNAMED"
    ]
    def printTestCount = { desc, result ->
        if (!desc.parent) { // will match the outermost suite
            println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
        }
    }

    task testJUnit4AndSpock(type: Test) {
        jvmArgs = jvmArgsDefault +
                jvmArgsAddOpens

        testLogging {
            afterSuite printTestCount
        }
    }
    test.dependsOn testJUnit4AndSpock
    test {
        jvmArgs = jvmArgsDefault +
                jvmArgsAddOpens

        // for JUnit 5
        useJUnitPlatform()

        testLogging {
            afterSuite printTestCount
        }
    }
}
  • subprojects { ... } 内で subproject 共通の Gradle plugin を記述する時に plugins { ... } は使えません。apply plugin: "..." で記述します。

Spring を使用しないライブラリのプロジェクトを作成する

sample-lib ディレクトリを作成する

gradle-multiprj-lib-cmdapp ディレクトリの下に sample-lib ディレクトリを作成します。

settings.gradle に sample-lib プロジェクトの include 文を追加する

D:\project-springboot\ksbysample-boot-miscellaneous\gradle-multiprj-lib-cmdapp の下の settings.gradle に include 'sample-lib' を追加します。

rootProject.name = 'gradle-multiprj-lib-cmdapp'
include 'sample-lib'

IntelliJ IDEA で gradle-multiprj-lib-cmdapp プロジェクトをオープンする

gradle-multiprj-lib-cmdapp プロジェクトを以下の画像の手順でオープンします。

f:id:ksby:20190420073950p:plain f:id:ksby:20190420074054p:plain f:id:ksby:20190420074246p:plain

IntelliJ IDEA のメイン画面が表示されると Project Tool Window には以下のように表示されます。

f:id:ksby:20190420074626p:plain

Gradle Tool Window は以下のように表示されます。

f:id:ksby:20190420074748p:plain

Project SDKJDK 11 に設定する

IntelliJ IDEA のメインメニューから「File」-「Project Structure...」を選択し「Project Structure」ダイアログを表示し「Project SDK」で JDK 11 を、「Project language level」で「SDK default(11 - local variable syntax for lambda parameters)」を選択して「OK」ボタンをクリックします。

f:id:ksby:20190419072755p:plain

StrNumUtils クラスを追加する

sample-lib/src/main/java の下に ksbysample.lib.samplelib パッケージを作成し、その下に StrNumUtils.java を新規作成して以下の内容を記述します。

package ksbysample.lib.samplelib;

public class StrNumUtils {

    public static String plus(String v1, String v2) {
        return String.valueOf(Integer.parseInt(v1) + Integer.parseInt(v2));
    }

}

テストクラスも作成します。今回は JUnit 5 で作成します。

f:id:ksby:20190420075427p:plain f:id:ksby:20190420075505p:plain

src/test/java/ksbysample/lib/samplelib/StrNumUtilsTest.java が新規作成されるので、以下の内容を記述します。

package ksbysample.lib.samplelib;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class StrNumUtilsTest {

    @Test
    @DisplayName("plusメソッドのテスト")
    void plus() {
        assertThat(StrNumUtils.plus("1", "2")).isEqualTo("3");
    }

}

ここまでで以下のディレクトリ構成になります。

f:id:ksby:20190420080105p:plain

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行う

build タスクが正常に終了するか確認します。clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190420081113p:plain

sample-lib ディレクトリの下に build, out ディレクトリが作成されており、sample-lib/build/libs の下に sample-lib-1.0.0-RELEASE.jar が出力されていました。

f:id:ksby:20190420081359p:plain

ここまでは問題なさそうです。

続く。。。

次回は Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成して Multi-project を完成させます。

履歴

2019/04/20
初版発行。

Gradle で Multi-project を作成する ( その1 )( 概要 )

概要

記事一覧はこちらです。

  • Gradle の Multi-project を作成したことがないので、作成手順を覚えるために作成してみます。
  • 以下のパターンの Multi-project を作成してみる予定です。Spring Boot ベースのアプリケーションを最低1つ+ライブラリのプロジェクト(Spring ベースかは問わない)を最低1つ+何か加えたものという構成です。
    • Spring を使用しないライブラリ+Spring Boot ベースのコマンドラインアプリケーション
    • Spring を使用しないライブラリ+Spring Boot ベースの Web アプリケーション x 2(メインとスタブ)
    • Doma 2 の Entity、Dao を提供するライブラリ+Spring Boot ベースのコマンドラインアプリケーション+Spring Boot ベースの Web アプリケーション
  • 他にやりたいパターンが思い浮かんだら変えるかもしれません。
  • 作成した Multi-project は ksby/ksbysample-boot-miscellaneous の repository にコミットします。

履歴

2019/04/18
初版発行。

Gradle で Multi-project を作成する ( 大目次 )

  1. その1 ( 概要 )
  2. その2 ( lib+cmdapp編、Multi-project の設定ファイルと Spring を使用しないライブラリのプロジェクトを作成する )
  3. その3 ( lib+cmdapp編、Spring Boot ベースのコマンドラインアプリケーションのプロジェクトを作成する )
  4. その4 ( lib+webappx2編、Multi-project の設定ファイルと Spring Boot ベースの Web アプリケーション(メイン)のプロジェクトを作成する )
  5. その5 ( lib+webappx2編、Spring Boot ベースの Web アプリケーション(スタブ)のプロジェクトを作成する )
  6. その6 ( Multi-project は settings.gradle に include を書くだけでもよいのでは? )
  7. 番外編 ( Spring Actuator を利用してアプリ起動時にメールサーバに接続できない場合には起動を中断させる )
  8. その7 ( doma2lib+cmdapp+webapp編、Multi-project の設定ファイルと docker-compose.yml を作成する )
  9. その8 ( doma2lib+cmdapp+webapp編、doma2-lib プロジェクトを作成する )
  10. その9 ( doma2lib+cmdapp+webapp編、sample-cmdapp プロジェクトを作成する )
  11. その10 ( doma2lib+cmdapp+webapp編、sample-cmdapp プロジェクトを作成する2 )
  12. その11 ( doma2lib+cmdapp+webapp編、log4jdbc-log4j2 を導入してトランザクションが有効なことを確認する )
  13. その12 ( doma2lib+cmdapp+webapp編、sample-webapp プロジェクトを作成する )
  14. その13 ( doma2lib+cmdapp+webapp編、PropertiesLauncher を利用して doma2-lib の jar ファイルを外部に出す )
  15. その14 ( vuejs+springboot編、Multi-project のベースと backend-app プロジェクトを作成する )
  16. その15 ( vuejs+springboot編、frontend-app プロジェクトを作成する )
  17. 感想

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その83 )( Checkstyle を 8.11 → 8.19 へ、PMD を 6.6.0 → 6.13.0 へバージョンアップ+JUnit 5 の導入+ Oracle JDK 8u202 → AdoptOpenJDK 11.0.2+9 へ、error-prone を 2.3.1 → 2.3.3 へバージョンアップする)

概要

記事一覧はこちらです。

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

  • 今回の手順で確認できるのは以下の内容です。
    • Checkstyle を 8.11 → 8.19 へ、PMD を 6.6.0 → 6.13.0 へバージョンアップします。
    • JUnit 5 を使用できるようにします。このプロジェクトでは Spock+Geb でしかテストを書いていないので JUnit 5 は使える環境を整えるだけになります。
    • JDKOracle JDK 8u202 → AdoptOpenJDK 11.0.2+9 へ、error-prone を 2.3.1 → 2.3.3 へバージョンアップします。

参照したサイト・書籍

  1. https://github.com/apache/groovy/commit/92bd96fcdfe35e502987e1846715a08a45620db1

    • Groovy で --add-opens オプションを付ける時に参照しました。

目次

  1. Checkstyle を 8.11 → 8.19 へ、PMD を 6.6.0 → 6.13.0 へバージョンアップする
  2. JUnit 5 を導入する
  3. Oracle JDK 8u202 → AdoptOpenJDK 11.0.2+9 へ、error-prone を 2.3.1 → 2.3.3 へバージョンアップする
  4. testJUnit4AndSpock タスクで出る警告を解消する
  5. 失敗するテストの原因を調査・解消する
  6. compileTestGroovy タスクで出る警告を解消する。。。ことは出来ませんでした
  7. gebTest タスクが成功するようにする

手順

Checkstyle を 8.11 → 8.19 へ、PMD を 6.6.0 → 6.13.0 へバージョンアップする

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

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

..........

pmd {
    toolVersion = "6.13.0"
    sourceSets = [project.sourceSets.main]
    ignoreFailures = true
    consoleOutput = true
    ruleSetFiles = rootProject.files("/config/pmd/pmd-project-rulesets.xml")
    ruleSets = []
}
  • checkstyle block で toolVersion = "8.11"toolVersion = "8.19" に変更します。
  • pmd block で toolVersion = "6.6.0"toolVersion = "6.13.0" に変更します。

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

clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと、PMD で何件か警告が出ました。

f:id:ksby:20190414123438p:plain

  • D:\project-springboot\ksbysample-boot-miscellaneous\boot-npm-geb-sample\src\main\java\ksbysample\webapp\bootnpmgeb\Application.java:26: The constant name 'springProfiles' doesn't match '[A-Z][A-Z_0-9]*'
    • 定数名を SPRING_PROFILES に変更します。
  • D:\project-springboot\ksbysample-boot-miscellaneous\boot-npm-geb-sample\src\main\java\ksbysample\webapp\bootnpmgeb\aspect\logging\ControllerAndEventNameLogger.java:17: The constant name 'logger' doesn't match '[A-Z][A-Z_0-9]*'
  • D:\project-springboot\ksbysample-boot-miscellaneous\boot-npm-geb-sample\src\main\java\ksbysample\webapp\bootnpmgeb\aspect\logging\MethodLogger.java:20: The constant name 'logger' doesn't match '[A-Z][A-Z_0-9]*'
  • D:\project-springboot\ksbysample-boot-miscellaneous\boot-npm-geb-sample\src\main\java\ksbysample\webapp\bootnpmgeb\aspect\logging\RequestAndResponseLogger.java:34: The constant name 'logger' doesn't match '[A-Z][A-Z_0-9]*'

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

f:id:ksby:20190414131126p:plain

JUnit 5 を導入する

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

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

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

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

def jvmArgsForTask = [
        "-ea",
        "-Dfile.encoding=UTF-8",
        "-Dsun.nio.cs.map=x-windows-iso2022jp/ISO-2022-JP"
]
def printTestCount = { desc, result ->
    if (!desc.parent) { // will match the outermost suite
        println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
    }
}

bootRun {
    jvmArgs = jvmArgsForTask +
            ["-Dspring.profiles.active=develop"]
}

tasks.withType(Test) {
    jvmArgs = jvmArgsForTask +
            ["-Dspring.profiles.active=unittest"]
}
task testJUnit4AndSpock(type: Test) {
    // testJUnit4AndSpock タスクの jvmArgs は tasks.withType(Test) { ... } で定義している
    exclude "geb/**"

    testLogging {
        afterSuite printTestCount
    }
}
test.dependsOn testJUnit4AndSpock
test {
    // test タスクの jvmArgs は tasks.withType(Test) { ... } で定義している

    // for JUnit 5
    useJUnitPlatform()

    testLogging {
        afterSuite printTestCount
    }
}

..........

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

        testLogging {
            afterSuite printTestCount
        }
    }
}
task gebTest {
    dependsOn drivers.collect { tasks["${it}Test"] }
    enabled = false
}
  • dependencyManagement block の import block 内に mavenBom("org.junit:junit-bom:5.4.2") を追加します。
  • dependencies block に以下の2行を追加します。
    • testCompile("org.junit.jupiter:junit-jupiter")
    • testRuntime("org.junit.platform:junit-platform-launcher")
  • def jvmArgsForTask = [ ... ] を追加します。
  • def printTestCount = { ... } を追加します。
  • bootRun タスクの jvmArgs の設定を jvmArgsForTask 変数を利用したものに変更します。
  • tasks.withType(Test) { ... } の jvmArgs の設定を jvmArgsForTask 変数を利用したものに変更します。
  • task testJUnit4AndSpock(type: Test) { ... } を追加します。
  • test.dependsOn testJUnit4AndSpock を追加します。
  • test タスク内に以下の記述を追加します。
    • useJUnitPlatform()
    • testLogging { afterSuite printTestCount }
  • exclude "geb/**" の記述は test タスクから testJUnit4AndSpock タスクへ移動します。
  • drivers.each { driver -> task "${driver}Test"(type: Test) { ... } } 内に testLogging { afterSuite printTestCount } を追加します。

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

clean タスク実行 → Rebuild Project 実行 → build タスク実行をすると、テストは問題なく成功し BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190414144014p:plain

gebTest タスクも BUILD SUCCESSFUL のメッセージが出力されました。

f:id:ksby:20190414144720p:plain

Oracle JDK 8u202 → AdoptOpenJDK 11.0.2+9 へ、error-prone を 2.3.1 → 2.3.3 へバージョンアップする

IntelliJ IDEA のメインメニューから「File」-「Project Structure...」を選択して「Project Structure」ダイアログを開き、「Project SDK」で「11.0.2+9」を選択してから「OK」ボタンをクリックしてダイアログを閉じます。

f:id:ksby:20190414154450p:plain

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

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.7.1"
    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"
}

sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

..........

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

..........

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

    ..........

    // for Geb + Spock
    testImplementation("org.gebish:geb-spock:2.3.1") {
        exclude group: "org.codehaus.groovy", module: "groovy-all"
    }
    ..........

}

def jvmArgsForTask = [
        "-ea",
        "-Dfile.encoding=UTF-8",
        "-Dsun.nio.cs.map=x-windows-iso2022jp/ISO-2022-JP"
]
// JDK 11 に変更後、test タスク実行時に groovy と powermock が JDKの内部部分にアクセスするためにコードでリフレクションを使用
// していて WARNING が出るため、JVM の起動時オプションの --add-opens を指定して WARNING が出ないようにする
def jvmArgsAddOpens = [
        "--add-opens=java.base/java.io=ALL-UNNAMED",
        "--add-opens=java.base/java.lang=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.ref=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
        "--add-opens=java.base/java.net=ALL-UNNAMED",
        "--add-opens=java.base/java.security=ALL-UNNAMED",
        "--add-opens=java.base/java.util=ALL-UNNAMED",
        "--add-opens=java.base/java.util.stream=ALL-UNNAMED"
]
def printTestCount = { desc, result ->
    if (!desc.parent) { // will match the outermost suite
        println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
    }
}

bootRun {
    jvmArgs = jvmArgsForTask +
            jvmArgsAddOpens +
            ["-Dspring.profiles.active=develop"]
}

tasks.withType(Test) {
    jvmArgs = jvmArgsForTask +
            jvmArgsAddOpens +
            ["-Dspring.profiles.active=unittest"]
}
  • plugins block の以下の点を変更します。
    • id "net.ltgt.errorprone" version "0.0.14"id "net.ltgt.errorprone" version "0.7.1"
  • sourceCompatibility、targetCompatibility に指定する値を 1.8JavaVersion.VERSION_11 に変更します。
  • compileJava.options.compilerArgs += [ ... ] を削除します。
  • tasks.named("compileTestJava").configure { options.errorprone.enabled = false } を追加します。
  • dependencies block の以下の点を変更します。
    • def errorproneVersion = "2.3.1"def errorproneVersion = "2.3.3"
  • def jvmArgsAddOpens = [ ... ] を追加します。Spring Boot 2.0.x の Web アプリを 2.1.x へバージョンアップする ( その15 )( JDK を 8u202 → 11.0.2+9 に変更する ) で指定したものと同じものを指定しておきます。
  • bootRun { ... }tasks.withType(Test) { ... } 内の jvmArgs の設定に jvmArgsAddOpens + を追加します。
  • groovy も 2.5 にバージョンアップします。
    • dependencies block 内で def spockVersion = "1.3-groovy-2.4"def spockVersion = "1.3-groovy-2.5" に変更します。
    • testImplementation("org.gebish:geb-spock:2.3.1")testImplementation("org.gebish:geb-spock:2.3.1") { exclude group: "org.codehaus.groovy", module: "groovy-all" } に変更します。

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

IntelliJ IDEA のメインメニューから「Run」-「Edit Configurations...」を選択して「Run/Debug Configurations」ダイアログを開き、画面左側のツリーから「Templates」-「JUnit」を選択後、画面右側の「VM options」に build.gradle の def jvmArgsAddOpens = [ ... ] に記述したオプションを追加します。

f:id:ksby:20190414194725p:plain

また追加した結果 IntelliJ IDEA からテストを実行しようとすると Command line is too long. のエラーメッセージが表示されて実行できなくなるので、画面右側の「Shorten command line」で「JAR manifest」を選択します。

f:id:ksby:20190414195417p:plain

clean タスク実行 → Rebuild Project 実行 → build タスク実行して出力される以下のエラーメッセージを取り除きます。

  • エラー: An unhandled exception was thrown by the Error Prone static analysis plugin.
    • このエラーメッセージが出る箇所は PMD の @SuppressWarnings が付与されているので、@SuppressWarnings({"PMD.UnusedPrivateMethod"})@SuppressWarnings({"PMD.UnusedPrivateMethod", "UnusedMethod"}) に変更します。
  • 警告:[JavaTimeDefaultTimeZone] LocalDateTime.now() is not allowed because it silently uses the system default time-zone. You must pass an explicit time-zone (e.g., ZoneId.of("America/Los_Angeles")) to this method.
    • LocalDateTime.now()LocalDateTime.now(ZoneId.of("Asia/Tokyo")) に変更します。

ここまでやると以下の状態になります。

f:id:ksby:20190414200539p:plain f:id:ksby:20190414200639p:plain

  • compileTestGroovy タスクで警告が出る。
  • testJUnit4AndSpock タスクで警告が出る。
  • テストが1件失敗する。

testJUnit4AndSpock タスクで出る警告を解消する

出たのは以下3件のメッセージでした。

  • WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedConstructor$1 (file:/C:/Users/root/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.6/6936e700f0fb1b50bac0698ada4347a769d40199/groovy-2.5.6.jar) to constructor java.util.stream.Collectors()
  • WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedConstructor$1 (file:/C:/Users/root/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.6/6936e700f0fb1b50bac0698ada4347a769d40199/groovy-2.5.6.jar) to constructor java.nio.charset.StandardCharsets()
  • WARNING: Illegal reflective access by org.powermock.reflect.internal.WhiteboxImpl (file:/C:/Users/root/.gradle/caches/modules-2/files-2.1/org.powermock/powermock-reflect/2.0.0/cd452bc345ec9f88ec5efecd41139de0cb1d4265/powermock-reflect-2.0.0.jar) to method java.util.regex.Pattern.clazz(boolean)

build.gradle と IntelliJ IDEA の「Edit Configurations...」-「JUnit」の設定に以下のオプションを追加します。

  • --add-opens=java.base/java.util.stream=ALL-UNNAMED
  • --add-opens=java.base/java.nio.charset=ALL-UNNAMED
  • --add-opens=java.base/java.util.regex=ALL-UNNAMED

失敗するテストの原因を調査・解消する

エラーの原因を調べるために Project Tool Window で src/test/groovy/ksbysample でコンテキストメニューを表示して「Run 'Tests in 'ksbysample''」を選択してテストを実行してみると、

f:id:ksby:20190414210930p:plain

テストが失敗したのは src/test/groovy/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidatorTest.groovy で、以下のように実装されていました。

    @RunWith(PowerMockRunner)
    @PowerMockRunnerDelegate(SpringRunner)
    @SpringBootTest
    @PrepareForTest(EmailValidator)
    @PowerMockIgnore("javax.management.*")
    static class InquiryInput02FormValidator_メールアドレス {

        @Autowired
        private InquiryInput02FormValidator input02FormValidator

        ..........

@PowerMockIgnore("javax.management.*") を変更し忘れていただけでした。。。 @PowerMockIgnore("javax.management.*")@PowerMockIgnore(["javax.management.*", "com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "org.w3c.dom.*", "com.sun.org.apache.xalan.*"]) に変更します。ksbysample-webapp-lending と同じ変更だと Caused by: java.lang.IllegalAccessError: class com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl (in unnamed module @0x12e035a8) cannot access class jdk.xml.internal.JdkXmlUtils (in module java.xml) because module java.xml does not export jdk.xml.internal to unnamed module @0x12e035a8 というエラーメッセージが表示されたので、, "com.sun.org.apache.xalan.*" を追加しています。

compileTestGroovy タスクで出る警告を解消する。。。ことは出来ませんでした

WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedClass (file:/C:/Users/root/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.6/6936e700f0fb1b50bac0698ada4347a769d40199/groovy-2.5.6.jar) to method java.util.AbstractCollection.hugeCapacity(int) というエラーメッセージが出ているので compileTestGroovy タスクの jvmArgs にも --add-opens オプションを設定しようと思い設定方法を調べたところ、gradle/gradle に Unable to add multiple --add-opens args to forked Groovy compiler #7045 という Issue を見つけました。

試してみたところ "--add-opens" を1行だけ書いた時は問題ないのですが、以下のように2行記述すると、

[compileJava, compileTestGroovy, compileTestJava]*.options*.encoding = "UTF-8"
[compileJava, compileTestGroovy, compileTestJava]*.options*.compilerArgs = ["-Xlint:all,-options,-processing,-path"]
tasks.named("compileTestJava").configure {
    options.errorprone.enabled = false
}
compileTestGroovy {
    options.forkOptions.jvmArgs += [
            "--add-opens", "java.base/java.util=ALL-UNNAMED",
            "--add-opens", "java.base/java.lang.annotation=ALL-UNNAMED"
    ]
}

下の画像のエラーメッセージが表示されます。

f:id:ksby:20190415225416p:plain

他にも調べてみましたがさっぱり解決方法が分かりませんでした。Issue のクローズ待ちでしょうか。。。 今回は compileTestGroovy の警告メッセージは解消するのは諦めます。

ここまでの対応で clean タスク実行 → Rebuild Project 実行 → build タスク実行を行うと compileTestGroovy タスクで警告のメッセージが出ますが、BUILD SUCCESSFUL のメッセージが表示されるようになりました。

f:id:ksby:20190415231548p:plain

gebTest タスクが成功するようにする

gebTest タスクを実行すると1件警告が出ます。

  • WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedConstructor$1 (file:/C:/Users/root/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy/2.5.6/6936e700f0fb1b50bac0698ada4347a769d40199/groovy-2.5.6.jar) to constructor java.beans.Introspector(java.lang.Class,java.lang.Class,int)

java.beans は https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/java/beans/package-summary.html を見ると Module java.desktop と書かれていたので、

f:id:ksby:20190416062245p:plain

build.gradle と IntelliJ IDEA の「Edit Configurations...」-「JUnit」の設定に "--add-opens=java.desktop/java.beans=ALL-UNNAMED" を追加します。

def jvmArgsAddOpens = [
        "--add-opens=java.base/java.io=ALL-UNNAMED",
        "--add-opens=java.base/java.lang=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.invoke=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.ref=ALL-UNNAMED",
        "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED",
        "--add-opens=java.base/java.net=ALL-UNNAMED",
        "--add-opens=java.base/java.nio.charset=ALL-UNNAMED",
        "--add-opens=java.base/java.security=ALL-UNNAMED",
        "--add-opens=java.base/java.util=ALL-UNNAMED",
        "--add-opens=java.base/java.util.regex=ALL-UNNAMED",
        "--add-opens=java.base/java.util.stream=ALL-UNNAMED",
        "--add-opens=java.desktop/java.beans=ALL-UNNAMED"
]

これで gebTest タスクは正常に終了するようになりました。

f:id:ksby:20190416063337p:plain

以上で今回の boot-npm-geb-sample プロジェクトのバージョンアップ作業は完了です。

履歴

2019/04/16
初版発行。