JavaプロジェクトにSonarQubeを導入すると、NullPointerExceptionやリソースリーク、セキュリティ脆弱性といったコードの問題をコミット前に自動で検出できるようになります。コードを動かさずにバグの芽を摘み取れる。これが静的解析の最大の価値です。
この記事では、10年以上Java現場に立ち続けてきた経験をもとに、以下をすべて解説します。
- SonarQubeのDockerインストール(5分で起動)
- sonar-project.propertiesの最小構成
- Maven/GradleでのJavaプロジェクト解析手順
- 解析結果(Bugs/Vulnerabilities/Code Smells)の読み方
- GitHub Actionsへの組み込み方
- SonarLintを使ったIDE連携
「警告が出すぎて放置している」「チームに導入したが形骸化している」という悩みにも、具体的な運用ルールを交えて答えます。
若手のころ、ベテランの先輩にコードレビューで何十個もの指摘をもらい鼻をへし折られた私が、「機械に任せられる部分は機械に任せる」という答えにたどり着くまでの実体験もあわせてお伝えします。
SonarQube + Javaの環境要件を確認する
セットアップの前に、バージョンの組み合わせを確認しておきましょう。「動かない」という問い合わせの多くは、JavaとSonarQubeのバージョン不一致が原因です。
| SonarQubeバージョン | サーバー起動に必要なJava |
|---|---|
| 10.x(最新) | Java 17以上 |
| 9.9 LTS | Java 11以上 |
| 9.x | Java 11以上 |
注意点は2つあります。まず、SonarQubeサーバーの起動に必要なJavaと、解析対象のJavaプロジェクトのバージョンは別物です。SonarQube 10.xはJava 17で動かしつつ、解析対象のプロジェクトはJava 8でも構いません(sonar.java.source=8で指定)。次に、Java 8や11でSonarQube 10.xを起動しようとするとエラーになります。まず自分の環境のJavaバージョンを確認してください。
java -version
# 出力例: openjdk version "17.0.10" 2024-01-16DockerでSonarQubeサーバーを起動する
SonarQubeはサーバーとデータベース、解析を実行するスキャナーが連携して動きます。個人学習やチームへの導入を試したいなら、Dockerを使うのが最短ルートです。
コマンド1つで起動する(開発・学習向け)
内蔵のH2データベースを使う簡易構成です。データの永続化はされませんが、試すには十分です。
docker run -d \
--name sonarqube \
-p 9000:9000 \
sonarqube:lts-community起動後、ブラウザで http://localhost:9000 にアクセスします。初回ログインのID/パスワードはともに admin です。ログイン後すぐにパスワード変更を求められるので、忘れないようにメモしておきましょう。
PostgreSQLと組み合わせる(チーム・本番向け)
チームで継続利用する場合は、PostgreSQLと組み合わせて解析履歴を永続化します。
# docker-compose.yml
version: "3"
services:
sonarqube:
image: sonarqube:lts-community
ports:
- "9000:9000"
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: sonar
depends_on:
- db
db:
image: postgres:15
environment:
POSTGRES_USER: sonar
POSTGRES_PASSWORD: sonar
POSTGRES_DB: sonardocker compose up -d起動したら、管理画面でプロジェクトを作成し、解析用のトークンを発行します。このトークンは後の手順で必要になるので控えておいてください。
sonar-project.propertiesを設定する
プロジェクトのルートに sonar-project.properties ファイルを置くことで、スキャン時のオプションを省略できます。以下が最小構成です。
# sonar-project.properties
sonar.projectKey=my-java-project
sonar.projectName=My Java Project
sonar.projectVersion=1.0
# ソースコードの場所
sonar.sources=src/main/java
sonar.tests=src/test/java
# 解析対象プロジェクトのJavaバージョン(サーバーとは別)
sonar.java.source=17
# コンパイル済みバイナリの場所(解析精度向上のために推奨)
sonar.java.binaries=target/classes
# JaCoCoカバレッジレポートの場所(テストカバレッジを計測する場合)
sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
# SonarQubeサーバーの接続先
sonar.host.url=http://localhost:9000
sonar.login=your-token-heresonar.java.binaries を指定しないと「バイナリが見つからない」エラーが出ることがあります。先に mvn compile や ./gradlew classes でビルドを通してからスキャンするのが安全です。
JavaプロジェクトをSonarQubeで解析する
Javaエンジニアなら、MavenかGradleのプラグインを使うのが最もスマートです。ビルドの一環として解析が走るため、CI連携とも相性が良くなります。
Mavenプロジェクトの場合
pom.xml にプラグインを追加します。
<build>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>4.0.0.4121</version>
</plugin>
</plugins>
</build>プラグインを追加したら、以下のコマンドで解析を実行します。
# ビルドしてから解析(カバレッジも取得する場合)
mvn clean verify sonar:sonar \
-Dsonar.host.url=http://localhost:9000 \
-Dsonar.login=your-token-hereGradleプロジェクトの場合
build.gradle にプラグインを追加します。
plugins {
id "org.sonarqube" version "4.4.1.3373"
id "jacoco" // カバレッジを計測する場合
}
sonarqube {
properties {
property "sonar.projectKey", "my-java-project"
property "sonar.host.url", "http://localhost:9000"
property "sonar.login", System.getenv("SONAR_TOKEN")
}
}# 環境変数でトークンを渡して実行
SONAR_TOKEN=your-token-here ./gradlew sonarqubeコマンドを叩いてしばらく待つと、解析結果がSonarQubeサーバーに送信されます。ブラウザで http://localhost:9000 を開くと、プロジェクトのダッシュボードに結果が表示されています。
解析結果の見方が分かると、SonarQubeは一気に使いやすくなる
解析が終わると、画面には大量の数字やグラフが表示されます。これを見て「うわ、面倒くさそう」と拒絶反応を起こしてはいけません。項目の意味さえ分かれば、どこを優先して直すべきかが自然と見えてきます。
Bugs・Vulnerabilities・Code Smellsの違い
「Bugs」は今すぐ修正が必要な動作不良、「Vulnerabilities」はセキュリティ上の欠陥を指します。一方で「Code Smells」は、動作には問題ないものの、将来的にメンテナンスを困難にする書き方です。
これらを混同すると修正の優先順位を付け間違えます。まずはBugsとVulnerabilitiesの2つに絞って対策を立てるのが、賢いエンジニアの立ち回りです。
初心者がまず見るべき画面と指標
最初に見るべきは、プロジェクトトップにある「Overview」タブです。全体的な評価がAからEのランクで表示されており、直感的に今の状態を把握できます。まずは「New Code」という項目に注目してください。
過去の負債は一旦置いておき、新しく追加したコードに問題がないかを確認するだけで、プロジェクトの品質が今以上に悪化するのを防げます。
Quality Gateが「OK/NG」を判断する仕組み
Quality Gateは、プロジェクトがリリース可能な品質を満たしているかを判定する門番です。「新規コードのバグが0個であること」や「テスト網羅率が80%以上」といった条件を自由に設定できます。
このゲートが「OK」にならない限り次の工程に進ませないといった運用により、客観的な指標でチーム内の議論をシンプルにできます。
SonarQubeでJavaの静的解析をすると何が分かるのか
静的解析は、プログラムを実行せずにソースコードの「形」を見て問題を指摘する仕組みです。ルールに基づいてコードをチェックするため、誰が解析しても同じ結果が出るのが特徴。1,000行を超えるような巨大なクラスでも、一瞬で問題点をリストアップしてくれます。
Java開発で見落としやすいバグ・臭い・脆弱性の具体例
実際に私が担当したプロジェクトでは、SonarQube導入前にNullPointerExceptionが原因で本番障害が月2〜3件発生していました。SonarQubeを入れた翌月には、その件数がゼロになりました。「機械に怒られる」だけで、チームの書き方が変わるのです。
SonarQubeが検出するJava特有の問題を具体的なコードで見てみましょう。
// Before: SonarQube警告 java:S2095「リソースを閉じ忘れている」
public String readFile(String path) throws IOException {
InputStream is = new FileInputStream(path); // ← 閉じ忘れ警告
byte[] data = is.readAllBytes();
return new String(data);
}
// After: try-with-resourcesで修正
public String readFile(String path) throws IOException {
try (InputStream is = new FileInputStream(path)) {
byte[] data = is.readAllBytes();
return new String(data);
}
}他にも、catch (Exception e) {} のような大雑把な例外処理(java:S2221)や、複雑にネストされたif文(java:S3776:Cognitive Complexity超過)なども厳しく指摘されます。警告の説明文には「なぜダメなのか」と「どう直すのか」が書かれているので、読み込むだけでJavaの深い知識が自然と身につきます。
人のコードレビューとSonarQubeの役割分担を整理する
機械に任せられる部分はすべてSonarQubeに任せ、人間はロジックの本質に集中しましょう。インデントの乱れや命名規則の違反を人間が指摘するのは時間の無駄でしかありません。
設計の妥当性や業務仕様の整合性は人間がチェックし、定型的なミスはツールが弾く。この分担を徹底することで、レビューの時間は半分以下に短縮でき、かつ質も向上します。
警告を活かす運用ルール(Clean as You Code)
ツールを導入したものの、警告が多すぎて結局放置されるケースは少なくありません。これは、すべての指摘を均等に扱おうとするのが原因です。重要なのは「捨てる勇気」を持つこと。現実的な運用ルールを作ることが、ツールを形骸化させないための秘訣です。
既存コードと新規コードを分けて考える
10年以上続くプロジェクトにSonarQubeを入れると、数万件の指摘が出ることも珍しくありません。これをすべて直すのは現実的ではないため、既存コードの負債は「現状維持」と割り切るのも一つの手です。
その代わり、新しく書くコードに対しては厳格な基準を適用します。この「Clean as You Code」という考え方を採用すれば、徐々に全体の品質を改善していけます。SonarQubeのダッシュボードでも「New Code」ビューがあり、新規コードだけを対象に評価する機能が標準で備わっています。
重要度の高い指摘と後回しでよい指摘の見分け方
まずBugs(バグ)とVulnerabilities(脆弱性)だけを対象にするなど、スモールステップで始めるのが定石です。システム停止や情報漏えいにつながるリスクがある指摘を最優先で修正し、Code Smells(コードの臭い)は余裕がある時に対処すれば十分です。
「週に1時間だけリファクタリングの時間を設ける」といった、ゆるいルールから始めることで、チームメンバーが「このツールは自分たちの味方だ」と感じられるようになります。
CIに組み込むと、SonarQubeはレビュー補助ツールになる
手動でスキャンを実行する手間を省くために、CI(継続的インテグレーション)への組み込みは必須です。開発者がコードをプッシュするたびに自動で解析が走り、結果がプルリクエストにコメントされます。
この仕組みを整えることで、SonarQubeは24時間365日働く「最強の副操縦士」へと進化します。
GitHub ActionsでSonarQube解析を自動化する
以下の設定を .github/workflows/sonarqube.yml として保存するだけで、pushやPRのたびに自動解析が走ります。
# .github/workflows/sonarqube.yml
name: SonarQube Analysis
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened]
jobs:
sonarqube:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 差分解析の精度向上のため浅いクローンを無効化
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build and analyze
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
run: |
mvn -B verify sonar:sonar \
-Dsonar.projectKey=my-java-project \
-Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \
-Dsonar.login=${{ secrets.SONAR_TOKEN }}GitHubリポジトリの「Settings → Secrets and variables → Actions」に SONAR_TOKEN と SONAR_HOST_URL を登録しておきましょう。セルフホスト型のSonarQubeサーバーはインターネットに公開されていないため、外部CIからアクセスできない場合は SonarCloud(クラウド版)の利用も選択肢です。
Pull Request時に自動解析するメリット
プルリクエストを出すと、その変更差分だけに絞ってSonarQubeが解析結果をフィードバックしてくれます。レビュー依頼を出す前に自分でミスに気づけるため、レビューをする側も機械的なチェックが済んだ状態のコードを読めるので、本質的な議論に時間を割けるようになります。まさに全員が幸せになれる仕組みです。
CI連携でよくつまずくポイントと対処の考え方
CI連携で多いのは、解析に時間がかかりすぎて開発のリズムが崩れることです。プロジェクトが大規模になると、解析だけで数十分かかる場合があります。これを避けるために、差分解析(fetch-depth: 0 の設定)をうまく活用しましょう。また、セルフホスト型のSonarQubeサーバーとCI環境のネットワーク疎通が取れているかも事前に確認が必要です。
Java開発で特に効果が出やすいSonarQube活用ポイント
Javaという言語の特性上、よく発生するミスのパターンが決まっています。SonarQubeには長年の歴史で培われたJava専用のルール(SonarWay)が大量に組み込まれており、これを活用しない手はありません。
null安全・例外処理・条件分岐でよく出る指摘
Javaで最も多い実行時エラーはNullPointerException。SonarQubeは変数がnullになる可能性を先読みして、事前にチェックするよう促します。また、catch (Exception e) のような大雑把な例外処理や、複雑にネストされたif文も厳しく指摘。これらを改善するだけで、コードの堅牢性と読みやすさが驚くほど向上します。
パフォーマンスと可読性に関する典型的な警告
ループ内での文字列連結(+ 演算子の多用)など、Javaでパフォーマンス劣化を招く定番の書き方を教えてくれます。使われていない変数やインポート文も削除するよう促されるため、コードがスッキリします。機械的な指摘に従うだけで、中級者以上のコードに近づけます。
チーム開発で品質を揃えるための使いどころ
複数人で開発していると、人によってコードの書き方が大きく異なる問題が発生します。SonarQubeの解析ルールをプロジェクトで共有すれば、誰が書いても同じような構造になります。
後から入ってきたメンバーがコードを理解するスピードを早める効果もあります。個人のこだわりを捨て、ツールが推奨する「標準」に合わせることが、チーム全体の利益につながります。
SonarLintでIDE連携するとコミット前に気づける
SonarQubeと合わせて使いたいのが「SonarLint」です。VSCodeやIntelliJ IDEAのプラグインとしてインストールでき、コードを書きながらリアルタイムで警告を確認できます。サーバーを起動しなくても動作するため、個人の開発段階でコミット前に問題を修正できます。
VSCode・IntelliJへの導入手順
- VSCode: 拡張機能マーケットプレースで「SonarLint」を検索してインストール
- IntelliJ IDEA: Plugins → Marketplace → 「SonarLint」を検索してインストール
インストール後は設定不要で、エディタ上に赤・黄色の下線でリアルタイム警告が表示されます。さらに、SonarQubeサーバーの接続設定(Connected Mode)を有効にすれば、サーバー側で設定したカスタムルールをIDEでも共有できます。チームのルールブックをIDEに持ち込める、という感覚です。
SonarQubeは「完璧にする道具」ではなく「品質を下げない仕組み」
このツールを導入したからといって、魔法のようにすべてのバグが消え去るわけではありません。静的解析はあくまでコードの構造を見ているだけで、実行時のデータの流れや外部システムとの連携までは完全に追えません。
論理的な矛盾や、ユーザーの要求とのズレを検知するのも苦手です。バグをゼロにするには、適切な単体テストや結合テスト、そして人の目による検証が不可欠。SonarQubeは、それらの活動をより効率的にするための土台に過ぎません。
それでも私がこのツールを10年以上使い続けているのは、「崩壊を防ぐための堤防」になることを知っているからです。完璧を目指して疲弊するのではなく、昨日より少しだけ綺麗なコードを書く。そのための良き相棒として、SonarQubeを長く使いこなしてください。