PMD JavaルールーCode Style

PMDのJavaルールについてまとめます。バージョン6.35.0時のルールとなっています。
非推奨となっているルールには「△」を先頭に付与しています。

Best Practiceカテゴリのまとめはこちら: olafnosuke.hatenablog.com

Code Styleカテゴリには、特定のコーディングスタイルを強制するルールが含まれている。

AbstractNaming

非推奨のため省略


AtLeastOneConstructor

クラスの中で少なくとも1つのコンストラクタが宣言されているか

// NG
public class Sample {
    static void doSomething() {
    }
}

// OK
public class Sample {
    public Sample(){
    }
    
    static void doSomething() {
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoredAnnotations lombok.Data| lombok.Value| lombok.Builder| lombok.NoArgsConstructor| lombok.RequiredArgsConstructor| lombok.AllArgsConstructor このルールで無視するアノテーションの完全修飾名 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/AtLeastOneConstructor" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/AtLeastOneConstructor">
    <properties>
        <property name="ignoredAnnotations" value="lombok.Data|lombok.Value|lombok.Builder|lombok.NoArgsConstructor|lombok.RequiredArgsConstructor|lombok.AllArgsConstructor" />
    </properties>
</rule>

AvoidDollarSigns

メソッド名、クラス名、変数名に$が含まれていない

// NG
String doller$ = "aaa";

ルール設定例

<rule ref="category/java/codestyle.xml/AvoidDollarSigns" />

AvoidFinalLocalVariable

非推奨のため省略


AvoidPrefixingMethodParameters

非推奨のため省略


AvoidProtectedFieldInFinalClass

finalクラスでprotectedフィールドが宣言されていないか
privateかパッケージプライベートにする

// NG
public final class Sample {
    protected int y;
}

ルール設定例

<rule ref="category/java/codestyle.xml/AvoidProtectedFieldInFinalClass" />

AvoidProtectedMethodInFinalClassNotExtending

finalクラスでprotectedメソッドが定義されていないか
privateかパッケージプライベートにする

// NG
public final class Sample {
    protected void doSomething() {
    }
}

ルール設定例

<rule ref="category/java/codestyle.xml/AvoidProtectedMethodInFinalClassNotExtending" />

AvoidUsingNativeCode

ネイティブコードの使用を避ける

// NG
void doSomething() {
    System.loadLibrary("nativelib");
}

ルール設定例

<rule ref="category/java/codestyle.xml/AvoidUsingNativeCode" />

BooleanGetMethodName

booleanのgetterのメソッド名にgetを使用しない

// NG
public class Sample {
    private boolean select;

    public boolean getSelect() {
        return select;
    }
}

// OK
public class Sample {
    private boolean select;

    public boolean isSelect() {
        return select;
    }
    
    public boolean getSelect(boolean bar){ // checkParameterizedMethodsをtrueにした場合はNGになる
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
checkParameterizedMethods false パラメーター化されたメソッドをチェックする -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/BooleanGetMethodName" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/BooleanGetMethodName">
    <properties>
        <property name="checkParameterizedMethods" value="false" />
    </properties>
</rule>

CallSuperInConstructor

継承しているクラスでコンストラクタでsuper()もしくは別のコンストラクタが呼ばれていること
呼ばないとコンパイルエラーになる。

// NG
public class Sample extends Parent {
    public Sample (){
    }
}

// OK
public class Sample extends Parent {
    public Sample (){
        super();
    }
}

ルール設定例

<rule ref="category/java/codestyle.xml/CallSuperInConstructor" />

ClassNamingConventions

クラスの命名規則を守っているか
デフォルトでは、クラスが大文字始まりであることと、ユーティリティクラスは*Utilで終わることをチェックしている。

// NG
public class sample {
}

public class Myclass {

    private Myclass() {
    }

    public static void doSomething() {
    }
}

// OK
public class Sample {
}

public class MyclassUtil {

    private MyclassUtil() {
    }

    public static void doSomething() {
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
classPattern [AZ][a-zA-Z0-9]* クラス名に適用される正規表現 -
abstractClassPattern [AZ][a-zA-Z0-9]* 抽象クラス名に適用される正規表現 -
interfacePattern [AZ][a-zA-Z0-9]* インターフェイス名に適用される正規表現 -
enumPattern [AZ][a-zA-Z0-9]* enumに適用される正規表現 -
annotationPattern [AZ][a-zA-Z0-9]* アノテーションに適用される正規表現 -
utilityClassPattern [AZ][a-zA-Z0-9]+(Utils?|Helper|Constants) ユーティリティクラス名に適用される正規表現 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/ClassNamingConventions" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/ClassNamingConventions">
    <properties>
        <property name="classPattern" value="[A-Z][a-zA-Z0-9]*" />
        <property name="abstractClassPattern" value="[A-Z][a-zA-Z0-9]*" />
        <property name="interfacePattern" value="[A-Z][a-zA-Z0-9]*" />
        <property name="enumPattern" value="[A-Z][a-zA-Z0-9]*" />
        <property name="annotationPattern" value="[A-Z][a-zA-Z0-9]*" />
        <property name="utilityClassPattern" value="[A-Z][a-zA-Z0-9]+(Utils?|Helper|Constants)" />
    </properties>
</rule>

CommentDefaultAccessModifier

パッケージプライベートなアノテーション、クラス、enum、メソッド、コンストラクタ、フィールドの宣言の最初にコメントを追加するべき
追加するコメントはデフォルトで/* default */もしくは/* package */である必要がある

// NG
public class Sample {
    void doSomething() {
    }
}

// OK
public class Sample {
    /* default */ void doSomething() {
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoredAnnotations com.google.common.annotations.VisibleForTesting| android.support.annotation.VisibleForTesting このルールで無視するアノテーションの完全修飾名 「|」区切り
regex \/*\s+(default|package)\s+*\/ 正規表現 -
checkTopLevelTypes false トップレベルのクラス、アノテーション、および列挙型のデフォルトのアクセス修飾子を確認する -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/CommentDefaultAccessModifier" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/CommentDefaultAccessModifier">
    <properties>
        <property name="ignoredAnnotations" value="com.google.common.annotations.VisibleForTesting|android.support.annotation.VisibleForTesting" />
        <property name="regex" value="\/\*\s+(default|package)\s+\*\/" />
        <property name="checkTopLevelTypes" value="false" />
    </properties>
</rule>

ConfusingTernary

if~elseの条件式内で否定は使わない

// NG
void doSomething() {
    boolean a = true;
    boolean b = false;

    if (a != b) {
        // 処理A
    } else {
        // 処理B
    }
}

// OK
void doSomething() {
    boolean a = true;
    boolean b = false;

    if (a == b) {
        // 処理B
    } else {
        // 処理A
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoreElseIf false else-ifの場合条件を無視する -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/ConfusingTernary" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/ConfusingTernary">
    <properties>
        <property name="ignoreElseIf" value="false" />
    </properties>
</rule>

ControlStatementBraces

for, while, if, if~elseで{}をつける

// NG
void doSomething() {
    int i = 1;

    if (i == 1)
       i++;
}

// OK
void doSomething() {
    int i = 1;

    if (i == 1){
       i++;
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
checkIfElseStmt true if~elseで中括弧を使用する -
checkSingleIfStmt true 単一のif文で中括弧を使用する -
checkWhileStmt true whileループで中括弧を使用する -
checkForStmt true forループは中括弧を使用する -
checkDoWhileStmt true do…whileループで中括弧を使用する -
checkCaseStmt false スイッチのケースで中括弧を使用する -
allowEmptyLoop false while(true);などの空のステートメントでのループを許可する -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/ControlStatementBraces" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/ControlStatementBraces">
    <properties>
        <property name="checkIfElseStmt" value="true" />
        <property name="checkSingleIfStmt" value="true" />
        <property name="checkWhileStmt" value="true" />
        <property name="checkForStmt" value="true" />
        <property name="checkDoWhileStmt" value="true" />
        <property name="checkCaseStmt" value="false" />
        <property name="allowEmptyLoop" value="false" />
    </properties>
</rule>

DefaultPackage

非推奨のため省略


DontImportJavaLang

非推奨のため省略


DuplicateImports

非推奨のため省略


EmptyMethodInAbstractClassShouldBeAbstract

抽象クラスの空または自動生成されたメソッドにはabstractメソッドにするべき

// NG
public abstract class Sample {
    /* default */ void doSomething() {
    }
}

// OK
public abstract class Sample {
    /* default */ abstract void doSomething();
}

ルール設定例

<rule ref="category/java/codestyle.xml/EmptyMethodInAbstractClassShouldBeAbstract" />

ExtendsObject

Objectを明示的に継承しない

// NG
public  class Sample extends Object {
}

// OK
public  class Sample {
}

ルール設定例

<rule ref="category/java/codestyle.xml/ExtendsObject" />

FieldDeclarationsShouldBeAtStartOfClass

フィールドの宣言はクラスの一番頭の部分で行う

// NG
public class Sample {
    public void doSomething() {
    }

    public String str;
}

// OK
public class Sample {
    public String str;
    
    public void doSomething() {
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoreEnumDeclarations true フィールドの前にあるenum宣言を無視する -
ignoreAnonymousClassDeclarations true 匿名クラス宣言で初期化されるフィールド宣言を無視する -
ignoreInterfaceDeclarations false フィールドの前にあるインターフェイス宣言を無視する -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/FieldDeclarationsShouldBeAtStartOfClass" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/FieldDeclarationsShouldBeAtStartOfClass">
    <properties>
        <property name="ignoreEnumDeclarations" value="true" />
        <property name="ignoreAnonymousClassDeclarations" value="true" />
        <property name="ignoreInterfaceDeclarations" value="false" />
    </properties>
</rule>

FieldNamingConventions

フィールド名の命名規則を守っているか
デフォルトではJava標準の命名規則(キャメルケース)を使用。定数、enumはALL_UPPER 規則を使用。

// NG
public class Sample {
    public String first_name;

    public static final String MyName = "Bob";
}

// OK
public class Sample {

    public String firstName;

    public static final String MY_NAME = "Bob";

    public void doSomething() {
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
publicConstantPattern [AZ][A-Z_0-9]* パブリック定数名に適用される正規表現 -
constantPattern [AZ][A-Z_0-9]* 定数名に適用される正規表現 -
enumConstantPattern [AZ][A-Z_0-9]* enum定数名に適用される正規表現 -
finalFieldPattern [AZ][A-Z_0-9]* finalフィールド名に適用される正規表現 -
staticFieldPattern [AZ][A-Z_0-9]* staticフィールド名に適用される正規表現 -
defaultFieldPattern [AZ][A-Z_0-9]* 静的フィールド名に適用される正規表現 -
exclusions serialVersionUID| serialPersistentFields 除外対象のフィールドの名前。 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/FieldNamingConventions" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/FieldNamingConventions">
    <properties>
        <property name="publicConstantPattern" value="[A-Z][A-Z_0-9]*" />
        <property name="constantPattern" value="[A-Z][A-Z_0-9]*" />
        <property name="enumConstantPattern" value="[A-Z][A-Z_0-9]*" />
        <property name="finalFieldPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="staticFieldPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="defaultFieldPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="exclusions" value="serialVersionUID|serialPersistentFields" />
    </properties>
</rule>

ForLoopShouldBeWhileLoop

whileでも実現可能なforループがないか

// NG
public void doSomething() {
    for (; true;) {
    }
}

// OK
public void doSomething() {
    while (true) {
    }
}

ルール設定例

<rule ref="category/java/codestyle.xml/ForLoopShouldBeWhileLoop" />

ForLoopsMustUseBraces

非推奨のため省略


FormalParameterNamingConventions

メソッドやラムダ式で仮引数名の命名規則を守っているか
デフォルトではJava標準の命名規則(キャメルケース)を使用。

// NG
public void doSomething(String your_name) {
    Consumer<String> lambda = my_name -> {
    };
}

// OK
public void doSomething(String yourName) {
    Consumer<String> lambda = myName -> {
    };
}

プロパティ

名前 デフォルト値 説明 複数指定
methodParameterPattern [az][a-zA-Z0-9]* 仮引数名に適用する正規表現 -
finalMethodParameterPattern [az][a-zA-Z0-9]* finalな仮引数名に適用する正規表現 -
lambdaParameterPattern [az][a-zA-Z0-9]* ラムダ式の引数名に適用する正規表現 -
explicitLambdaParameterPattern [az][a-zA-Z0-9]* ラムダ式で明示的に型付けされた引数名に適用する正規表現 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/FormalParameterNamingConventions" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/FormalParameterNamingConventions">
    <properties>
        <property name="methodParameterPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="finalMethodParameterPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="lambdaParameterPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="explicitLambdaParameterPattern" value="[a-z][a-zA-Z0-9]*" />
    </properties>
</rule>

GenericsNaming

一般的な型パラメータの参照名は英語大文字1文字にするべき

// NG
public class Sample<t extends Book> {
}
public class Sample<TA extends Book> {
}

// OK
public class Sample<T extends Book> {
}

ルール設定例

<rule ref="category/java/codestyle.xml/GenericsNaming" />

IdenticalCatchBranches

同一の処理を行うキャッチ節を複数書かない

// NG
public void doSomething() {
    try {
    } catch (IllegalArgumentException e) {
        throw e;
    } catch (IllegalStateException e) {
        throw e;
    } catch (NullPointerException e) {
        throw e;
    }
}

// OK
public void doSomething() {
    try {
    } catch (IllegalArgumentException | IllegalStateException | NullPointerException e) {
        throw e;
    } 
}

ルール設定例

<rule ref="category/java/codestyle.xml/IdenticalCatchBranches" />

IfElseStmtsMustUseBraces

非推奨のため省略


IfStmtsMustUseBraces

非推奨のため省略


LinguisticNaming

変数名、メソッド名と型に不和がないか
boolean値を持ちそうな名前の変数がbooleanでなかったり、booleanを返しそうなメソッドなのに違う型を返すメソッドを検出する。
getterが戻り値があってsetterに戻り値がないことも確認する。

// NG
public class Sample {
    int isSelected;

    public int isExist() {
        return 1;
    }

    public String setName() {
        return "";
    }

    public void getName() {

    }
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoredAnnotations java.lang.Override このルールで無視するアノテーションの完全修飾名 「|」区切り
checkBooleanMethod true メソッド名と型に一貫性のない名前がないか確認するか -
checkGetters true getterの戻り型を確認するか -
checkSetters true setterの戻り型を確認するか -
checkPrefixedTransformMethods true 指定されたプレフィックスで始まる名前のメソッドの戻り型を確認するか -
checkTransformMethods false 指定されたインフィックスを含むメソッドの戻り型を確認するか -
booleanMethodPrefixes is| has| can| have| will| should booleanを返すメソッドのプレフィックス 「|」区切り
transformMethodNames to|as 変換メソッドを示すプレフィックスとインフィックス 「|」区切り
checkFields true フィールド名と型に一貫性のない名前がないか確認する -
checkVariables true ローカル変数の名前と型に一貫性のない名前がないか確認する -
booleanFieldPrefixes is| has| can| have| will| should booleanを示すフィールドと変数のプレフィックス 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/LinguisticNaming" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/LinguisticNaming">
    <properties>
        <property name="ignoredAnnotations" value="java.lang.Override" />
        <property name="checkBooleanMethod" value="true" />
        <property name="checkGetters" value="true" />
        <property name="checkSetters" value="true" />
        <property name="checkPrefixedTransformMethods" value="true" />
        <property name="checkTransformMethods" value="false" />
        <property name="booleanMethodPrefixes" value="is|has|can|have|will|should" />
        <property name="transformMethodNames" value="to|as" />
        <property name="checkFields" value="true" />
        <property name="checkVariables" value="true" />
        <property name="booleanFieldPrefixes" value="is|has|can|have|will|should" />
    </properties>
</rule>

LocalHomeNamingConvention

javax.ejb.EJBLocalHomeを継承したインターフェースにはLocalHomeという接尾辞をつける必要がある

// NG
public interface MissingProperSuffix extends javax.ejb.EJBLocalHome {
}

// OK
public interface MyBeautifulLocalHome extends javax.ejb.EJBLocalHome {
}

ルール設定例

<rule ref="category/java/codestyle.xml/LocalHomeNamingConvention" />

LocalInterfaceSessionNamingConvention

javax.ejb.EJBLocalObjectを継承したインターフェースにはLocalという接尾辞をつける必要がある

// NG
public interface MissingProperSuffix extends javax.ejb.EJBLocalObject {
} 

// OK
public interface MyLocal extends javax.ejb.EJBLocalObject {
}

ルール設定例

<rule ref="category/java/codestyle.xml/LocalInterfaceSessionNamingConvention" />

LocalVariableCouldBeFinal

一度しか使われていないローカル変数名がfinalで宣言されているか

// NG
public void doSomething() {
    String str = "str";
    System.out.println(str);
}

// OK
public void doSomething() {
    final String str = "str";
    System.out.println(str);
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoreForEachDecl false for-eachでfinalでないループ変数を無視するか 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/LocalVariableCouldBeFinal" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/LocalVariableCouldBeFinal">
    <properties>
        <property name="ignoreForEachDecl" value="false" />
    </properties>
</rule>

LocalVariableNamingConventions

ローカル変数の命名規則を守っているか
デフォルトではJava標準の命名規則(キャメルケース)を使用。

// NG
public void doSomething() {
    String my_name = "Bob";
}

// OK
public void doSomething() {
    String myName = "Bob Bob";
}

プロパティ

名前 デフォルト値 説明 複数指定
localVarPattern [az][a-zA-Z0-9]* finalでないローカル変数に適用される正規表現 -
finalVarPattern [az][a-zA-Z0-9]* finalローカル変数に適用される正規表現 -
catchParameterPattern [az][a-zA-Z0-9]* 例外ブロックのパラメータ名に適用される正規表現 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/LocalVariableNamingConventions" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/LocalVariableNamingConventions">
    <properties>
        <property name="localVarPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="finalVarPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="catchParameterPattern" value="[a-z][a-zA-Z0-9]*" />
    </properties>
</rule>

LongVariable

変数名が長すぎないか
デフォルトでは17を超えると検出される

// NG
public class Sample {

    public int tameshinitsuketaNagaiNamae;

    public void doSomething(String yourFirstNameAndLastName) {
        String myFirstNameAndLastName = "Bob";
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
minimum 17 変数名の最大値 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/LongVariable" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/LongVariable">
    <properties>
        <property name="minimum" value="17" />
    </properties>
</rule>

MDBAndSessionBeanNamingConvention

MessageDrivenBeanもしくはSessionBeanの実装クラスはBeanという接尾辞をつける必要がある

// NG
public class MissingTheProperSuffix implements SessionBean {
}

// OK
public class SomeBean implements SessionBean{
}

ルール設定例

<rule ref="category/java/codestyle.xml/MDBAndSessionBeanNamingConvention" />

MethodArgumentCouldBeFinal

メソッド内で再割り当てされないメソッド引数はfinalで宣言する

// NG
public void doSomething(String yourName) {
    System.out.println(yourName);
}

// OK
public void doSomething(final String yourName) {
    System.out.println(yourName);
}

ルール設定例

<rule ref="category/java/codestyle.xml/MethodArgumentCouldBeFinal" />

MethodNamingConventions

メソッドの命名規則を守っているか
デフォルトではJava標準の命名規則(キャメルケース)を使用。

// NG
public class Sample {
    public void do_something() {
    }

    public void DoSomething() {
    }
}

// OK
public class Sample {
    public void doSomething() {
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
methodPattern [az][a-zA-Z0-9]* メソッド名に適用される正規表現 -
staticPattern [az][a-zA-Z0-9]* staticメソッド名に適用される正規表現 -
nativePattern [az][a-zA-Z0-9]* ネイティブメソッド名に適用される正規表現 -
junit3TestPattern test[az][a-zA-Z0-9]* Junit3のテストメソッド名に適用される正規表現 -
junit4TestPattern [az][a-zA-Z0-9]* Junit4のテストメソッド名に適用される正規表現 -
junit5TestPattern [az][a-zA-Z0-9]* Junit5のテストメソッド名に適用される正規表現 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/MethodNamingConventions" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/MethodNamingConventions">
    <properties>
        <property name="methodPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="staticPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="nativePattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="junit3TestPattern" value="test[A-Z0-9][a-zA-Z0-9]*" />
        <property name="junit4TestPattern" value="[a-z][a-zA-Z0-9]*" />
        <property name="junit5TestPattern" value="[a-z][a-zA-Z0-9]*" />
    </properties>
</rule>

MIsLeadingVariableName

非推奨のため省略


NoPackage

パッケージのないクラス、インターフェース、enumアノテーションがないか

// NG

public class MyClass {
}

// OK
package jp.co.sample;

public class MyClass {
}

ルール設定例

<rule ref="category/java/codestyle.xml/NoPackage" />

OnlyOneReturn

メソッドの最後以外にreturnを書かない

// NG
public boolean doSomething() {
     int i = 3;

     if (i < 3) {
         return false;
     }
     return true;
}

ルール設定例

<rule ref="category/java/codestyle.xml/OnlyOneReturn" />

PackageCase

パッケージに大文字は書かない

// NG
package jp.co.Sample;

// OK
package jp.co.sample;

ルール設定例

<rule ref="category/java/codestyle.xml/PackageCase" />

PrematureDeclaration

ローカル変数の宣言が早いところがないか

// NG
public int doSome(int number) {
    int count = 0;

    if (number == 3) {
        return 3;
    }

    if (number != 3) {
        count += number;
    }
    return count;
}

// OK
public int doSome(int number) {
    if (number == 3) {
        return 3;
    }

    int count = 0;
    if (number != 3) {
        count += number;
    }
    return count;
}

ルール設定例

<rule ref="category/java/codestyle.xml/PrematureDeclaration" />

RemoteInterfaceNamingConvention

EJBObjectを継承したインターフェイス名はSessionEJBBeanをつけない

// NG
public interface BadSuffixSession extends javax.ejb.EJBObject {
}
public interface BadSuffixEJB extends javax.ejb.EJBObject {
}
public interface BadSuffixBean extends javax.ejb.EJBObject {
}

ルール設定例

<rule ref="category/java/codestyle.xml/RemoteInterfaceNamingConvention" />

RemoteSessionInterfaceNamingConvention

EJBHome を継承したインターフェイス名はHomeで終わるようにする

// NG
public interface MissingProperSuffix extends javax.ejb.EJBHome {
} 

// OK
public interface MyBeautifulHome extends javax.ejb.EJBHome {
} 

ルール設定例

<rule ref="category/java/codestyle.xml/RemoteSessionInterfaceNamingConvention" />

ShortClassName

クラス名が短すぎる
デフォルトでは5文字未満のクラス名が検出される

// NG
public class Book {
}

// OK
public class Animal {
}

プロパティ

名前 デフォルト値 説明 複数指定
minimum 5 クラス名の最小文字数 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/ShortClassName" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/ShortClassName">
    <properties>
        <property name="minimum" value="5" />
    </properties>
</rule>

ShortMethodName

メソッド名が短すぎる
デフォルトでは3文字未満のメソッド名が検出される

// NG
public void a() {
}

// OK
public void send() {
}

プロパティ

名前 デフォルト値 説明 複数指定
minimum 3 メソッド名の最小文字数 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/ShortMethodName" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/ShortMethodName">
    <properties>
        <property name="minimum" value="3" />
    </properties>
</rule>

ShortVariable

変数名が短すぎる
デフォルトでは3文字未満の変数名が検出される

// NG
public void doSomething() {
     int i = 3;
}

// OK
public void doSomething() {
     int count = 3;
}

プロパティ

名前 デフォルト値 説明 複数指定
minimum 3 変数名の最小文字数 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/ShortVariable" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/ShortVariable">
    <properties>
        <property name="minimum" value="3" />
    </properties>
</rule>

SuspiciousConstantFieldName

非推奨のため省略


TooManyStaticImports

static インポートが多すぎる
デフォルトでは5個以上で検知される

// NG
import static Lennon;
import static Ringo;
import static George;
import static Paul;
import static Yoko;

プロパティ

名前 デフォルト値 説明 複数指定
maximumStaticImports 4 許容するstaticインポートの数。 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/TooManyStaticImports" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/TooManyStaticImports">
    <properties>
        <property name="maximumStaticImports" value="4" />
    </properties>
</rule>

UnnecessaryAnnotationValueElement

アノテーションの属性が1つしかない場合にvalueを使用しない

// NG
@Max(value = 3)
private int age;

// OK
@Max(3)
private int age;

ルール設定例

<rule ref="category/java/codestyle.xml/UnnecessaryAnnotationValueElement" />

UnnecessaryCast

不必要なキャストをしていないか

// NG
public void doSomething() {
    List<String> list = List.of("abc", "bcd", "cde");
    String string = (String) list.get(0);
}

// OK
public void doSomething() {
    List<String> list = List.of("abc", "bcd", "cde");
    String string = list.get(0);
}

ルール設定例

<rule ref="category/java/codestyle.xml/UnnecessaryCast" />

UnnecessaryConstructor

不要なコンストラクタがないか
クラスにコンストラクタが1つで、デフォルトのコンストラクタと同じである場合

// NG
public class Sample {
    public Sample(){
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoredAnnotations javax.inject.Inject このルールで無視するアノテーションの完全修飾名 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/UnnecessaryConstructor" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/UnnecessaryConstructor">
    <properties>
        <property name="ignoredAnnotations" value="javax.inject.Inject" />
    </properties>
</rule>

UnnecessaryFullyQualifiedName

import文を追加することで完全修飾名を使用しなくてよくなる箇所はないか

// NG
public class Sample {
    private java.util.List list; 
}

// OK
import java.util.List;
public class Sample {
    private List list; 
}

ルール設定例

<rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName" />

UnnecessaryImport

使用していない不要なimport文はないか

// NG
import java.util.List;
import java.io.File; 
public class Sample {
    private List list; 
}

// OK
import java.util.List;
public class Sample {
    private List list; 
}

ルール設定例

<rule ref="category/java/codestyle.xml/UnnecessaryImport" />

UnnecessaryLocalBeforeReturn

returnする値を入れるだけの不要なローカル変数を生成していないか

// NG
public int execute() {
   int x = doSomething();
   return x;
}

// OK
public int execute() {
  return doSomething();
}

プロパティ

名前 デフォルト値 説明 複数指定
statementOrderMatters true falseの場合変数宣言とreturnが連続した行にある必要はなく、returnでのみ使用される変数は報告される -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn">
    <properties>
        <property name="statementOrderMatters" value="true" />
    </properties>
</rule>

UnnecessaryModifier

不要な修飾子をつけていないか
インターフェースやアノテーション内のフィールドは自動的にpublic static finalとなり、メソッドはpublic abstractとなるので書く必要ない

// NG
public interface Animal {
    public abstract void doSomething();
}

// OK
public interface Animal {
    void doSomething();
}

ルール設定例

<rule ref="category/java/codestyle.xml/UnnecessaryModifier" />

UnnecessaryReturn

不要なreturnを書かない

// NG
public void doSomething() {
    int count = 3;
    return;
}

// OK
public void doSomething() {
    int count = 3;
}

ルール設定例

<rule ref="category/java/codestyle.xml/UnnecessaryReturn" />

UseDiamondOperator

ダイアモンド演算子を使用する

// NG
List<String> list = new ArrayList<String>();

// OK
List<String> list = new ArrayList<>();

プロパティ

名前 デフォルト値 説明 複数指定
java7Compatibility false java7で使用する場合trueにする -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/UseDiamondOperator" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/UseDiamondOperator">
    <properties>
        <property name="java7Compatibility" value="false" />
    </properties>
</rule>

UselessParentheses

不要な括弧がないか

// NG
int count = (3);

// OK
int count = 3;

ルール設定例

<rule ref="category/java/codestyle.xml/UselessParentheses" />

UselessQualifiedThis

自分自身をさすときにクラス名から書かない

// NG
public class Sample {
    Sample sample = Sample.this;
}

// OK
public class Sample {
    Sample sample = this;
}

ルール設定例

<rule ref="category/java/codestyle.xml/UselessQualifiedThis" />

UseShortArrayInitializer

配列フィールドまたは変数を宣言および初期化する場合にnewを使用しない

// NG
int[] x = new int[] { 1, 2, 3 };

// OK
int[] x2 = { 1, 2, 3 };

ルール設定例

<rule ref="category/java/codestyle.xml/UseShortArrayInitializer" />

UseUnderscoresInNumericLiterals

桁数の多い数字の記述時にアンダースコアをつける
デフォルトでは5桁以上で3桁ごとにアンダースコアをつける必要がある

// NG
int number = 10000;

// OK
int number = 10_000;

プロパティ

名前 デフォルト値 説明 複数指定
acceptableDecimalLength 4 10進数の数値にアンダースコアが必要ない桁数 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/codestyle.xml/AtLeastOneConstructor" />

<!-- プロパティ設定あり -->
<rule ref="category/java/codestyle.xml/AtLeastOneConstructor">
    <properties>
        <property name="ignoredAnnotations" value="lombok.Data|lombok.Value|lombok.Builder|lombok.NoArgsConstructor|lombok.RequiredArgsConstructor|lombok.AllArgsConstructor" />
    </properties>
</rule>

VariableNamingConventions

非推奨のため省略


WhileLoopsMustUseBraces

非推奨のため省略

PMD JavaルールーBest Practices

PMDのJavaルールについてまとめます。バージョン6.35.0時のルールとなっています。
非推奨となっているルールには「△」を先頭に付与しています。

Code Styleカテゴリのまとめはこちら: olafnosuke.hatenablog.com

Best Practicesカテゴリには、一般に受け入れられているベストプラクティスを実施するルールが含まれている。

AbstractClassWithoutAbstractMethod

abstractクラスにabstractメソッドが記述されているか

// NG例
public abstract class Sample { // abstractメソッドも定義する

    public void doSomething() {
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod" />

△ AccessorClassGeneration

privateコンストラクタが呼び出されていないか
Java10までのルール。Java11では使えない。issue

ルール設定例

<rule ref="category/java/bestpractices.xml/AccessorClassGeneration" />

△ AccessorMethodGeneration

別のクラスからプライベート フィールド/メソッドにアクセスしていないか
Java10までのルール。Java11では使えない。issue

ルール設定例

<rule ref="category/java/bestpractices.xml/AccessorMethodGeneration" />

ArrayIsStoredDirectly

メソッドのパラメータに指定された配列をそのまま配列フィールドに設定していないか

// NG例
public class Sample {

    private String[] x;

    public void doSomething(String[] param) { // コピーした配列を設定するべき
        this.x = param;
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
allowPrivate true true の場合、privateメソッド/コンストラクターは配列をそのまま保存できるようにする -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/ArrayIsStoredDirectly" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/ArrayIsStoredDirectly">
    <properties>
        <property name="allowPrivate" value="true" />
    </properties>
</rule>

AvoidMessageDigestField

MessageDigestインスタンスをフィールドとして宣言していないか

// NG例
public class Sample {

    private final MessageDigest sharedMd;

    public Sample() throws Exception {
        sharedMd = MessageDigest.getInstance("SHA-256");
    }
}

// OK例
public class Sample {

    public byte[] doSomething(byte[] data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(data);
        return md.digest();
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/AvoidMessageDigestField" />

AvoidPrintStackTrace

printStackTrace()が使用されていないか

// NG例
void doSomething() {
    try {
    } catch (Exception e) {
        e.printStackTrace(); // ログ出力にするべき
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/AvoidPrintStackTrace" />

AvoidReassigningCatchVariables

キャッチ変数の再割り当てをしていないか

// NG例
void doSomething() {
    try {
    } catch (Exception e) {
        e = new IllegalArgumentException(); 
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/AvoidReassigningCatchVariables" />

AvoidReassigningLoopVariables

ループ変数の再割り当てをしていないか

// NG例
public class Sample {

    void doSomething() {
        for (int i = 0; i < 10; i++) {
            if (check(i)) {
                i++; 
            }

            i = 5; 
        }
    }

    boolean check(int i) {
        if (i > 5) {
            return true;
        } else {
            return false;
        }
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
foreachReassign deny foreach制御変数の再割り当ての方法と条件。
deny:ループ本体内のループ変数の再割り当てを検出
allow:ループ変数をチェックしない
firstOnly:ループ本体の最初の処理を除き、ループ変数の再割り当てを検出
-
forReassign deny どのようにして制御変数を再配置するか。
deny:ループ本体内の制御変数の再割り当てを検出
allow:制御変数をチェックしない
skip:条件付きインクリメント/デクリメント ( ++、--、+=、-=)を除く制御変数の再割り当てを検出
-

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/AvoidReassigningLoopVariables" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/AvoidReassigningLoopVariables">
    <properties>
        <property name="foreachReassign" value="deny" />
        <property name="forReassign" value="deny" />
    </properties>
</rule>

AvoidReassigningParameters

パラメーターの再割り当てをしていないか

// NG例
void doSomething(String s) {
    s = s.trim();
}

ルール設定例

<rule ref="category/java/bestpractices.xml/AvoidReassigningParameters" />

AvoidStringBufferField

StringBuffer 型のフィールドを検出

// NG例
public class Sample {
    private StringBuffer buffer;
}

ルール設定例

<rule ref="category/java/bestpractices.xml/AvoidStringBufferField" />

AvoidUsingHardCodedIP

ハードコードされた IP アドレスがないか

// NG例
public class Sample {
    private String ip = "127.0.0.1";
}

プロパティ

名前 デフォルト値 説明 複数指定
checkAddressTypes IPv4 mapped IPv6 | IPv6 | IPv4 IPアドレスの種類を確認する。 区切り文字「|」

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/AvoidUsingHardCodedIP" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/AvoidUsingHardCodedIP">
    <properties>
        <property name="checkAddressTypes" value="IPv4 mapped IPv6|IPv6|IPv4" />
    </properties>
</rule>

CheckResultSet

ResultSetのメソッド (next、previous、first、last) の戻り値を確認しているか

// NG例
void doSomething() throws SQLException {
    Connection conn = null;
    Statement stat = conn.createStatement();
    ResultSet rst = stat.executeQuery("SELECT name FROM person");
    rst.next();
    String firstName = rst.getString(1);
}

ルール設定例

<rule ref="category/java/bestpractices.xml/CheckResultSet" />

ConstantsInInterface

インターフェイスで定数を使用していないか

// NG例
public interface Animal {
    public static final int COUNT = 50;
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoreIfHasMethods true インターフェイスがメソッドを定義する場合、インターフェイスの定数を無視するかどうか -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/ConstantsInInterface" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/ConstantsInInterface">
    <properties>
        <property name="ignoreIfHasMethods" value="true" />
    </properties>
</rule>

DefaultLabelNotLastInSwitchStmt

switch文のdefaultが最後にあるか

// NG例
void doSomething() {
    int a = 3;
    switch (a) {
    case 1:
        break;
    default:
        break;
    case 2:
        break;
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/DefaultLabelNotLastInSwitchStmt" />

DoubleBraceInitialization

ダブルブレースイニシャライゼーション(二重括弧での初期化)をしていないか

// NG例
List<String> doSomething() {
    return new ArrayList<String>() {
        {
            add("a");
            add("b");
            add("c");
        }
    };
}

// OK例
List<String> doSomething() {
    List<String> a = new ArrayList<>();
    a.add("a");
    a.add("b");
    a.add("c");
    return a;
}

ルール設定例

<rule ref="category/java/bestpractices.xml/DoubleBraceInitialization" />

ForLoopCanBeForeach

foreach 構文で置き換えることができるループを検出

// NG例
void doSomething() {
    List<String> a = new ArrayList<>();
    a.add("a");
    a.add("b");
    a.add("c");

    for (int i = 0; i < a.size(); i++) { 
        System.out.println(a.get(i));
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/ForLoopCanBeForeach" />

ForLoopVariableCount

変数が2つ以上あるforループを使用していないか

// NG例
void doSomething() {
    for (int i = 0, j = 1; i < 5; i++, j += 2) { 
        System.out.println(i + j);
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
maximumVariables 1 for文に最大いくつの制御変数を許可するか -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/ForLoopVariableCount" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/ForLoopVariableCount">
    <properties>
        <property name="maximumVariables" value="1" />
    </properties>
</rule>

GuardLogStatement

ログレベルを使用する場合はログレベルが有効になっているかどうかを確認しているか

// NG例
log.debug("log something");

// OK例
if (log.isDebugEnabled()) {
    log.debug("log something");
}

プロパティ

名前 デフォルト値 説明 複数指定
logLevels trace, debug, info, warn, error, log, finest, finer, fine, info, warning, severe 確認するログレベル コンマ区切り
guardsMethods isTraceEnabled, isDebugEnabled, isInfoEnabled, isWarnEnabled, isErrorEnabled, isLoggable ログレベルを確認するメソッド コンマ区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/GuardLogStatement" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/GuardLogStatement">
    <properties>
        <property name="logLevels" value="trace,debug,info,warn,error,log,finest,finer,fine,info,warning,severe" />
        <property name="guardsMethods" value="isTraceEnabled,isDebugEnabled,isInfoEnabled,isWarnEnabled,isErrorEnabled,isLoggable" />
    </properties>
</rule>

JUnit4~はJUnit3→JUnit4でアノテーションベースになったことに対するチェック


JUnit4SuitesShouldUseSuiteAnnotation

suiteはアノテーション(@RunWith(Suite.class) )で示されているか

ルール設定例

<rule ref="category/java/bestpractices.xml/JUnit4SuitesShouldUseSuiteAnnotation" />

JUnit4TestShouldUseAfterAnnotation

テスト終了後に行う処理は@AfterEach、@AfterAllを付与したメソッドで行う

ルール設定例

<rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseAfterAnnotation" />

JUnit4TestShouldUseBeforeAnnotation

テスト終了後に行う処理は @BeforeEach 、@BeforeAll を付与したメソッドで行う

ルール設定例

<rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseBeforeAnnotation" />

JUnit4TestShouldUseTestAnnotation

テストメソッドにアノテーションを付与しているか

ルール設定例

<rule ref="category/java/bestpractices.xml/JUnit4TestShouldUseTestAnnotation" />

JUnit5TestShouldBePackagePrivate

パッケージプライベートではないJUnit 5テストクラスとメソッドを検出する

// NG例
@Test
public void test() {
}

// OK例
@Test
void test() {
}

ルール設定例

<rule ref="category/java/bestpractices.xml/JUnit5TestShouldBePackagePrivate" />

JUnitAssertionsShouldIncludeMessage

JUnit アサーションにメッセージを含めているか

// NG例
@Test
public void test() {
    assertEquals("foo", "bar");
}

// OK例
@Test
void test() {
    assertEquals("Foo does not equals bar", "foo", "bar");
}

ルール設定例

<rule ref="category/java/bestpractices.xml/JUnitAssertionsShouldIncludeMessage" />

JUnitTestContainsTooManyAsserts

アサーションを使いすぎていないか(2つ以上でNG)

// NG例
@Test
public void test() {
    assertEquals("Foo does not equals bar", "foo", "bar");
    assertEquals("Foo does not equals bar", "foo", "bar");
}

// OK例
@Test
void test() {
    assertEquals("Foo does not equals bar", "foo", "bar");
}

プロパティ

名前 デフォルト値 説明 複数指定
maximumAsserts 1 テスト メソッド内のアサートの最大数。 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/JUnitTestContainsTooManyAsserts" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/JUnitTestContainsTooManyAsserts">
    <properties>
        <property name="maximumAsserts" value="1" />
    </properties>
</rule>

JUnitTestsShouldIncludeAssert

テストメソッドに少なくとも1つのアサーションが含まれているか

// NG例
@Test
public void test() {
}

// OK例
@Test
void test() {
    assertEquals("Foo does not equals bar", "foo", "bar");
}

ルール設定例

<rule ref="category/java/bestpractices.xml/JUnitTestsShouldIncludeAssert" />

JUnitUseExpected

Junit4で例外のテストに @Test(expected) を使用する

ルール設定例

<rule ref="category/java/bestpractices.xml/JUnitUseExpected" />

LiteralsFirstInComparisons

文字列比較でリテラルを最初に配置しているか

// NG例
void doSomething() {
    String s = "";
    s.equals("a");
}

// OK例
void doSomething() {
    String s = "";
    "a".equals(s);
}

ルール設定例

<rule ref="category/java/bestpractices.xml/LiteralsFirstInComparisons" />

LooseCoupling

インターフェイス(例:Set)ではなく、実体クラス(例:HashSet)で宣言している箇所がないか

// NG例
public class Sample {
    ArrayList<String> list = new ArrayList<>();
}

// OK例
public class Sample {
    List<String> list = new ArrayList<>();
}

ルール設定例

<rule ref="category/java/bestpractices.xml/LooseCoupling" />

MethodReturnsInternalArray

配列フィールドをそのまま戻り値として返却していないか

// NG例
public class Sample {
    String[] s;
    
    String[] doSomething() {
        return s; // コピーした配列を返却するべき
    }    
}

ルール設定例

<rule ref="category/java/bestpractices.xml/MethodReturnsInternalArray" />

MissingOverride

オーバーライドされたメソッドに @Override をつけているか

// NG例
public class Sample {
    
    String toString() {
    }    
}

// OK例
public class Sample {
    @Override
    String toString() {
    }    
}

ルール設定例

<rule ref="category/java/bestpractices.xml/MissingOverride" />

OneDeclarationPerLine

同じタイプの複数の変数宣言を 1 行でしていないか

// NG例
public class Sample {
    String names, lastnames; 
}

// OK例
public class Sample {
    String name; 
    String lastname;

    String namea,
           lastnamea;
}

プロパティ

名前 デフォルト値 説明 複数指定
strictMode false true の場合、宣言が別々の行にある場合でも、結合された宣言をマークする。
OK例の一番下がNGになる。
-

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/OneDeclarationPerLine" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/OneDeclarationPerLine">
    <properties>
        <property name="strictMode" value="false" />
    </properties>
</rule>

△ PositionLiteralsFirstInCaseInsensitiveComparisons

非推奨のため省略


△ PositionLiteralsFirstInComparisons

非推奨のため省略


PreserveStackTrace

スタックトレースが捨てられていないか

// NG例
void doSomething() {
    try {
    } catch (Exception e) {
        throw new IllegalArgumentException(e.getMessage());
    }
}

// OK例
void doSomething() {
    try {
    } catch (Exception e) {
        throw new IllegalArgumentException(e);
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/PreserveStackTrace" />

ReplaceEnumerationWithIterator

Enumerationが使用されているか

// NG例
public class Sample implements Enumeration {
    @Override
    public boolean hasMoreElements() {
        return false;
    }

    @Override
    public Object nextElement() {
        return null;
    }
}

// OK例
public class Sample implements Iterator {
    @Override
    public boolean hasNext() {
        return false;
    }

    @Override
    public Object next() {
        return null;
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/ReplaceEnumerationWithIterator" />

ReplaceHashtableWithMap

Hashtableが使用されているか

// NG例
void doSomething() {
    Hashtable<String, String> h = new Hashtable<String, String>();
}

// OK例
void doSomething() {
    Map<String, String> h = new HashMap<String, String>();
}

ルール設定例

<rule ref="category/java/bestpractices.xml/ReplaceHashtableWithMap" />

ReplaceVectorWithList

Vectorが使用されているか

// NG例
void doSomething() {
    Vector<String> v = new Vector<String>();
}

// OK例
void doSomething() {
    List<String> l = new ArrayList<String>();
}

ルール設定例

<rule ref="category/java/bestpractices.xml/ReplaceVectorWithList" />

SwitchStmtsShouldHaveDefault

switch文にdefaultケースがあるか

// NG例
void doSomething() {
    int a = 3;
    switch (a) {
    case 1:
        break;
    case 2:
        break;
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/SwitchStmtsShouldHaveDefault" />

SystemPrintln

System.(out|err).print を使用しているか

// NG例
void doSomething() {
    System.out.println("qa"); //ログ出力にするべき
}

ルール設定例

<rule ref="category/java/bestpractices.xml/SystemPrintln" />

UnusedAssignment

変数が上書きされるかスコープ外になる前に使用されることのない変数がないか

public class Sample {

    private String f = "t";

    Sample(String f) {
        this.f = f;
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
checkUnusedPrefixIncrement false (i + 1) に置き換えられる可能性のある++iのような式を検出する。 -
reportUnusedVariables false 初期化されただけでまったく読み取られない変数を検出する。 -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/UnusedAssignment" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/UnusedAssignment">
    <properties>
        <property name="checkUnusedPrefixIncrement" value="false" />
        <property name="reportUnusedVariables" value="false" />
    </properties>
</rule>

UnusedFormalParameter

使用されていない引数がないか

// NG例
public class Sample {
    private void doSomething(int r) { //使用しないなら削除する

    }
}

プロパティ

名前 デフォルト値 説明 複数指定
checkAll false プライベートでないものを含むすべてのメソッドをチェックする -

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/UnusedFormalParameter" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/UnusedFormalParameter">
    <properties>
        <property name="checkAll" value="false" />
    </properties>
</rule>

△ UnusedImports

非推奨のため省略


UnusedLocalVariable

使用されていないローカル変数がないか

// NG例
public class Sample {
    void doSomething(String p) {
        String s = "a"; //使用しないなら削除する
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/UnusedLocalVariable" />

UnusedPrivateField

使用されていないプライベートフィールドがないか

// NG例
public class Sample {
    private String t = "t"; //使用しないなら削除する

    void doSomething(String p) {
        String s = "a";
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoredAnnotations lombok.Setter| lombok.Getter| lombok.Builder| lombok.Data| lombok.RequiredArgsConstructor| lombok.AllArgsConstructor| lombok.Value| lombok.NoArgsConstructor| java.lang.Deprecated| javafx.fxml.FXML| lombok.experimental.Delegate| lombok.EqualsAndHashCode このルールで無視する必要がある注釈タイプの完全修飾名。 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/UnusedPrivateField" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/UnusedPrivateField">
    <properties>
        <property name="ignoredAnnotations" value="lombok.Setter|lombok.Getter|lombok.Builder|lombok.Data|lombok.RequiredArgsConstructor|lombok.AllArgsConstructor|lombok.Value|lombok.NoArgsConstructor|java.lang.Deprecated|javafx.fxml.FXML|lombok.experimental.Delegate|lombok.EqualsAndHashCode" />
    </properties>
</rule>

UnusedPrivateMethod

使用されていないプライベートメソッドがないか

// NG例
public class Sample {
    void doSomething(String p) {
        String s = "a";
    }

    private void doSomething() { //使用しないなら削除する
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
ignoredAnnotations java.lang.Deprecated このルールで無視する必要がある注釈タイプの完全修飾名 「|」区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/UnusedPrivateMethod" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/UnusedPrivateMethod">
    <properties>
        <property name="ignoredAnnotations" value="java.lang.Deprecated" />
    </properties>
</rule>

UseAssertEqualsInsteadOfAssertTrue

assertTrueよりもassertEqualsがふさわしい検証はないか

// NG例
class SampleTest {

    @Test
    void test() {
        Sample s = new Sample();
        Sample s2 = new Sample();
        assertTrue(s.equals(s2));
    }
}

// OK例
class SampleTest {

    @Test
    void test() {
        Sample s = new Sample();
        Sample s2 = new Sample();
        assertEquals(s, s2);
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/UseAssertEqualsInsteadOfAssertTrue" />

UseAssertNullInsteadOfAssertTrue

assertTrueよりもassertNullがふさわしい検証はないか

// NG例
class SampleTest {

    @Test
    void test() {
        Sample s = new Sample();
        assertTrue(s == null);
    }
}

// OK例
class SampleTest {

    @Test
    void test() {
        Sample s = new Sample();
        assertNull(s);
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/UseAssertNullInsteadOfAssertTrue" />

UseAssertSameInsteadOfAssertTrue

assertTrueよりもassertSameがふさわしい検証はないか

// NG例
class SampleTest {

    @Test
    void test() {
        Sample s = new Sample();
        Sample s2 = new Sample();
        assertTrue(s == s2);
    }
}

// OK例
class SampleTest {

    @Test
    void test() {
        Sample s = new Sample();
        Sample s2 = new Sample();
        assertSame(s, s2);
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/UseAssertSameInsteadOfAssertTrue" />

UseAssertTrueInsteadOfAssertEquals

assertEqualsよりもassertTrueがふさわしい検証はないか

// NG例
class SampleTest {

    @Test
    void test() {
        boolean b = true;
        assertEquals(b, true);
    }
}

// OK例
class SampleTest {

    @Test
    void test() {
        boolean b = true;
        assertTrue(b);
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/UseAssertTrueInsteadOfAssertEquals" />

UseCollectionIsEmpty

コレクションが空であることを確認する時はisEmpty()を使用するべき

// NG例
public class Sample {

    void doSomething() {
        List<String> list = new ArrayList<String>();
        if (list.size() == 0) {
        }
    }
}

// OK例
public class Sample {

    void doSomething() {
        List<String> list = new ArrayList<String>();
        if (list.isEmpty()) {

        }
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/UseCollectionIsEmpty" />

UseStandardCharsets

一般的な Charset オブジェクトの定数を使用するべき

// NG例
public class Sample {

    void doSomething() {

        File file = new File("test");
        try (BufferedReader reader = new BufferedReader(new FileReader(file, Charset.forName("UTF-8")))) {
        } catch (Exception e) {
        }
    }
}

// OK例
public class Sample {

    void doSomething() {

        File file = new File("test");
        try (BufferedReader reader = new BufferedReader(new FileReader(file, StandardCharsets.UTF_8))) {
        } catch (Exception e) {
        }
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/UseStandardCharsets" />

UseTryWithResources

try-with-resources ステートメントを使用するべき

// NG例
public class Sample {

    void doSomething() {
        File file = new File("test");
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(file));
        } catch (Exception e) {
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                }
            }
        }
    }
}

// OK例
public class Sample {

    void doSomething() {
        File file = new File("test");
        try (BufferedReader reader = new BufferedReader(new FileReader(file)) {
        } catch (Exception e) {
        }
    }
}

プロパティ

名前 デフォルト値 説明 複数指定
allowPrivate close, closeQuietly このルールをトリガーする、finally ブロック内のメソッド名。 コンマ区切り

ルール設定例

<!-- プロパティ設定なし -->
<rule ref="category/java/bestpractices.xml/UseTryWithResources" />

<!-- プロパティ設定あり -->
<rule ref="category/java/bestpractices.xml/UseTryWithResources">
    <properties>
        <property name="closeMethods" value="close,closeQuietly" />
    </properties>
</rule>

UseVarargs

可変長引数の利用

// NG例
public class Sample {
    void doSomething(String s, int[] args) {
    }
}

// OK例
public class Sample {
    void doSomething(String s, int... args) {
    }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/UseVarargs" />

WhileLoopWithLiteralBoolean

true,falseが直書きされているwhile文はないか

// NG例
public class Sample {

    void doSomething() {
        while (true) {
            break;
        }
}

ルール設定例

<rule ref="category/java/bestpractices.xml/WhileLoopWithLiteralBoolean" />

SpringBootーControllerAdvice

ControllerAdviceとは?

ControllerAdviceとは、エラー処理などをコントローラーの共通処理としてまとめて定義するためのものである。

@Controllerを付与したクラスには、Handlerメソッド(@RequestMappingを付与したメソッド)とは別に、Controller専用の特殊なメソッド( @InitBinderメソッド、@ModelAttributeメソッド、@ExceptionHandlerメソッド )を実装することができる。

コントローラークラス内に定義した場合は、そのコントローラーのみに対して処理が適用されるが、これらのメソッドを複数のControllerクラスで共有したい場合は、@ControllerAdviceを付加したクラスに上記のメソッドを定義する。

@InitBinderメソッド

WebDataBinderオブジェクト(リクエストデータをJavaオブジェクトにバインドするためのオブジェクト)をカスタマイズするためのメソッド。 型変換、フォーマッティング、バリデーションなどをカスタマイズすることができる。

例えば、バインドするデータに対して両端の空白を削除するには以下のように記述する。

@ControllerAdvice
public class MyControllerAdvice {
    @InitBinder
    public void initBinder(WebDataBinder dataBinder) {
        dataBinder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
    }
}

@ModelAttributeメソッド

Modelにオブジェクトを格納するためのメソッド。 Handlerメソッド実行前に呼び出され、メソッドでなにか値を返却した場合は、返却したオブジェクトがModelに格納される。

MVCにおいて共通のデータを Model に設定したい場合に使用する。

@ControllerAdvice
public class MyControllerAdvice {
    @ModelAttribute
    public void setTimestamp(Model model) {
        model.add("timestamp", System.currentTimeMillis());
    }
}

@ExceptionHandlerメソッド

例外をハンドリングするためのメソッド。

@ExceptionHandlerは、コントローラーでスローされた特定の例外に対しての処理を定義する。 属性に処理対象の例外クラスを指定する。

  • @ExceptionHandlerの引数に指定した例外がスローされた場合にメソッドが実行される。
  • 引数に与える例外クラスは複数記述することができる。
  • 例外の親クラスを引数に設定した場合は、その例外クラスの子の例外が発生した場合も捕捉される。
    (例:引数にRuntimeException.classを指定時にNullPointerExceptionが発生しても例外処理メソッドが実行される)
@ControllerAdvice
public class MyControllerAdvice {
    @ExceptionHandler({ IllegalArgumentException.class })
    public String testExceptionHandle(IllegalArgumentException e, Model model) {
        String stackTrace = ExceptionUtils.getStackTrace(e);
        model.addAttribute("message0", e);
        model.addAttribute("message1", stackTrace);
        return "/exception/runtime";
    }
}

SpringでInterceptorを利用する(SpringBoot)

Interceptorとは?

Interceptorは、画面処理の前後とリクエストの一番最後に呼び出される割り込み処理のこと。
Interceptorを使うとControllerの実行前後に処理を追加することができる。

実装する場合には、org.springframework.web.servlet.HandlerInterceptorインターフェースを実装する。

public class SampleInterceptor implements HandlerInterceptor {
  //...
}

HandlerInterceptorには以下の3つのメソッドが定義されている。

preHandle

コントローラーの実行前の処理を定義する。
戻り値の型はboolean型でtrueであればコントローラーの処理を実行し、falseであればコントローラーの処理を実行せずに200のレスポンスを返却する。
引数のhandlerから実行されるコントローラーを取得する事ができる。

@Override
public boolean preHandle(HttpServletRequest request,
    HttpServletResponse response, Object handler) throws Exception {
  //...
  return true;
}

postHandle

コントローラーの実行後の処理を定義する。
MVCの場合はテンプレートエンジンによるレンダリングの前に実行される処理で、REST API の場合はレスポンス送信前の処理に実行される。
コントローラーの処理中に例外が発生した場合、このメソッドは実行されない。

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
    Object handler, @Nullable ModelAndView modelAndView) throws Exception {
  //...
}

afterCompletion

クライアントへレスポンスを送信した後の処理を定義する。
MVC の場合は、テンプレートエンジンによるレンダリングが完了してレスポンスを送信後に実行される。
exにはレンダリングで発生した例外が設定され、コントローラーでスローされた例外が設定されるわけではない。
コントローラーで例外がスローされても実行される。

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
    Object handler, @Nullable Exception ex) throws Exception {
  //...
}

Interceptorの定義方法

作成したインターセプターはDIコンテナへの登録と、SpringにInterceptorを追加したことを教えてあげる必要がある。

■ DIコンテナへの登録

@Configuration
public class BeanConfiguration {

    @Bean
    public SampleInterceptor sampleInterceptor() throws Exception{
        return new SampleInterceptor();
    }

}

■ インターセプターの追加

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    HandlerInterceptor sampleInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(displayIdInterceptor())
            // インターセプターの実行対象外とするURLを設定する
            // 設定していない場合は全てのURLが実行対象となる
            .excludePathPatterns("/images/**")
            // インターセプターの実行対象とするURLを設定する
            .addPathPatterns("/sample")
            // インターセプターの適用順序を設定(デフォルト:0)
            // 特に設定していない場合追加した順に実行される
            .order(1);
    }
}

SpringFrameworkーAOPとは?

SpringFrameworkの特徴的な機能のひとつであるAOPについて書いていきます。

SpringFrameworkについての記事はこちら

olafnosuke.hatenablog.com

AOPとは?

Aspect Oriented Programmingの略で、「アスペクト指向プログラミング」と呼ばれる。

AOPを使用することで、クラスを横断した処理(例外処理やロギング、トランザクション処理など)をビジネスロジックから分離するようにコードを記述することができるようになる。
これによって、複数の処理をシンプルに記述できたり、同じ処理をおこなうコードが色々な場所で記述されていることを防ぐことができる。

Spring AOPで使用する用語

Aspect

横断的な処理とそれを実行する場所を定義したモジュールのこと。

Springでは@AspectをクラスにつけることでそのクラスはAspectとして認識される。
AspectはDIコンテナに登録されている必要があるので、コンポーネントスキャン対象配下にクラスが存在する場合はクラスに@Componentをつけ、そうでない場合はJavaConfigクラスでBean登録する。

@Component
@Aspect
public class SampleAspect{
}

JoinPoint

横断的な処理を挿入する場所のこと。
メソッドやコンストラクタの実行前、メソッドやコンストラクタの実行後といったように実行されるタイミングのことを示す。

Advice

JoinPointで実行される横断的な処理のこと。
@Aspectをつけたクラスのメソッドにアノテーションをつけることで、そのメソッドをAdviceとして実行させることができる。
Adviceを表すアノテーションの種類は、以下の5つ。

@Before

JoinPointの処理前に実行されるAdviceのこと。

@After

JoinPointの処理後に実行されるAdviceのこと。
メソッドの実行結果が正常・例外に関わらずメソッドの実行後に実行される。

@AfterReturning

JoinPointの処理が正常終了時に実行されるAdviceのこと。
JoinPointで例外がスローされた場合は無効となる。

returningパラメータで文字列を指定すると、その文字列の変数にJoinPointで実行された処理の戻り値が格納される。これによって戻り値をAdviceで利用することができる。

@AfterReturning("execution(* jp.co.sample..*(..))", returning = "r")
public void after(Object r) {
}
@AfterThrowing

JoinPointで例外が発生した後に実行されるAdviceのこと。

throwingパラメータで文字列を指定すると、その文字列の変数にJoinPointで実行された処理で起きた例外が格納される。これによって例外をAdviceで利用することができる。

@AfterThrowing("execution(* jp.co.sample..*(..))", throwing = "t")
public void after(Throwable r) {
}
@Around

JoinPointの前後で実行されるAdviceのこと。
実行タイミングは自身で定義できる等、最も汎用的なAdvice。

@Around("execution(* jp.co.sample..*(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable {
  // 前処理

  //メソッド実行
  Object result = pjp.proceed();

  // 後処理
}

PointCut

処理がJoinPointに到達した時、Adviceを実行するかどうかを判定するもの。
例えば、「メソッド名がgetで始まる時だけAdviceを実行する」のような条件を定義したもの。

下のコード例のようにAdviceのアノテーションのパラメータとしてPointCutを表現する。

@After("execution(* jp.co.sample..*(..))")
public void after(){
}

PointCutの書き方は以下の通り

execution(修飾子 戻り値 パッケージ名.クラス名.メソッド名(引数の型) throws 例外の型

修飾子・パッケージ名・クラス名・例外の型は省略可能。
Spring AOPpublicメソッドのみサポート なので修飾子は記述する必要はない。

executionとは ポイントカット指示子(メソッド実行条件) と呼ばれるもので、Spring AOPでは最もよく利用される。
execution()以外にもwithin()やtarget()など存在する。(後述)

PointCutには具体的なメソッドを指定してもよいが、「*」と「..」を使用することで、対象のメソッドに幅を持たせることができる。

AOPの対象とするクラスもDIコンテナに登録されている必要がある。DIコンテナに登録されていない場合は、PointCutの条件に合致していてもAdviceは実行されない。

記号 説明
* 任意の文字列を表す。パッケージ名で使う場合は、「任意の名前の1パッケージ」を表し、引数で使う場合は「任意の型1つ」を表す。
.. パッケージ名で使う場合は、「0以上のパッケージ」を表し、引数で使う場合は「0以上の任意の型」を表す。

以下にPointCutの具体的な設定例を示す

publicメソッドの実行前
@Before("execution(public * *(..))")

メソッド名が"set"で始まるメソッドの実行前
@Before("execution(* set*(..))")

MyServiceで定義されているメソッドの実行前
@Before("execution(* jp.co.sample.MyService.*(..))")

sampleパッケージに定義されているメソッドの実行前
@Before("execution(* jp.co.sample..(..))")

sampleもしくはそのサブパッケージ内に定義されているメソッドの実行前
@Before("execution(* jp.co.sample...(..))")

ポイントカット指示子

上で紹介したexecution()以外の指示子について説明する。

within

指定したクラス(型)で定義されたメソッドに対する呼び出しに適用するポイントカット。
以下のように設定した場合はExampleServiceで定義されたメソッドに対する呼び出しに適用される。

@Before("within(com.example.service.ExampleService)")
target

指定したクラス(型)のインスタンス(その型を実装するインスタンス)のメソッド呼び出しに適用するポイントカット。
例えばExampleServiceがParentExampleServiceを継承している場合、以下の設定例では、ExampleService及びParentExampleServiceで定義されたメソッド呼び出しに適用される (withinでは指定したクラスのみで親クラス、子クラスの呼び出しには適用されない)。

@Before("target(com.example.service.ParentExampleService)")
args

指定した引数の型にマッチするメソッド呼び出しに適用するポイントカット。
例えば以下のようにすることで、ExampleServiceクラスでString型の引数を取るメソッド呼び出しに適用される。

@Before("within(com.example.service.ExampleService) && args(java.lang.String)")
public void beforeArgs() {

また、以下のようにargsに実際の引数名を指定することでAdvice(ここではbeforeArgsメソッド)の引数としてバインディングされ、Advice内で利用することができる。

@Before("within(com.example.service.ExampleService) && args(something)")
public void beforeArgs(String something) {
@annotation

指定されたアノテーションが付与されたメソッド呼び出しに適用するポイントカット。
例えば以下のようにすることで、ExampleServiceクラスで@Beanアノテーションが付与されたメソッド呼び出しに適用される。

@Before("within(com.example.service.ExampleService) && @annotation(org.springframework.context.annotation.Bean)")
その他のポイントカット指示子

以下のサイトに説明がされている。

5.2.3. Declaring a pointcut
Spring AOP ポイントカット指定子の書き方について
Introduction to Pointcut Expressions in Spring

SpringFrameworkーDIとは?

SpringFrameworkの特徴的な機能のひとつであるDIコンテナについて書いていきます。

SpringFrameworkについての記事はこちら olafnosuke.hatenablog.com

DIコンテナとは

SpringがJavaインスタンスを管理している入れ物。
管理方法:key-value方式

例:
sampleService:newSampleService("a");

Springが管理しているインスタンスのことをコンポーネントbeanと呼ぶ。 DIコンテナにインスタンスを登録することをbean定義と呼ぶ。

Beanのスコープ

スコープとは、DIコンテナに登録されたコンポーネントインスタンス)の「生存期間」のこと。
スコープには以下のものがある。

prototype

Beanを取得するたびに、毎回インスタンスが生成される

request

HTTP Request単位でインスタンスを生成する
ex. 何かボタンを押してリクエストが返ってくるまで

session

HTTP Session単位でインスタンスを生成する
ex. ユーザーがログインしてからログアウトするまで

singleton(デフォルト)

Spring起動時にインスタンスを1つだけ生成する。生成後は、1つのインスタンスを共有して使う
ApplicationContext単位のスコープ

application

サーブレットのコンテキスト単位でインスタンスが生成される
application スコープは複数のApplicationContext内で同一のコンポーネントを使用する


Bean定義の方法

XMLファイルで定義する方法とJavaConfigで定義する方法、アノテーションで定義する方法がある。

xmlファイルで定義する

<beans>要素の子要素の<bean>要素に個々のBean定義を記述する。

Bean名 Beanインスタンス
id属性で指定した値 class属性で指定したクラス
※class属性は完全修飾クラス名を記述する

以下に記述例を示す

<bean id="sampleService" class="jp.co.sample.SampleServiceImpl" />

JavaConfigで定義する

クラスに@Configurationアノテーションを付与し、Bean定義を行うクラスであることを宣言する。
@Configurationアノテーションを付与したクラスのメソッドに@Beanアノテーションを付与し、Bean定義を記述する。

Bean名 Beanインスタンス
デフォルトでは@beanアノテーションを付与したメソッド名
指定したい場合は、@Bean(name = “別名”)とする。
@beanアノテーションを付与したメソッドの戻り値

以下に記述例を示す

@Configuration
public class AppConfig {
    @Bean
    Sample sampleService(){
        return new SampleServiceImpl();
    }
}

アノテーションで定義する

DIコンテナに管理させたいBean(もしくはコンポーネント)に@Componentアノテーションを付与し、@ComponentScanアノテーションでスキャンすることでDIコンテナに登録する。

Bean名 Beanインスタンス
デフォルトでは@Componentを付与したクラス名の先頭を小文字にしたもの。
指定したい場合は@Component("別名")
@Componentを付与したクラス

以下に記述例を示す

package jp.co.sample.service;

// DIコンテナに登録したいクラス
@Component
public class SampleServiceImpl implements SampleService {
}

@ComponentScanの属性「basePackages」でスキャン対象のパッケージを指定することが出来る。

// スキャンを行うクラス
@Configuration
@ComponentScan(basePackages = "jp.co.sample")
public class AppConfig {
    @Bean
    SampleService sampleService(){
        return new SampleServiceImpl();
    }
}

インジェクション方法

インジェクションとは、DIコンテナに登録したコンポーネントを他のDIコンテナに登録されているクラスで使用できるように注入することである。

インジェクションには、コンストラクタインジェクション、セッターインジェクション、アノテーションインジェクションがある。

コンストラクタインジェクション

コンストラクタインジェクションは、コンポーネントのコンストラクタで依存するコンポーネントを注入する方法である。

以下にSampleクラスにSampleServiceクラスをインジェクションする例を示す。

インジェクションを行いたいクラスで、インジェクションしたいコンポーネントを引数にもつコンストラクタを定義する。

// インジェクション対象のクラス
public class Sample {
    private SampleService service;
    
    public Sample(SampleService service){
        this.service = service;
    }
}

JavaConfigでbean定義を行う場合、以下のようにSampleクラスをDIコンテナに登録する際に定義したコンストラクタを使用してインスタンスを作成するようにする。

@Configuration
public class AppConfig {
    @Bean
    Sample sampleService(){
        return new SampleServiceImpl();
    }

    @Bean
    Sample sample(){
        return new Sample(sampleService());
    }
}

XMLでbean定義を行う場合は以下のように記述する。

<bean id="sampleService" class="jp.co.sample.service.SampleServiceImpl" />
<bean id="sample" class="jp.co.sample.Sample">
    <constructor-arg ref="sampleService"/>
</bean>

アノテーションベースの定義の場合はコンストラクタに@Autiwiredを付与する。

public class Sample {
    private SampleService service;
    
    @Autowired
    public Sample(SampleService service){
        this.service = service;
    }
}

セッターインジェクション

セッターインジェクションはコンポーネントのセッターの引数に依存するコンポーネントを注入する方法である。

public class Sample {
    private SampleService service;

    public void setSampleService(SampleService service){
        this.service = service;
    }
}

JavaConfigでbean定義を行う場合、以下のようにSampleクラスをDIコンテナに登録する際に定義したセッターを使用してインジェクションを行う。

@Configuration
public class AppConfig {
    @Bean
    Sample sampleService(){
        return new SampleServiceImpl();
    }

    @Bean
    Sample sample(){
        Sample sample = new Sample();
        sample.setSampleService(sampleService());
        return sample;
    }
}

XMLでbean定義を行う場合は以下のように記述する。

<bean id="sampleService" class="jp.co.sample.service.SampleServiceImpl" />
<bean id="sample" class="jp.co.sample.Sample">
    <property name="sampleService" ref="sampleService"/>
</bean>

アノテーションベースの定義の場合はセッターに@Autiwiredを付与する

public class Sample {
    private SampleService service;

    @Autowired
    public void setSampleService(SampleService service){
        this.service = service;
    }
}

フィールドインジェクション

フィールドインジェクションはコンポーネントのフィールドに依存するコンポーネントアノテーションでインジェクションする方法である。

public class Sample {
    @Autowired
    private SampleService service;
}

Spring Frameworkとは

Spring Frameworkとは

アプリケーション開発を容易にすることを目的としたオープンソースJavaアプリケーションフレームワークのこと。
多数のサブプロジェクトで、Webアプリケーション開発に必要な機能(リクエスマッピング、セッション管理、入力チェック、画面遷移処理、タグライブラリなど)を提供しており、開発の効率化が期待できる。

  • Spring MVC
  • Spring AOP
  • Spring JDBC
  • Spring Sequrityなど

Spring Bootも含まれる。

Spring Frameworkの主な特徴

Spring Frameworkの特徴として、AOPとDIと呼ばれる概念で構築されている。

DI(依存性の注入)

Dependency Injection」の略。プログラムコードから依存関係を取り除き、外部から依存性を与えることで、コンポーネントの独立性が高まる。
DIを用いれば、オブジェクトの成立要件に必要な情報を、外部に切り離して設定する「コンポーネント」を作成できるようになる。

DIについて詳しく書いた記事を書いたので、詳しくはこちらを御覧ください。

olafnosuke.hatenablog.com

AOPアスペクト指向プログラミング)

Aspect Orientation Programming」の略。オブジェクトの本質ではない複数のオブジェクトにまたがる共通の処理を分離することで、オブジェクト指向では解決が困難な問題点を解決する。
システム内で行われる同じ処理(共通処理)を抽出して集約をする。プログラミングの「本質的な処理」のみをクラスに書き、そうではない処理を別に書くといったように、処理の分断を行うことができる。

AOPについて詳しく書いた記事を書いたので、詳しくはこちらを御覧ください。

olafnosuke.hatenablog.com

Springを使用するメリット

拡張性が高い

ここで言う拡張性とは、機械やアプリケーションが本来備えている機能をさらに向上させる性能を指す。Spring Frameworkは、基本的な機能の大部分が「インターフェース」として提供されているので、性能の向上が行いやすい。

保守性に優れている

AOPAspect Oriented Programming)」によって、例えばログの出力のような機能を、本来のプログラムとは分割して行う事ができるので、バグや不具合があった際にどこが問題になっているのかを特定しやすく、解決が容易となる。

テストがしやすい

Spring Frameworkは「Spring MVC Test」という優秀なテストプログラム機能が使用可能。
「Spring MVC Test」は、一つ一つの処理ごとに行う単体テストではなく、コンテナコンテキストの配線やデータアクセスなど、一連の処理をテストする結合テストを行う事が可能。

変更がしやすい

「DI」(Dependency Injection)を使用することで、オブジェクトを利用する状況が変わっても、設定を変更するだけでそのオブジェクトを利用できるようになるため、修正範囲を最小に留められる。

再利用性が高い

Spring FrameworkはDIとAOPの仕組みにより、共通プログラムの再利用が容易となる。プログラムを再利用することで、プログラムを書く量が減り、修正する場合も最低限の修正で済むようになる。

デメリット

・豊富なプロジェクトを有し、幅広い開発に対応しているが、その規模の大きさゆえに全体を把握しにくい
・日本語の情報が少なく、学習コストが高い
・設定一つで機能を実現できるがその設定が難しい


Spring Boot

Spring Bootとは

SpringFrameworkを使用したJavaで行うWebアプリ開発を迅速かつ効率的にする仕組みを備えたフレームワークのこと。Spring Frameworkの機能の使い分けが難しいというデメリットを解決するために作られたフレームワーク

特徴

  • 複数のフレームワークを使用するときに発生するBean定義やXML設定を可能な限り自動設定する機能を持ち、必要最低限の設定を行うだけでアプリケーションの起動・実行を行うことができる。
  • アノテーションを記述することにより機能を実装することが可能なため、コーディング量が削減される
  • Webコンテナをjar(Java ARchive)ファイルに含めることが可能で、jarファイル単体でWebアプリケーションの作成が可能。Spring BootではデフォルトでTomcatコンテナを含んでいる。

Spring Bootプロジェクトの作成

以下のサイトで作成可能。

https://start.spring.io/

Eclipse上でも、「新規」⇒「Springスタータープロジェクト」から作成可能

application.ymlはなにか?

Spring Bootの色々な設定を行うファイル。

application.ymlで設定できるプロパティの一覧

https://docs.spring.io/spring-boot/docs/2.4.4/reference/html/appendix-application-properties.html

application-プロファイル名.ymlとすることで、環境ごとに設定ファイルを作成することができる。

環境変数とapplication.yml

application.ymlには環境変数をインジェクションすることができる。

環境変数をインジェクションする理由

  1. 環境ごとに設定ファイルを作成する必要が無くなる。
    環境変数を前もって設定しておくか、実行時に設定するようにすれば、同じ設定ファイルを他の環境でも利用することが出来る。
    開発時はローカルDBを使用することが多いので、人によってURLが異なるが、設定ファイルの書き方は統一できる。
  2. セキュリティの向上につながる。
    application.properties内にユーザー名やパスワードといった秘密にしたい情報をベタ書きした状態で、リモートリポジトリに上げてしまったりするとセキュリティの問題にもなりかねない。

以下は環境変数をapplication.ymlにインジェクションする例である。

spring:
# JDBCの接続設定
    datasource:
      driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
      url: ${DATASOURCE_URL}
      username: ${DATASOURCE_USER_NAME}
      password: ${DATASOURCE_PASSWORD}