1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【VSCode × Java】Linter, Formatter と Github Actions を活用してコード品質を高める

Last updated at Posted at 2025-12-22

この記事は、はじめてのアドベントカレンダー Advent Calendar 2025 の 17 日目の記事です。今まで読むばかりだったアドカレに初参加です😊 最近 VSCode で Java の開発環境を構築することがあったので、それについてまとめてみました!

はじめに

Java の開発には、IntelliJ IDEA や Eclipse などの統合開発環境 (IDE) が用いられることが多いと思いますが、VSCodeでも Extension Pack for Java などの拡張機能を利用することで、同様の開発環境を構築することができます。

コードの品質を高めるうえで Linter, Formatter の設定は欠かせませんが、IntelliJ IDEA や Eclipse での設定手順の説明は多くあるものの、VSCode での導入手順や CI への組み込みまで詳しく説明するものは多くないため、本記事では後者の導入手順について説明したいと思います。

Linter, Formatter について

Linter とは、ソースコードの構文エラーや潜在的なバグ、プロジェクトで定めたコーディング規約の違反などを検出してくれる静的解析ツールです。ソースコードの実行やコンパイルを行うことなく、命名規則違反や例外の握りつぶし、空ブロックや未使用変数などをチェックしてくれるため、コンパイルエラーにはならないものの品質面で問題となるコードを実行前に検出することができます。Javaで用いられる Linter には SpotBugs や後述する Checkstyle などがあります。

対して Formatter は、プロジェクトのコーディングスタイルに沿うようにソースコードを整形するツールです。ファイルの保存時に Formatter が実行されるように設定することで、改行の挿入や行の折り返し、import文の並び順などが自動的に整形され、開発者間で一貫したコーディングスタイルを保つことができます。Java では今回説明する google-java-format や、複数言語対応でエディタに依存しない Spotless などを用いることができます。

一般的に、Linter は例外の握りつぶしなど潜在的な問題まで検出するものを指しますが、Checkstyle プラグインの Lint 対象は基本的にコーディング規約違反のチェックに限るので注意が必要です。コーディングスタイル以外の静的解析には、SonarLint や SpotBugs などを別途利用します。

実行環境

  • VSCode : ver 1.100.3

    $ java --version 
    openjdk 21.0.8
    
    $ gradle --version
    Gradle 8.13
    
  • JDK や VSCode の拡張機能 Extention Pack for Java がインストールされていることを前提としています。

Checkstyle を導入する

1. build.gradle に以下の内容を追記し、プラグインを追加します。

build.gradle
plugins {
    id 'checkstyle'
}

checkstyle {
    toolVersion = '12.1.2'
    configFile = file('config/checkstyle/checkstyle.xml')  // 配置するディレクトリやファイル名は任意
}

2. 上記で指定した configFile のパスに、コーディングスタイルを定義した xml ファイルを配置します。今回は Google Java Style Guide に準拠したコーディング規約を用います。

このとき checkstyle.xml の記述は、checkstyleの最新バージョンに沿ったものとなっているため、先ほど記述した build.gradletoolVersion もそれに合うように設定する必要があります (バージョンが不整合だと Lint 実行時にエラーとなります)。Checkstyle リポジトリの Code ページから最新のリリースバージョンを確認できます。

3. 必要に応じてプロジェクトで採用したいコーディング規約に沿うように checkstyle.xml を書き換えます。

  • インデントレベルを 2 → 4 に変更する
    <module name="Indentation">
    - <property name="basicOffset" value="2"/>
    - <property name="braceAdjustment" value="2"/>
    - <property name="caseIndent" value="2"/>
    + <property name="basicOffset" value="4"/>
    + <property name="braceAdjustment" value="0"/>
    + <property name="caseIndent" value="4"/>
      <property name="throwsIndent" value="4"/>
      <property name="lineWrappingIndentation" value="4"/>
    - <property name="arrayInitIndent" value="2"/>
    + <property name="arrayInitIndent" value="4"/>
    </module>
    
  • import順の変更
    Java標準パッケージと自作クラスのimport順についてのルールを追加します。
    <module name="CustomImportOrder">
      <property name="sortImportsInGroupAlphabetically" value="true"/>
      <property name="separateLineBetweenGroups" value="true"/>
    - <property name="customImportOrderRules" value="STATIC###THIRD_PARTY_PACKAGE"/>
    + <property name="customImportOrderRules" value="STATIC###STANDARD_JAVA_PACKAGE###THIRD_PARTY_PACKAGE###SPECIAL_IMPORTS"/>
    + <property name="specialImportsRegExp" value="my\.unique\.domain\.projectname\..*"/>
      <property name="tokens" value="IMPORT, STATIC_IMPORT, PACKAGE_DEF"/>
    </module>
    
  • Javadoc の存在checkの無効化
    Javadocが書かれていないメソッドがあっても pass するように該当部分をコメントアウトしておきます。
    <!--
      <module name="MissingJavadocMethod">
        <property name="scope" value="protected"/>
        <property name="allowMissingPropertyJavadoc" value="true"/>
        <property name="allowedAnnotations" value="Override, Test"/>
        <property name="tokens" value="METHOD_DEF, CTOR_DEF, ANNOTATION_FIELD_DEF,
                                     COMPACT_CTOR_DEF"/>
      </module>
      <module name="MissingJavadocType">
        <property name="scope" value="protected"/>
        <property name="tokens"
                  value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF,
                        RECORD_DEF, ANNOTATION_DEF"/>
        <property name="excludeScope" value="nothing"/>
      </module>
      -->
    

4. checkstyle違反があったら build が失敗するように変更します。

- <property name="severity" value="${org.checkstyle.google.severity}" default="warning"/>
+ <property name="severity" value="${org.checkstyle.google.severity}" default="error"/>

5. Lint を実行する
以下のコマンドで checkstyle による Lint が正常に実行されるか確認します。

$ ./gradlew check

checkstyleMaincheckstyleTest の 2つの Task が実行されます。checkstyle.xml に構文エラーがあったり、先述したバージョンの不整合があると以下のようなエラーが表示されるので、適宜修正して再実行してください。

 $ ./gradlew check
> Task :checkstyleMain FAILED
> Task :checkstyleTest FAILED

FAILURE: Build completed with 2 failures.

1: Task failed with an exception.
-----------
* What went wrong:
Execution failed for task ':checkstyleMain'.
> A failure occurred while executing org.gradle.api.plugins.quality.internal.CheckstyleAction
   > An unexpected error occurred configuring and executing Checkstyle.
      > Unable to create Root Module: config {/config/checkstyle/checkstyle.xml}.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

Test コードを Lint 対象としたくない場合は、以下のコマンドで Main のプロダクトコードのみ Lint することができます。

$ ./gradlew checkstyleMain

試しに、以下のようなコーディング規約違反がある状態で Lint をかけてみます。

@Override
public List<Trade> findAll() {
    try (var reader = Files.newBufferedReader(
            this.csvResource.getFile().toPath(), this.charset
    )) {
        return reader.lines()
                .skip(1)
                .map(Line -> UserEntity.fromCsvLine(Line, this.csvConfig.getDelimiter()))  // 変数名が大文字始まり 
                .map(UserEntity::toModel)
                .toList();
    } catch (IOException e) {
            throw new RuntimeException("Failed to read csv file.", e);  // インデントレベルが深すぎる
    }
}
$ ./gradlew checkstyleMain

> Task :checkstyleMain
[ant:checkstyle] [ERROR] projectroot/src/main/java/my/unique/domain/myproject/infrastructure/repository/user/csv/CsvUserRepository.java:46:26: Lambda parameter name 'Line' must match pattern '^[a-z]([a-z0-9][a-zA-Z0-9]*)?$'. [LambdaParameterName]
[ant:checkstyle] [ERROR] projectroot/src/main/java/my/unique/domain/myproject/infrastructure/repository/user/csv/CsvUserRepository.java:52:17: 'catch' child has incorrect indentation level 16, expected level should be 12. [Indentation]

> Task :checkstyleMain FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':checkstyleMain'.
> A failure occurred while executing org.gradle.api.plugins.quality.internal.CheckstyleAction
   > Checkstyle rule violations were found. See the report at: file://myproject/build/reports/checkstyle/main.html
     Checkstyle files with violations: 1
     Checkstyle violations by severity: [error:3]


* Try:
> Run with --scan to get full insights.

BUILD FAILED in 19s
3 actionable tasks: 2 executed, 1 up-to-date

このようにエラー箇所とその原因が表示されれば、正常に実行できています。修正して Lint が pass すると以下のようにビルドが成功します。

$ ./gradlew checkstyleMain

BUILD SUCCESSFUL in 35s
3 actionable tasks: 2 executed, 1 up-to-date

google-java-format を導入する

先ほど導入した Checkstyle のコーディングスタイルに沿うように、Formatter を導入し、ファイルの保存時に自動整形されるようにします。

1. eclipse-java-google-style からフォーマットルールが記述された xml ファイルをプロジェクト内の任意のディレクトリに配置します。今回は config/formatter/eclipse-java-google-style.xml に配置します。

2. .vscode/settings.json で Formatter が保存時に実行されるように設定します。

settings.json
{
	"java.format.settings.url": "config/formatter/eclipse-java-google-style.xml",
	"java.format.settings.profile": "GoogleStyle",
	"[java]": {
		"editor.formatOnSave": true,
		"editor.tabSize": 4
	}
}

3. 必要に応じて Format ルールをカスタムします。

<!-- 不要な空行を削除する -->
- <setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="3"/>
+ <setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="0"/>

<!-- 改行を保持する -->
- <setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
+ <setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>

<!-- importグループごとに改行を入れる -->
- <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="0"/>
+ <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>

4. ソースコードを保存して整形されれば ok です。その他詳細な説明はこちら1の記事が詳しいので譲りたいと思います。

Github Actions で CI に組み込む

CI (継続的インテグレーション)2とは、ソフトウェア開発においてコードを頻繁に共有リポジトリに統合する手法のことを指しますが、統合のたびにビルドやテスト、静的解析といったタスクが自動実行される開発プロセスまでを含めて指すことが一般的です。Github では Github Actions を用いてワークフローを作成することで、ソースコードの push や Pull Request の作成などのイベントをトリガーに、Lint や build を自動的に実行する CI パイプラインを構築できます。これにより、開発ブランチのレビューに入る前の段階で問題のあるコードを自動的に検出することができるので、開発効率の向上や、開発者間で一定のコード品質を担保させることが可能になります。

今回は、Lint と Build の job をワークフローに定義し、push や Pull Requestの作成時に自動的に実行されるように設定したいと思います。

ワークフローを記述する

プロジェクトリポジトリの Actions のページにアクセスし、Java with Gradle のページにいくことで、ワークフローのテンプレートとなる YAML ファイルを作成することができます。作成される .github/workflows ディレクトリについては、Github Actions を利用するうえで決められているものになるので注意してください。また、YAML ファイル名は任意なので適当な名前をつけておきましょう。

image.png

テンプレートとなる YAML ファイルが作成できたら、具体的なワークフローを以下のように記述していきます。workflow の詳細な書き方はこちら3を参考にしてください。

name: Java CI with Gradle  # workflow 名, github の Actionsタブに表示される

on:  
  # main ブランチに push または PR が出された場合に trigger
  push:
    branches: ["main"]
  pull_request:
    branches: ["main"]

jobs:
  # lint job を定義
  lint:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          java-version: 21    # 開発環境のバージョンと揃える
          distribution: temurin

      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@v4

      - name: Run Gradle check (lint)
        run: ./gradlew check  # lintコマンド

  # build job を定義
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    steps:
      - uses: actions/checkout@v4
      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          java-version: "21"
          distribution: "temurin"

      # Configure Gradle for optimal use in GitHub Actions, including caching of downloaded dependencies.
      # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
      - name: Setup Gradle
        uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0

      - name: Build with Gradle Wrapper
        run: ./gradlew build  # buildコマンド

YAML ファイルが記述できたら、実際に開発ブランチから main ブランチへのPRを出して workflow が実行されるか確認しましょう。以下のように表示されていれば workflow が正常に実行されています。先ほど、checkstyle 違反があった場合は build も失敗するように設定したので、不適切なコードが含まれている場合 lint, build ともに落ちているはずです。

image.png

Branch protection rules で CI の成功を強制する

ここまでの設定で、PR をトリガーに workflow が実行されるようになりましたが、今のままでは、workflow が失敗していてもそのまま開発ブランチをマージできてしまいます。Github では force push や 未レビューのブランチのマージなどを禁止する Branch protection rules を設定することができます。CI check が成功していない場合にはブランチをマージできないように ブランチ保護ルールを追加しましょう。

プロジェクトリポジトリの Settings タブ → RulesRulesets と進み、New branch ruleset をクリックします。
image.png

ブランチ保護ルール名として適当な名前をつけ、main ブランチに対して、保護ルールが適用されるようにしておきます。
image.png

Require status checks to pass にチェックを入れ、さらに Add checks から workflow で決めた job 名を検索し追加します。このとき直近で実行された job 名のみ検索欄に表示されるようになっているので、見つからない場合は一度 job を実行することで追加できるようになります。
image.png

このように設定しておくと、CI が成功するまで開発ブランチをマージすることができなくなり、不適切な品質状態のままのコードが main ブランチにマージされることを避けることができます。
image.png

CI による workflow が成功するとマージできるようになります。
image.png

おわりに

今回は VSCode で Java 開発をする際の Linter, Formatter の導入、Github Actions による CI 構築の手順を説明しました。これらのツールを適切に利用することで、チーム開発時に一定のコード品質を担保できたり、開発効率を向上させたりできると思うので、ぜひ導入して快適な開発体験を構築していただけるとよいと思います。

以上!!

参考

ブランチ保護による CI ステータスチェックの強制
GitHubのブランチ保護でステータスチェックを必須にする

  1. Google-java-format の詳細な導入手順
    VSCode の Java 開発環境にフォーマッターを設定する

  2. CI についての Github ドキュメント
    継続的インテグレーション

  3. Github Actions の workflow の書き方
    【入門】GitHub Actionsとは?概要やメリット、使用例まとめ

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?