かんがるーさんの日記

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

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その78 )( PMD を 6.5.0 → 6.6.0 へバージョンアップする+gradle-processes を導入する )

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その77 )( RequestAndResponseLogger クラスの Cookie ログは name, value だけ出力するように変更する+SESSION Cookie の secure 属性を true にするには? ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • build 時の警告ログが出なくなるような記事を見かけたので、PMD を 6.5.0 → 6.6.0 へバージョンアップしてみます。
    • Gradle 4.6 以降に対応した gradle-processes 0.5.0 がリリースされていましたので、正式に導入します。

参照したサイト・書籍

目次

  1. PMD を 6.5.0 → 6.6.0 へバージョンアップする
  2. gradle-processes を導入する
  3. 最後に

手順

PMD を 6.5.0 → 6.6.0 へバージョンアップする

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

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

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

clean タスク実行 → Rebuild Project → build タスクを実行してみますが、出力されるログはほとんど変わりませんでした。

f:id:ksby:20180813102536p:plain f:id:ksby:20180813102827p:plain

  • 以前は出ていなかった Could not determine ant log level, no supported build listeners found. Log level is set to FINEST というメッセージが表示されていました。
  • This analysis could be faster, please consider using Incremental Analysis: https://pmd.github.io/pmd-6.6.0/pmd_userdocs_incremental_analysis.html が2行出力される点は変わらず。

Could not determine ant log level, no supported build listeners found. Log level is set to FINEST の方は調べると以下の Issue を見つけました。PMD 6.7.0 待ちのようです。

gradle-processes を導入する

https://mvnrepository.com/artifact/gradle.plugin.com.github.jengelman.gradle.plugins/gradle-processes を見ると 0.5.0 がリリースされていました。

f:id:ksby:20180813135702p:plain

Not compatible with gradle 4.8.1 due to changes in gradles internal api の Issue が反映されたバージョンのはずなので、正式に導入してみます。

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

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

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.2"
    id "pmd"
    id "com.moowork.node" version "1.2.0"
    id "com.gorylenko.gradle-git-properties" version "1.5.1"
    id "com.github.johnrengelman.processes" version "0.5.0"
}
  • buildscript block に repositories { ... } を追加します。
  • plugins block に id "com.github.johnrengelman.processes" version "0.5.0" を追加します。

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

次に build.gradle に Web アプリの自動起動、自動停止のタスクを追加します。build.gradle の以下の点を変更します。

buildscript {
    ext {
        group "ksbysample"
        version "1.0.2-RELEASE"
        mainClass = "ksbysample.webapp.bootnpmgeb.Application"
    }
    ..........
}

..........

// 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()
    }
}
def drivers = ["chrome", "firefox"]
drivers.each { driver ->
    task "${driver}Test"(type: Test) {
        // 前回実行時以降に何も更新されていなくても必ず実行する
        outputs.upToDateWhen { false }
        systemProperty "geb.env", driver
        exclude "ksbysample/**"
        dependsOn startServer
        finalizedBy stopServer
    }
}
task gebTest {
    dependsOn drivers.collect { tasks["${it}Test"] }
    enabled = false
}
  • buildscript block に mainClass = "ksbysample.webapp.bootnpmgeb.Application" を追加します。
  • startServer, stopServer タスクを追加します。
  • drivers.each { driver -> task "${driver}Test"(type: Test) { ... } } 内に以下の2行を追加します。
    • dependsOn startServer
    • finalizedBy stopServer

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

まずは clean タスク実行 → Rebuild Project → build タスクを実行してみます。BUILD SUCCESSFUL が出力されて、startServer と stopServer タスクは実行されませんでした。

f:id:ksby:20180813151831p:plain

gebTask を実行してみます。startServer → chromeTest, firefoxTest → stopServer の順に実行されて、BUILD SUCCESSFUL が表示されました。

f:id:ksby:20180813153717p:plain f:id:ksby:20180813153838p:plain

chromeTest タスクだけを実行しても startServer → chromeTest → stopServer の順に実行されて、テストは全て成功しました。

f:id:ksby:20180813154726p:plain

firefoxTest タスクだけを実行しても startServer → chromeTest → stopServer の順に実行されて、テストは全て成功しました。

f:id:ksby:20180813155415p:plain

最後に

やりたいことが一通り終わりました。「Spring Boot + npm + Geb で入力フォームを作ってテストする」は以上で終わりです。

次は以下のことを書くつもりです。

  • Windows 10 PC を購入したので、まずは今の環境(Windows 7)から移行します。
  • その後に ksbysample-webapp-lending の Spring Boot 1.5 → 2.0 バージョンアップを行います。
  • 気がむいたら Spring Integration ネタをしばらく書いていないので、何か書くかもしれません。あるいは最近覚えている AWS 関連で何か試したいネタを見つけて書けるといいかな。。。

履歴

2018/08/13
初版発行。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その77 )( RequestAndResponseLogger クラスの Cookie ログは name, value だけ出力するように変更する+SESSION Cookie の secure 属性を true にするには? )

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その76 )( Spring Boot Actuator を導入する ) の続きです。

参照したサイト・書籍

目次

  1. 現在の状況を確認する
  2. サーバから Cookie の domani 属性が未セットの状態で返されると、ブラウザはアクセスした時のドメインをセットする?
  3. Spring Session では SESSION Cookie の httponly 属性をデフォルトで有効にしている?
  4. RequestAndResponseLogger クラスの Cookie のログでは name, value しか出力しないように変更する
  5. SESSION Cookie の secure 属性を true にするには?

手順

現在の状況を確認する

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その75 )( コネクションプーリング用ライブラリを Tomcat connection pool → HikariCP に切り替える ) で、ksbysample.webapp.bootnpmgeb.aspect.logging.RequestAndResponseLogger が出力しているログを見ると SESSION Cookie の domain 属性が null だったり、httponly 属性が false だったりしていたのですが、

[req][cookie] name = SESSION, value = MThlNDQ3NGUtNmQ0Mi00Y2Q2LTlmNTYtMDA4ZDZlYjg3NTQ3, domain = null, path = null, maxage = -1, secure = false, httponly = false

Chrome の Develper Tools で SESSION Cookie を確認すると domain 属性も httponly 属性もセットされていました。

f:id:ksby:20180812153719p:plain

Develper Tools で SESSION Cookie を削除してから再度リクエストを送信し、Fiddler で SESSION Cookie が最初に返される時の HTTP ヘッダを確認したところ以下の文字列が返ってきており、domain 属性はありませんが httponly 属性はセットされていました。

Set-Cookie: SESSION=ZDIyYThlZTctZDg1Yi00MGYyLTgwZmEtNzA4N2U4Y2E1YTY4; Path=/; HttpOnly

今度はリクエストの送信時に Cookie をどのように送信しているかを見てみると以下の文字列が HTTP ヘッダで送信されており、Cookie はキーと値しか送信されていませんでした。

Cookie: SESSION=ZDIyYThlZTctZDg1Yi00MGYyLTgwZmEtNzA4N2U4Y2E1YTY4

ということは、

  • サーバから Cookie の domani 属性が未セットの状態で返されると、ブラウザはアクセスした時のドメインをセットする?
  • Spring Session では SESSION Cookie の httponly 属性をデフォルトで有効にしている?
  • request 時のデータを ksbysample.webapp.bootnpmgeb.aspect.logging.RequestAndResponseLogger で出力しているが、request では Cookie は name と value しか送信されないので、それ以外の属性を出力しても意味がない。

サーバから Cookie の domani 属性が未セットの状態で返されると、ブラウザはアクセスした時のドメインをセットする?

調べたら CookieのDomain属性は 指定しない が一番安全 という記事を見つけました。内容が分かりやすく納得しました。domain 属性はセットしてはいけないんですね。

Spring Session では SESSION Cookie の httponly 属性をデフォルトで有効にしている?

org.springframework.session.web.http.DefaultCookieSerializer を見ると private boolean useHttpOnlyCookie = true; と実装されていました。デフォルトで httponly 属性を有効にしていました。

f:id:ksby:20180812160620p:plain

RequestAndResponseLogger クラスの Cookie のログでは name, value しか出力しないように変更する

src/main/java/ksbysample/webapp/bootnpmgeb/aspect/logging/RequestAndResponseLogger.java の以下の点を変更します。

    private void loggingRequestCookies(HttpServletRequest request) {
        if (request.getCookies() != null) {
            Arrays.asList(request.getCookies()).forEach(cookie -> {
                StringBuilder sb = new StringBuilder();
                sb.append("name = ")
                        .append(cookie.getName())
                        .append(", value = ")
                        .append(cookie.getValue());
                logging(LOG_REQUEST_COOKIE, null, sb.toString());
            });
        }
    }
  • loggingRequestCookies メソッド内の .append(", domain = ") ... .append(cookie.isHttpOnly()); を削除します。

これで SESSION Cookie をログに出力すると以下のように name, value しか出力されません。

[req][cookie] name = SESSION, value = OTk1MmIzZDktMjQwMi00NDEyLTgwZWItYWQyOTQ5MGYyMmUx

SESSION Cookie の secure 属性を true にするには?

Spring Session - Custom Cookie に記述がありました。

src/main/java/ksbysample/webapp/bootnpmgeb/config/ApplicationConfig.java に cookieSerializer Bean を定義し、その中で cookieSerializer.setUseSecureCookie(true); を呼び出して secure 属性を有効にします。独自の cookieSerializer Bean を定義すると Spring Session でこちらが使用されるようになります。

    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        cookieSerializer.setUseSecureCookie(true);
        return cookieSerializer;
    }

動作確認してみます。bs-springboot-config.js に https: true, を追加して Browsersync で https を処理できるようにします。

  ..........
  serveStatic: [],
  https: true,
  ghostMode: {
    ..........

Tomcat を起動した後、npm run springboot コマンドを実行します。

Chrome の Developer Tools で SESSION Cookie を削除した後、https://localhost:9080/inquiry/input/01/ にアクセスします。

画面が表示された後、Developer Tools で SESSION Cookie を見ると secure 属性が有効になっていることが確認できます。

f:id:ksby:20180812201647p:plain

履歴

2018/08/12
初版発行。

IntelliJ IDEA を 2018.1.6 → 2018.2.1 へバージョンアップ

IntelliJ IDEA を 2018.1.6 → 2018.2.1 へバージョンアップする

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

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

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

  2. IDE and Plugin Updates」ダイアログが表示されます。「Update and Restart」ボタンではなく「Download」ボタンが表示されています。

    f:id:ksby:20180812100320p:plain

    「Download」ボタンを押して IntelliJ IDEA の Download ページを開いた後、「DOWNLOAD」ボタンを押して ideaIU-2018.2.1.exe をダウンロードします。

    f:id:ksby:20180812100634p:plain

  3. 起動している IntelliJ IDEA を終了します。

  4. ideaIU-2018.2.1.exe を実行します。

  5. IntelliJ IDEA Setup」ダイアログが表示されます。「Next >」ボタンをクリックします。

    f:id:ksby:20180812101211p:plain

  6. 「Uninstall old versions」画面が表示されます。画面上の全てのチェックボックスをチェックした後、「Next >」ボタンをクリックします。

    f:id:ksby:20180812101338p:plain

  7. 「Choose Install Location」画面が表示されます。「Destination Folder」を C:\IntelliJ_IDEA\2018.2.1 に変更した後、「Next >」ボタンをクリックします。

    f:id:ksby:20180812101512p:plain

  8. 「Installation Options」画面が表示されます。何も変更せずに「Next >」ボタンをクリックします。

    f:id:ksby:20180812101607p:plain

  9. 「Choose Start Menu Folder」画面が表示されます。何も変更せずに「Install」ボタンをクリックします。

    f:id:ksby:20180812101711p:plain

  10. 「Installing」画面が表示されてインストールが始まりますので、完了するまで待ちます。

  11. インストールが完了すると「Completing IntelliJ IDEA Setup」画面が表示されます。「Finish」ボタンをクリックしてダイアログを閉じます。

  12. C:\IntelliJ_IDEA\2018.1.4 フォルダが残っていましたので削除します。

  13. C:\IntelliJ_IDEA\2018.2.1\bin\idea64.exe を実行します。

  14. 「Complete Installation」ダイアログが表示されますので「Previous version」が選択された状態で「OK」ボタンをクリックします。

    f:id:ksby:20180812102337p:plain

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

    f:id:ksby:20180812102758p:plain

  16. Plugin が最新にアップデートされていないので先にアップデートします。IntelliJ IDEA のメインメニューから「Help」-「Check for Updates...」を選択します。

  17. IDE and Plugin Updates」ダイアログが表示されます。何も変更せずに「Update」ボタンをクリックします。

    f:id:ksby:20180812103748p:plain

    Patch がダウンロードされた後、IntelliJ IDEA を再起動します。再起動後、画面下部に「Indexing…」のメッセージが表示されますので、終了するまで待機します。

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

  19. Gradle Tool Window のツリーを見ると「Tasks」の下に「other」しかない状態になっているので、左上にある「Refresh all Gradle projects」ボタンをクリックして更新します。

    f:id:ksby:20180812105519p:plain

    Gradle のアイコンが変わっているし、ボタンも青ではなくグレーになっていますね。よく見たら IntelliJ IDEA のボタンが全面的にグレーになっていて、調べたところ 2018.2 からアイコンを変更したことに関するBlog のページが見つかりました。個人的にアイコンがグレーなのは見にくかったので、迷わず ToolWindow Colorful Icons Plugin をインストールしました。

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

    f:id:ksby:20180812113311p:plain

    Run Tool Window を閉じようと思ったら、X アイコンも無くなっていますね。以下のページに無くした理由が記載されています。

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

    f:id:ksby:20180812122810p:plain

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

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その76 )( Spring Boot Actuator を導入する )

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その75 )( コネクションプーリング用ライブラリを Tomcat connection pool → HikariCP に切り替える ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Spring Boot Actuator を導入します。

参照したサイト・書籍

目次

  1. Actuator を導入せずに IntelliJ IDEA から Tomcat を起動するとどのような状態か?
  2. build.gradle を変更する
  3. IntelliJ IDEA から Tomcat を起動して Run Tool Window を確認する
  4. ログレベルを変更してみる
  5. /actuator/** を Spring Security の CSRF チェックの対象外にする
  6. ログレベルを変更してみる(続き)
  7. Info Endpoint から情報を取得してみる
  8. Shutdown Endpoint からシャットダウンしてみる
  9. Thread Dump Endpoint からスレッドダンプを出力してみる
  10. /actuator/** に IPアドレスでアクセス制限をかけるには?
  11. 最後に

手順

Actuator を導入せずに IntelliJ IDEA から Tomcat を起動するとどのような状態か?

IntelliJ IDEA から Tomcat を起動後、画面の下の Run Tool Window 内に表示される「EndPoints」タブの中の「Health」「Mappings」タブを見ると Spring Boot Actuator is not enabled. Add dependency to the spring-boot-actuator to enable it. のメッセージが表示されています。

f:id:ksby:20180805233846p:plain f:id:ksby:20180805233947p:plain

build.gradle を変更する

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

dependencies {
    ..........
    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.boot:spring-boot-starter-actuator") を追加します。

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

IntelliJ IDEA から Tomcat を起動して Run Tool Window を確認する

今度は「Health」「Mappings」タブ内にデータが表示されるようになりました。

f:id:ksby:20180806000034p:plain f:id:ksby:20180806000243p:plain

  • デフォルトで health check してくれる対象は 50.9.1 Auto-configured HealthIndicator に一覧があります。Elasticsearch、Rabbit、Redis 等もチェックしてくれるようです。
  • 現在メールサーバ(smtp4dev)を起動していないので、mail に「Status: DOWN」のアイコンが表示されていました。
  • 「Mappings」に表示されている Path の内リンクになっているもの(おそらく GET でアクセス可能なもの?)をクリックすると、ブラウザが起動してドメイン名やポート番号を追加された URL でアクセスしてくれます。大量に表示されていても IntelliJ IDEA の Search 機能が効くのでパスをタイプすると該当するものにジャンプしてくれます(下の例だと input 03 と入力しています)。これは以外に便利な機能ではないでしょうか。 f:id:ksby:20180806003908p:plain
  • webjars は導入していないのですが、/webjars/** が表示されていました。Spring Boot Reference Guide を見たところ In addition to the “standard” static resource locations mentioned earlier, a special case is made for Webjars content. Any resources with a path in /webjars/** are served from jar files if they are packaged in the Webjars format. という記述があり、src/main/resources の下に static ディレクトリを作成すると自動で /webjars/** の mapping?を作成するようです。初めて知りました。。。

smtp4dev を起動すると mail のアイコンが「Status: UP」のものに変わりました。IntelliJ IDEA で起動している場合にはデフォルトだと 15秒間隔でチェックされます(「Endpoints」タブ内の左側にある歯車アイコンをクリックすると設定画面が表示されます。)。

f:id:ksby:20180806002601p:plain

ログレベルを変更してみる

application.properties に設定を追加して Loggers endpoint を有効にします。

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

management.endpoints.web.exposure.include=health,info,loggers

spring.datasource.hikari.jdbc-url=jdbc:h2:mem:bootnpmgebdb
..........
  • management.endpoints.web.exposure.include=health,info,loggers を追加します。management.endpoints.web.exposure.include の設定を追加する場合、デフォルトで有効になっている health, info も記述しないと無効になります。

IntelliJ IDEA から Tomcat を再起動した後、ブラウザから http://localhost:8080/inquiry/input/01 にアクセスすると以下のログが出力されます。application-develop.properties に logging.level.org.springframework.web=DEBUG の設定を入れていますので、DEBUG ログが出力されています。

f:id:ksby:20180806005716p:plain

Spring Boot Actuator Web API Documentation を参考に、コマンドプロンプトから curl 'http://localhost:8080/actuator/loggers/org.springframework.web' -i -X POST -H 'Content-Type: application/json' -d '{"configuredLevel":"info"}' コマンドを実行します。。。が 403 でアクセス拒否されました。Spring Security が入っているので POST メソッドだと CSRF のチェック対象から外さないとアクセスできませんでした。

f:id:ksby:20180806010334p:plain

/actuator/** を Spring Security の CSRF チェックの対象外にする

src/main/java/ksbysample/webapp/bootnpmgeb/config/WebSecurityConfig.java の以下の点を変更します。http.csrf().ignoringAntMatchers(...) というメソッドがあることに気づいたのでいろいろ書き直します。

package ksbysample.webapp.bootnpmgeb.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * ???
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String ACTUATOR_ANT_PATTERN = "/actuator/**";
    private static final String H2_CONSOLE_ANT_PATTERN = "/h2-console/**";

    @Value("${spring.h2.console.enabled:false}")
    private boolean springH2ConsoleEnabled;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 認証の対象外にしたいURLがある場合には、以下のような記述を追加します
                // 複数URLがある場合はantMatchersメソッドにカンマ区切りで対象URLを複数列挙します
                // .antMatchers("/country/**").permitAll()
                //
                // この Web アプリケーションでは Spring Security を CSRF対策で使用したいだけなので、
                // 全ての URL を認証の対象外にする
                .antMatchers("/**").permitAll()
                .anyRequest().authenticated();

        // Spring Boot Actuator のパスは CSRF チェックの対象外にする
        http.csrf().ignoringAntMatchers(ACTUATOR_ANT_PATTERN);

        // spring.h2.console.enabled=true に設定されている場合には H2 Console を表示するために必要な設定を行う
        if (springH2ConsoleEnabled) {
            http.csrf().ignoringAntMatchers(H2_CONSOLE_ANT_PATTERN);
            http.headers().frameOptions().sameOrigin();
        }
    }

}
  • private static final Pattern DISABLE_CSRF_TOKEN_PATTERN = Pattern.compile("(?i)^(GET|HEAD|TRACE|OPTIONS)$"); を削除します。
  • private static final String ACTUATOR_ANT_PATTERN = "/actuator/**"; を追加します。
  • private static final Pattern H2_CONSOLE_URI_PATTERN = Pattern.compile("^/h2-console");private static final String H2_CONSOLE_ANT_PATTERN = "/h2-console/**"; に変更します。
  • http.csrf().ignoringAntMatchers(ACTUATOR_ANT_PATTERN); を追加します。
  • http.csrf() から .requireCsrfProtectionMatcher(...) を削除し、.ignoringAntMatchers(H2_CONSOLE_ANT_PATTERN) を追加します。

ログレベルを変更してみる(続き)

再度 curl コマンドを実行すると、今度は 204(No Content)が返ってきました。成功したようです。

f:id:ksby:20180806012314p:plain

ブラウザから http://localhost:8080/inquiry/input/01 にアクセスしてログを出力してみると DEBUG ログが出力されていません。これまで設定を変更して再起動しないと変更できないものと思っていたので、これはちょっと感激です。

f:id:ksby:20180806012555p:plain

curl 'http://localhost:8080/actuator/loggers/org.springframework.web' -i -X GET コマンドを実行すれば、現在設定されているログレベルが取得できます。

f:id:ksby:20180806013233p:plain

Info Endpoint から情報を取得してみる

Spring Boot Actuator Web API Documentation - 11. Info (info) を参考にコマンドプロンプトから curl 'http://localhost:8080/actuator/info' -i -X GET コマンドを実行してみます。。。が、何も返ってきませんでした。"git" と "build" の情報が返ってくるものと思ったのですが。

f:id:ksby:20180807010529p:plain

調べてみると Spring Boot Reference Guide に以下の記述を見つけました。build.gradle に設定を追加して情報を生成しないといけないようです。

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.2"
    id "pmd"
    id "com.moowork.node" version "1.2.0"
    id "com.gorylenko.gradle-git-properties" version "1.5.1"
}

..........

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

springBoot {
    buildInfo()
}
  • plugins block に id "com.gorylenko.gradle-git-properties" version "1.5.1" を追加します。
  • springBoot { buildInfo() } を追加します。

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

clean タスク → Rebuild Project → build タスクを実行すると bootBuildInfogenerateGitProperties というタスクが追加されていました。

f:id:ksby:20180807012748p:plain

Tomcat を起動して、再び curl 'http://localhost:8080/actuator/info' -i -X GET コマンドを実行してみますがやっぱり何も出ません。どうも Executable Jar から起動しないと何も出ないようです。

f:id:ksby:20180807013038p:plain

Tomcat を停止後 Executable Jar から起動して再度コマンドを実行すると、今度は情報が返ってきました。

f:id:ksby:20180807013649p:plain

JSON がフォーマットされていなくて見にくいので、jq というツールを入れてフォーマットしてみます。Download jq から「Windows」の jq 1.5 executables for 64-bit or 32-bit.64-bit のリンクをクリックして jq-win64.exe をダウンロードした後、ファイル名を jq.exe に変更して C:\Git\mingw64\bin の下へ入れます。

HTTPヘッダは不要なので -i オプションを外し、他にも余計な情報を出さないように -s オプションを付けて curl 'http://localhost:8080/actuator/info' -X GET -s | jq コマンドを実行するときれいに整形されました。

f:id:ksby:20180807021022p:plain

Shutdown Endpoint からシャットダウンしてみる

application.properties に設定を追加して Shutdown endpoint を有効にします。Shutdown endpoint は management.endpoints.web.exposure.include に endpoint 名を追加するだけでは有効にならず、management.endpoint.shutdown.enabled=true も追加する必要がありますAppendix A. Common application properties に記述がありました)。

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

IntelliJ IDEA から Tomcat を起動後、curl 'http://localhost:8080/actuator/shutdown' -i -X POST コマンドを実行すると {"message":"Shutting down, bye..."} のレスポンスが返ってきました。

f:id:ksby:20180808015723p:plain

しかし、Tomcat の方は落ちませんでした。これも Executable Jar から起動しないとダメなのかな。。。

f:id:ksby:20180808015629p:plain

boot-npm-geb-sample-1.0.2-RELEASE.jar を作成し直してコピーしてから、コマンドプロンプトから起動してみます。

f:id:ksby:20180808020802p:plain f:id:ksby:20180808020942p:plain

curl 'http://localhost:8080/actuator/shutdown' -i -X POST コマンドを実行すると、

f:id:ksby:20180808021236p:plain

今度は Tomcat が停止しました。ログは IntelliJ IDEA から Tomcat を起動した時と同じく HikariPool-1 - Shutdown completed. で終わっていました。

f:id:ksby:20180808021403p:plain f:id:ksby:20180808021622p:plain

ちなみにサービスに登録して起動してから、

f:id:ksby:20180808022052p:plain

curl コマンドを実行して停止してもサービスの画面上は起動したままでした。ログは HikariPool-1 - Shutdown completed. までは出力されています。

f:id:ksby:20180808022303p:plain f:id:ksby:20180808022556p:plain

Executable Jar を直接起動している時はきちんと落ちるようですが、IntelliJ IDEA や Windows のサービスから起動している時は落ちたことが起動元のプロセスに伝わらない、ということでしょうか?

Thread Dump Endpoint からスレッドダンプを出力してみる

application.properties に設定を追加して Thread Dump endpoint を有効にします。

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

IntelliJ IDEA から Tomcat を起動後、curl 'http://localhost:8080/actuator/threaddump' -i -X POST コマンドを実行します。

f:id:ksby:20180808221827p:plain

なんかこれじゃない感が。。。 スレッドダンプと言えばテキスト形式のものだと思っていたので、JSON ではなくテキストのものを返して欲しいのですが、テキストで返す方法は見当たりませんでした。

もしかして最近はスレッドダンプは JSON 形式が常識なのか?と思って調べてみましたが、それらしい記事も見当たらず。その代わり以下の記事を見つけました。IBM Thread and Monitor Dump Analyzer for Java というツールが便利そうです。

試しに Java VisualVM からスレッドダンプを出力してテキストファイルに保存した後、

f:id:ksby:20180808224409p:plain f:id:ksby:20180808224506p:plain

java -Xmx512m -jar jca457.jar コマンドで IBM Thread and Monitor Dump Analyzer for Java を起動して保存したスレッドダンプを読み込ませると以下のような感じで表示されます。

f:id:ksby:20180808224740p:plain f:id:ksby:20180808224910p:plain f:id:ksby:20180808225045p:plain

2つのタイミングの異なるスレッドダンプを読み込ませて比較表示することも出来るようです。

f:id:ksby:20180808225523p:plain f:id:ksby:20180808225731p:plain

このツール、全然噂を聞いたことがありませんでした。そんなに有名なツールではないのかな?

/actuator/**IPアドレスでアクセス制限をかけるには?

src/main/java/ksbysample/webapp/bootnpmgeb/config/WebSecurityConfig.java に以下のように定義します。

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()

                // アクセス元のホストIPアドレスで指定する場合
                .antMatchers(ACTUATOR_ANT_PATTERN).hasIpAddress("127.0.0.1")
                .antMatchers(ACTUATOR_ANT_PATTERN).hasIpAddress("192.168.56.1")

                // アクセス元のネットワークIPアドレスで指定する場合
                .antMatchers(ACTUATOR_ANT_PATTERN).hasIpAddress("192.168.56.0/24")

                // アクセス元を複数指定する場合
                .antMatchers(ACTUATOR_ANT_PATTERN)
                    .access("hasIpAddress('127.0.0.1') or hasIpAddress('192.168.56.0/24')")

                ..........

最後に

Health , Loggers, Mappings 等の Endpoint も面白いのですが、Actuator で一番面白そうなのは Prometheus Endpoint を利用して Prometheus と連携してモニタリングすることですよね。他の人が書いたものを見る限りでは簡単に出来るようです。

Spring Boot ってどんどん便利になっていますが、覚えることが多くて大変です。。。 いや、本当に。

Spring Boot Actuator の導入まで終わりましたが、あと以下の点を記述して終わりにする予定です。

  • Spring Session が生成している SESSION Cookie の domain 属性や httponly 属性の値を変更する方法の調査
  • gradle-processes の Gradle 4.6 以降対応版が出ているようなので正式に導入する
  • PMD を 6.6.0 にバージョンアップすると build タスク実行時のメッセージが減るような記述を見かけたので、その検証

履歴

2018/08/09
初版発行。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その75 )( コネクションプーリング用ライブラリを Tomcat connection pool → HikariCP に切り替える )

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その74 )( FindBugs 3.0.1 → SpotBugs 3.1.3 に切り替える ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • Spring Boot 2 からデフォルトのコネクションプーリング用ライブラリが Tomcat connection pool → HikariCP に変わりましたので、HikariCP に変更します。

参照したサイト・書籍

目次

  1. build.gradle を変更する
  2. application.properties を変更する
  3. logback-spring.xml を変更する
  4. dataSource Bean の実装を変更する
  5. clean タスク → Rebuild Project → build タスクを実行する
  6. JMX への登録状況を確認する
  7. Executable Jar ファイルから起動してみる

手順

build.gradle を変更する

build.gradle の dependencies block から implementation("org.apache.tomcat:tomcat-jdbc") の行を削除します。

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

application.properties を変更する

Configuration を読んだのですが、おそらく HikariCP はデフォルトの設定で十分で個別に設定する必要がないと思います。よって jdbc-url, username, password, driver-class-name と気になった leak-detection-threshold だけ設定します(leak-detection-threshold もその心配がなければ削除して構わないと思います)。

また JMX への登録は Tomcat connection pool の時は spring.datasource.jmx-enabled=true の設定で行いましたが、HikariCP では spring.datasource.hikari.register-mbeans=true の設定で行います。

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

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

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.session.store-type=jdbc
..........

また src/main/resources/application-product.properties から以下の5行の設定を削除します。

  • slowquery.logging.file=${server.tomcat.basedir}/logs/slow-query.log
  • spring.datasource.tomcat.initialSize=2
  • spring.datasource.tomcat.maxActive=2
  • spring.datasource.tomcat.maxIdle=2
  • spring.datasource.tomcat.minIdle=2

logback-spring.xml を変更する

Tomcat connection pool の SlowQueryReport interceptor がなくなりましたので、<if condition='"${spring.profiles.active}" == "product" &amp;&amp; "${slowquery.logging.file}" != ""'> ... </if> の設定を削除します。

dataSource Bean の実装を変更する

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

@Configuration
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class ApplicationConfig {

    ..........

    /**
     * @return HikariCP の DataSource オブジェクト
     */
    @Bean
    @ConfigurationProperties("spring.datasource.hikari")
    public DataSource dataSource() {
        return DataSourceBuilder.create()
                .type(HikariDataSource.class)
                .build();
    }

}
  • @EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) を追加します。
  • @ConfigurationProperties("spring.datasource.tomcat")@ConfigurationProperties("spring.datasource.hikari") に変更します。
  • .type(org.apache.tomcat.jdbc.pool.DataSource.class).type(HikariDataSource.class) に変更します。

@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING) を付けていないと Executable Jar から起動しようとした時に以下の例外が発生して起動しません(IntelliJ IDEA の時は起動します)。

org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [HikariDataSource (HikariPool-1)] with key 'dataSource'; nested exception is javax.management.InstanceAlreadyExistsException: MXBean already registered with name com.zaxxer.hikari:type=PoolConfig (HikariPool-1)
    at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:625)
    at org.springframework.jmx.export.MBeanExporter.lambda$registerBeans$2(MBeanExporter.java:551)
    at java.util.HashMap.forEach(HashMap.java:1289)
    at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:551)
    at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:434)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:776)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:869)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:762)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:398)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:330)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1258)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246)
    at ksbysample.webapp.bootnpmgeb.Application.main(Application.java:43)
    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.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: javax.management.InstanceAlreadyExistsException: MXBean already registered with name com.zaxxer.hikari:type=PoolConfig (HikariPool-1)
    at com.sun.jmx.mbeanserver.MXBeanLookup.addReference(MXBeanLookup.java:151)
    at com.sun.jmx.mbeanserver.MXBeanSupport.register(MXBeanSupport.java:160)
    at com.sun.jmx.mbeanserver.MBeanSupport.preRegister2(MBeanSupport.java:173)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:930)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)
    at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:137)
    at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:671)
    at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:615)
    ... 22 common frames omitted

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

clean タスク → Rebuild Project → build タスクを実行すると BUILD SUCCESSFUL が出力されました。問題ないようです。

f:id:ksby:20180805080215p:plain

JMX への登録状況を確認する

IntelliJ IDEA から Tomcat を起動した後、コマンドプロンプトから jconsole コマンドを実行します。

f:id:ksby:20180805080936p:plain

「JConsole: 新規接続」ダイアログが表示されますので、「ローカル・プロセス」の一覧から ksbysample.webapp.bootnpmgeb.Application を選択した後「接続」ボタンをクリックします。

f:id:ksby:20180805081108p:plain

JConsole の画面が表示されますので「MBeans」タグをクリックします。画面左側のツリーに「com.zaxxer.hikari」という項目で登録されていることが確認できます。

f:id:ksby:20180805081344p:plain

Executable Jar ファイルから起動してみる

生成された build/libs/boot-npm-geb-sample-1.0.2-RELEASE.jar を C:\webapps\boot-npm-geb-sample\lib の下にコピーした後、C:\webapps\boot-npm-geb-sample\bat\webapp_startup.bat をコマンドプロンプトから起動します。

入力画面1~3で入力して確認画面→送信画面まで進めても特にエラーは発生しませんでした。ただし、今回ログを見ていて気づきましたが、Spring Session が生成している SESSION Cookie の domain 属性が null? とか、httponly 属性が false?とかなんかいろいろ問題がありそうです。。。 次回以降で調査してみます。

[req][cookie] name = SESSION, value = MThlNDQ3NGUtNmQ0Mi00Y2Q2LTlmNTYtMDA4ZDZlYjg3NTQ3, domain = null, path = null, maxage = -1, secure = false, httponly = false

JMX の登録状況も確認します。コマンドプロンプトから jconsole コマンドを実行した後、「JConsole: 新規接続」ダイアログの「ローカル・プロセス」の一覧から boot-npm-geb-sample-1.0.2-RELEASE.jar を選択して「接続」ボタンをクリックします。

f:id:ksby:20180805124621p:plain

IntelliJ IDEA から起動した時と同様に「MBeans」タグの画面左側のツリーに「com.zaxxer.hikari」という項目で登録されていることが確認できます。

f:id:ksby:20180805124813p:plain

履歴

2018/08/05
初版発行。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( その74 )( FindBugs 3.0.1 → SpotBugs 3.1.3 に切り替える )

概要

記事一覧はこちらです。

Spring Boot + npm + Geb で入力フォームを作ってテストする ( 番外編 )( IntelliJ IDEA に Rainbow Brackets をインストールする ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • バージョンアップ時に FindBugs で警告が出たので確認しようと思いましたが、この機会に SpotBugs に切り替えてしまおうと思います。
    • 今回から JDK を 8u181 に変更しています。

参照したサイト・書籍

目次

  1. build.gradle を変更する
  2. config/findbugs/findbugs-exclude.xml → config/spotbugs/spotbugs-exclude-filter.xml に変更する
  3. clean タスク → Rebuild Project → build タスクを実行する
  4. 出力された警告を解消する
    1. null になっている可能性があるメソッドの戻り値を利用しています。(Bug type NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE )
    2. target は,非 null でなければならないが null 可能としてマークされています。(Bug type NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE)
  5. 再び clean タスク → Rebuild Project → build タスクを実行する
  6. IntelliJ IDEA から FindBugs-IDEA Plugin をアンインストールする

手順

build.gradle を変更する

FindBugs 3.0 から SpotBugs 3.1 への移行ガイド を参考に build.gradle の以下の点を変更します。

plugins {
    ..........
    id "checkstyle"
    id "com.github.spotbugs" version "1.6.2"
    id "pmd"
    ..........
}

..........

spotbugs {
    toolVersion = '3.1.3'
    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
    }
}

..........

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 spotbugsVersion = "3.1.3"

    ..........

    // 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")
}
  • plugins block の以下の点を変更します。
    • id "findbugs"id "com.github.spotbugs" version "1.6.2" に変更します。
  • タスク名を findbugsspotbugs に変更し、以下の点を変更します。
    • toolVersion = '3.0.1'toolVersion = '3.1.3' に変更します。
    • excludeFilter = file("${rootProject.projectDir}/config/findbugs/findbugs-exclude.xml")excludeFilter = file("${rootProject.projectDir}/config/spotbugs/spotbugs-exclude-filter.xml") に変更します。
  • tasks.withType(FindBugs)tasks.withType(com.github.spotbugs.SpotBugsTask) に変更します。
  • dependencies block の以下の点を変更します。
    • 以下の4行を追加します。
      • def spotbugsVersion = "3.1.3"
      • compileOnly("com.github.spotbugs:spotbugs:${spotbugsVersion}")
      • compileOnly("net.jcip:jcip-annotations:1.0")
      • compileOnly("com.github.spotbugs:spotbugs-annotations:${spotbugsVersion}")
    • 以下の1行を SpotBugs のライブラリの記述の下に移動します。
      • testImplementation("com.google.code.findbugs:jsr305:3.0.2")

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

config/findbugs/findbugs-exclude.xml → config/spotbugs/spotbugs-exclude-filter.xml に変更する

config/findbugs/findbugs-exclude.xml → config/spotbugs/spotbugs-exclude-filter.xml にフォルダ名、ファイル名を変更します。また フィルタファイル を参考にファイルの内容の以下の点を変更します。

<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter
        xmlns="https://github.com/spotbugs/filter/3.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubusercontent.com/spotbugs/spotbugs/3.1.0/spotbugs/etc/findbugsfilter.xsd">
    <Match>
        <Class name="ksbysample.webapp.lending.web.lendingapp.LendingappService"/>
        <Bug pattern="DLS_DEAD_LOCAL_STORE"/>
    </Match>
</FindBugsFilter>
  • <FindBugsFilter><FindBugsFilter xmlns="https://github.com/spotbugs/filter/3.0.0" ...> に変更します。

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

clean タスク → Rebuild Project → build タスクを実行してみると BUILD SUCCESSFUL の文字が出力されました。ただし SpotBugs rule violations were found. のメッセージが出るのは FindBugs の時と変わりませんでした。

f:id:ksby:20180804145611p:plain

レポートファイルは build/reports/spotbugs/main.html に作成されており、開いてみると FindBugs の時と同じく警告が5件出ています。

f:id:ksby:20180804150233p:plain

出力された警告を解消する

null になっている可能性があるメソッドの戻り値を利用しています。(Bug type NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE

警告が出ている原因の箇所は src/main/java/ksbysample/webapp/bootnpmgeb/aspect/logging/RequestAndResponseLogger.java の以下の画像の赤線で囲んだところでした。RequestContextHolder.getRequestAttributes().getResponse() の戻り値が null の可能性があるので警告が出ています。

f:id:ksby:20180804153814p:plain

Optional を使って以下のように変更します。

f:id:ksby:20180804165110p:plain

target は,非 null でなければならないが null 可能としてマークされています。(Bug type NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE)

警告が出ている原因の箇所は src/main/java/ksbysample/webapp/bootnpmgeb/web/inquiry/form/InquiryInput02FormValidator.java の以下の画像の赤線で囲んだところでした。

f:id:ksby:20180804165539p:plain

これは validate メソッドの引数を Object target@Nonnull Object target に変更します。

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

再び clean タスク → Rebuild Project → build タスクを実行すると、今度は SpotBugs の警告は出ずに BUILD SUCCESSFUL が出力されました。

f:id:ksby:20180804171646p:plain

修正した内容は Spring Boot 2系とは関係ないように思えるのですが、なぜバージョンアップしたら警告が出るようになったのかが分からないですね。。。

IntelliJ IDEA から FindBugs-IDEA Plugin をアンインストールする

FindBugs を使用しなくなったので FindBugs-IDEA Plugin をアンインストールします。

f:id:ksby:20180804172746p:plain

履歴

2018/08/04
初版発行。
2018/08/29
SpotBugs が正常に動作していなかったので build.gradle の spotbugs タスクの以下の点を修正した。
* sourceSets = [project.sourceSets.main] を削除した
* spotbugsTest.enabled = false を追加した

Java SE を 8u172 → 8u181 へバージョンアップ

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

Java SE を 8u172 → 8u181 へバージョンアップする

  1. OracleJava SE Downloads を見ると 8u181 がダウンロードできるようになっていましたので、8u181 へバージョンアップします。

  2. jdk-8u181-windows-x64.exe をダウンロードして C:\Java\jdk1.8.0_181 へインストールした後、環境変数 JAVA_HOME のパスを C:\Java\jdk1.8.0_181 へ変更します。

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

    f:id:ksby:20180804090025p:plain

  3. IntelliJ IDEA を再起動した後、プロジェクトで使用する Java SE を 8u181 へ変更します。

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

  5. ダイアログ下部の「Configure」-「Project Defaults」-「Project Structure」を選択します。メニューが増えていますね。。。

    f:id:ksby:20180804090747p:plain

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

    f:id:ksby:20180804091357p:plain

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

    f:id:ksby:20180804093549p:plain

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

    f:id:ksby:20180804093728p:plain

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

    f:id:ksby:20180804094005p:plain

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

    f:id:ksby:20180804094153p: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:20180804094500p:plain

    「Project SDK」と「Project language level」を選択し直します。

    f:id:ksby:20180804094643p:plain

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

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

    f:id:ksby:20180804094750p:plain

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

    f:id:ksby:20180804095701p:plain

  18. Project Tool Window で src/test を選択した後、コンテキストメニューを表示して「Run ‘All Tests’ with Coverage」を選択し、テストが全て成功することを確認します。

    f:id:ksby:20180804101022p:plain

  19. 特に問題は発生しませんでした。8u181 で開発を進めます。