かんがるーさんの日記

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

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その5 )( checkstyle を 7.8.1 → 8.12 に、PMD を 5.8.1 → 6.7.0 にバージョンアップする )

概要

記事一覧はこちらです。

Spring Boot 1.5.x の Web アプリを 2.0.x へバージョンアップする ( その4 )( AbstractJsonpResponseBodyAdvice を削除し、失敗しているテストを成功させる ) の続きです。

  • 今回の手順で確認できるのは以下の内容です。
    • checkstyle を 7.8.1 → 8.12 にバージョンアップします。
    • PMD を 5.8.1 → 6.7.0 にバージョンアップします。

参照したサイト・書籍

目次

  1. checkstyle を 7.8.1 → 8.12 にバージョンアップする
  2. PMD を 5.8.1 → 6.7.0 にバージョンアップする
    1. build.gradle を変更して build してみる
    2. The constant name 'springProfiles' doesn't match '[A-Z][A-Z_0-9]*'
    3. Do not use hard coded encryption keys
    4. Comment is too large: Too many lines
    5. Avoid throwing raw exception types.
    6. The constant name 'logger' doesn't match '[A-Z][A-Z_0-9]*'
    7. StringBuffer (or StringBuilder).append is called consecutively without reusing the target variable.
    8. This class has too many methods, consider refactoring it.
    9. Avoid unnecessary constructors - the compiler will generate these for you
    10. It is a good practice to call super() in a constructor
    11. A method/constructor should not explicitly throw java.lang.Exception
    12. The constant name 'serialVersionUID' doesn't match '[A-Z][A-Z_0-9]*'
    13. Useless parentheses.
    14. Document empty constructor
    15. There is log block not surrounded by if
    16. Avoid short class names like ...
    17. Avoid using Literals in Conditional Statements
    18. Avoid instantiating new objects inside loops
    19. Prefer StringBuilder (non-synchronized) or StringBuffer (synchronized) over += for concatenating strings
    20. Assigning an Object to null is a code smell. Consider refactoring.
    21. Avoid using redundant field initializer for 'errcode'
    22. Avoid catching generic exceptions such as NullPointerException, RuntimeException, Exception in try-catch block
    23. 最後に

手順

checkstyle を 7.8.1 → 8.12 にバージョンアップする

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

checkstyle {
    configFile = file("${rootProject.projectDir}/config/checkstyle/google_checks.xml")
    toolVersion = "8.12"
    sourceSets = [project.sourceSets.main]
}
  • checkstyle タスクで toolVersion = "7.8.1"toolVersion = "8.12" に変更します。

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

clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると、checkstyleMain タスクで失敗しました。

f:id:ksby:20180917093557p:plain

コマンドラインから gradlew --stacktrace --debug build > gradle-debug.log 2>&1 コマンドを実行してログをファイルに出力した後、gradle-debug.log を IntelliJ IDEA のメインメニューの「Tools」-「Tail File in Console...」で開きます。

f:id:ksby:20180917094603p:plain

Property 'maxLineLength' in module LeftCurly does not exist, please check the documentation というエラーが出ていました。Spring Boot + npm + Geb で入力フォームを作ってテストする ( その28 )( Spring Boot を 1.5.4 → 1.5.7 へ、error-prone を 2.0.15 → 2.1.1 へバージョンアップする ) で書きましたが、LeftCurly module から maxLineLength プロパティがなくなったので削除します。

config/checkstyle/google_checks.xml を以下のように変更します。

        <module name="NeedBraces"/>
        <module name="LeftCurly"/>
        <module name="RightCurly">
            <property name="id" value="RightCurlySame"/>
            <property name="tokens" value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_DO"/>
        </module>
  • LeftCurly module に記述していた <property name="maxLineLength" value="100"/> を削除して、<module name="LeftCurly">...</module><module name="LeftCurly"/> に変更します。

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

f:id:ksby:20180917095641p:plain

Checkstyle plugin の設定も 8.12 に変更しておきます。

f:id:ksby:20180917095842p:plain

PMD を 5.8.1 → 6.7.0 にバージョンアップする

以下の記事をベースに進めます。

設定ファイルも以下のファイルをコピーします。

build.gradle を変更して build してみる

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

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

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

pmd-project-rulesets.xml をダウンロードして、config/pmd/pmd-project-rulesets.xml にコピーします。

clean タスク実行 → Rebuild Project 実行 → build タスクを実行しますが、警告が大量に出力されました。1つずつ解消していきます。

f:id:ksby:20180917133714p:plain

The constant name 'springProfiles' doesn't match '[A-Z][A-Z_0-9]*'

定数名を 英大文字+スネークケースにしていなかったので、警告が出ていました。警告に従って springProfilesSPRING_PROFILES に変更します。

Do not use hard coded encryption keys

SecretKeySpec クラスのコンストラクタの第1引数に渡すキー文字列をクラス内に定数として定義していたので、外部に定義するよう警告が出ていました。このサンプルではこのままにしますので、クラスに @SuppressWarnings({"PMD.HardCodedCryptoKey"}) を付けて警告が出ないようにします。

Comment is too large: Too many lines

コメントの行数が多いという警告なのですが、警告が出たところを見ると以下の内容でした。

f:id:ksby:20180917141407p:plain

この警告は不要なので削除します。config/pmd/pmd-project-rulesets.xml では一旦 exclude した後、<rule ref="category/java/documentation.xml/CommentSize">...</rule> で定義し直していたのですが、<rule ref="category/java/documentation.xml/CommentSize">...</rule> を削除して exclude するだけにします。

Avoid throwing raw exception types.

適切な Exception クラスを定義せずに throw new RuntimeException(e); と RuntimeException を throw していたので警告が出ていました。このサンプルでは config/pmd/pmd-project-rulesets.xml を以下のように変更して、警告が出ないようにします。

    <rule ref="category/java/design.xml">
        <exclude name="AvoidThrowingRawExceptionTypes"/>
        <exclude name="CyclomaticComplexity"/>
        <exclude name="DataClass"/>
        <exclude name="LawOfDemeter"/>
        <exclude name="LoosePackageCoupling"/>
        <exclude name="NcssCount"/>
        <exclude name="UseObjectForClearerAPI"/>
        <exclude name="UseUtilityClass"/>
    </rule>
  • <exclude name="AvoidThrowingRawExceptionTypes"/> を追加します。

The constant name 'logger' doesn't match '[A-Z][A-Z_0-9]*'

logger を private static final Logger logger = LoggerFactory.getLogger(ControllerAndEventNameLogger.class); と定義していたので、定数なのに英大文字+スネークケースでないと警告が出ていました。でも、変数は logger のままにしたいので static を削除すると、今度は The Logger variable declaration does not contain the static and final modifiers という警告が出ます。

今回は static を削除して private static final Logger logger = ...private final Logger logger = ... に変更し、config/pmd/pmd-project-rulesets.xml を以下のように変更します。

    <rule ref="category/java/errorprone.xml">
        <exclude name="BeanMembersShouldSerialize"/>
        <exclude name="DataflowAnomalyAnalysis"/>
        <exclude name="LoggerIsNotStaticFinal"/>
        <exclude name="MissingStaticMethodInNonInstantiatableClass"/>
    </rule>
  • <exclude name="LoggerIsNotStaticFinal"/> を追加します。

StringBuffer (or StringBuilder).append is called consecutively without reusing the target variable.

1行ずつ .append(...) を呼び出していたので警告が出ていました。

f:id:ksby:20180917230017p:plain

.append(...) を連続で呼び出すようにします。

This class has too many methods, consider refactoring it.

メソッド数が多いので警告が出ていました。この警告は不要なので、config/pmd/pmd-project-rulesets.xml を以下のように変更します。

    <rule ref="category/java/design.xml">
        <exclude name="AvoidThrowingRawExceptionTypes"/>
        <exclude name="CyclomaticComplexity"/>
        <exclude name="DataClass"/>
        <exclude name="LawOfDemeter"/>
        <exclude name="LoosePackageCoupling"/>
        <exclude name="NcssCount"/>
        <exclude name="TooManyMethods"/>
        <exclude name="UseObjectForClearerAPI"/>
        <exclude name="UseUtilityClass"/>
    </rule>
  • <exclude name="TooManyMethods"/> を追加します。

Avoid unnecessary constructors - the compiler will generate these for you

以下のように空の public コンストラクタを定義していたら不要との警告でした。コンストラクタの定義を削除します。

f:id:ksby:20180917233413p:plain

It is a good practice to call super() in a constructor

継承クラスのコンストラクタで super(); を呼び出していないという警告でした。super(); の呼び出しを追加します。

A method/constructor should not explicitly throw java.lang.Exception

メソッドに throws Exception を付けているとこの警告が出ていました。メソッドに付けている throws Exception を削除し、もしメソッド内から呼び出しているメソッドに throws Exception が付いていて削除できない場合には、メソッドに @SuppressWarnings("PMD.SignatureDeclareThrowsException") を付けて警告が出ないようにします。

The constant name 'serialVersionUID' doesn't match '[A-Z][A-Z_0-9]*'

private static final long serialVersionUID = ...static final が付いているので定数と判断されたが、英大文字/数字+スネークケースでないので警告が出ていました。serialVersionUID はこういう宣言だと思うので警告出さなくてもいいと思うのですが。。。 @SuppressWarnings("PMD.FieldNamingConventions") を付けて警告が出ないようにします。

Useless parentheses.

不要なカッコが書かれているという警告でした。この警告は不要なので、config/pmd/pmd-project-rulesets.xml を以下のように変更します。

    <rule ref="category/java/codestyle.xml">
        <exclude name="AtLeastOneConstructor"/>
        <exclude name="ClassNamingConventions"/>
        <exclude name="CommentDefaultAccessModifier"/>
        <exclude name="DefaultPackage"/>
        <exclude name="LongVariable"/>
        <exclude name="LocalVariableCouldBeFinal"/>
        <exclude name="MethodArgumentCouldBeFinal"/>
        <exclude name="OnlyOneReturn"/>
        <exclude name="ShortVariable"/>
        <exclude name="UnnecessaryAnnotationValueElement"/>
        <exclude name="UselessParentheses"/>
        <exclude name="VariableNamingConventions"/>
    </rule>
  • <exclude name="UselessParentheses"/> を追加します。

Document empty constructor

コンストラクタをオーバーロードしている時に、中身が空でコメントも書かれていないものがあると出る警告でした。// This constructor is intentionally empty. Nothing special is needed here. というコメントを記述して警告が出ないようにします。

There is log block not surrounded by if

logger.info("★★★ リトライ回数 = " + context.getRetryCount()); のようにlogger で変数を出力する時に {} を使わずに + で結合しているために警告が出ていました。logger.info("★★★ リトライ回数 = {}", context.getRetryCount()); という書き方に変更します。

Avoid short class names like ...

クラス名が短い(デフォルトでは5文字以内)と出る警告でした。この警告は不要なので、config/pmd/pmd-project-rulesets.xml を以下のように変更します。

    <rule ref="category/java/codestyle.xml">
        <exclude name="AtLeastOneConstructor"/>
        <exclude name="ClassNamingConventions"/>
        <exclude name="CommentDefaultAccessModifier"/>
        <exclude name="DefaultPackage"/>
        <exclude name="LongVariable"/>
        <exclude name="LocalVariableCouldBeFinal"/>
        <exclude name="MethodArgumentCouldBeFinal"/>
        <exclude name="OnlyOneReturn"/>
        <exclude name="ShortClassName"/>
        <exclude name="ShortVariable"/>
        <exclude name="UnnecessaryAnnotationValueElement"/>
        <exclude name="UselessParentheses"/>
        <exclude name="VariableNamingConventions"/>
    </rule>
  • <exclude name="ShortClassName"/> を追加します。

Avoid using Literals in Conditional Statements

メソッドの処理内に数値リテラルを直接記述していたので警告が出ていました。定数を定義して、数値リテラルと置き換えます。

Avoid instantiating new objects inside loops

ループ処理内で new でオブジェクトを生成していたので警告が出ていました。@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") を付けるか、ループの外で生成したオブジェクトをループ内で使い回すように変更します。

Prefer StringBuilder (non-synchronized) or StringBuffer (synchronized) over += for concatenating strings

+= を使用しているところを StringBuilder か StringBuffer に置き換えるように出た警告でした。StringBuilder を使用するよう変更します。

Assigning an Object to null is a code smell. Consider refactoring.

変数宣言時以外の場所で変数に null をセットしていると出る警告でした。直接 null をセットしないよう実装を変えるようにします。

Avoid using redundant field initializer for 'errcode'

int の変数を宣言した時に 0 をセットしていたのですが、default の初期値なので警告が出ていました。セットしないようにします。

Avoid catching generic exceptions such as NullPointerException, RuntimeException, Exception in try-catch block

catch (Exception e) { ... } を記述していると出る警告でした。使用している外部ライブラリが Exception を throw するため変更も削除もできないので、`` を付けて警告が出ないようにします。

最後に

これで全ての警告に対応しました。clean タスク実行 → Rebuild Project 実行 → build タスクを実行すると BUILD SUCCESSFUL の文字が出力されます。

f:id:ksby:20180921004029p:plain

config/pmd/pmd-project-rulesets.xml は以下のようになりました。

<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="mybraces"
         xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
    <description>project rulesets</description>

    <!--
        rulesets の種類・説明は 以下の URL 参照
        https://github.com/pmd/pmd/tree/master/pmd-java/src/main/resources/category/java
        https://github.com/pmd/pmd/tree/master/pmd-java/src/main/resources/rulesets/java
        https://pmd.github.io/pmd-6.7.0/pmd_rules_java.html
        ※"pmd-6.7.0" の部分は適用しているバージョンに変更すること。
    -->
    <rule ref="category/java/bestpractices.xml"/>
    <rule ref="category/java/codestyle.xml">
        <exclude name="AtLeastOneConstructor"/>
        <exclude name="ClassNamingConventions"/>
        <exclude name="CommentDefaultAccessModifier"/>
        <exclude name="DefaultPackage"/>
        <exclude name="LocalVariableCouldBeFinal"/>
        <exclude name="LongVariable"/>
        <exclude name="MethodArgumentCouldBeFinal"/>
        <exclude name="OnlyOneReturn"/>
        <exclude name="ShortClassName"/>
        <exclude name="ShortVariable"/>
        <exclude name="UnnecessaryAnnotationValueElement"/>
        <exclude name="UselessParentheses"/>
        <exclude name="VariableNamingConventions"/>
    </rule>
    <rule ref="category/java/design.xml">
        <exclude name="AvoidThrowingRawExceptionTypes"/>
        <exclude name="CyclomaticComplexity"/>
        <exclude name="DataClass"/>
        <exclude name="LawOfDemeter"/>
        <exclude name="LoosePackageCoupling"/>
        <exclude name="NcssCount"/>
        <exclude name="TooManyMethods"/>
        <exclude name="UseObjectForClearerAPI"/>
        <exclude name="UseUtilityClass"/>
    </rule>
    <rule ref="category/java/documentation.xml">
        <!-- CommentRequired はここでは exclude し、下で別途定義する -->
        <exclude name="CommentRequired"/>
        <exclude name="CommentSize"/>
        <exclude name="UncommentedEmptyMethodBody"/>
    </rule>
    <rule ref="category/java/documentation.xml/CommentRequired">
        <properties>
            <property name="fieldCommentRequirement" value="Ignored"/>
            <property name="enumCommentRequirement" value="Ignored"/>
        </properties>
    </rule>
    <rule ref="category/java/errorprone.xml">
        <exclude name="BeanMembersShouldSerialize"/>
        <exclude name="DataflowAnomalyAnalysis"/>
        <exclude name="LoggerIsNotStaticFinal"/>
        <exclude name="MissingStaticMethodInNonInstantiatableClass"/>
    </rule>
    <rule ref="category/java/multithreading.xml">
        <exclude name="UseConcurrentHashMap"/>
    </rule>
    <rule ref="category/java/performance.xml"/>
    <rule ref="category/java/security.xml"/>
</ruleset>

履歴

2018/09/21
初版発行。