SpotBugs 導入指引

導入效應

效應 說明
深度靜態分析 分析 Bytecode 而非原始碼,能找到更高階的 Bug
FindBugs 後繼 繼承 FindBugs 的所有規則並持續更新
數值精度問題 偵測 new BigDecimal(0.1) 等浮點數精度問題
多執行續 Bug 偵測 Race Condition、Thread Safety 問題
序列化安全 檢查 Serializable 的正確性
與 ErrorProne 互補 ErrorProne 抓編譯期問題,SpotBugs 抓 Bytecode 層級問題

1. Maven 導入

<plugin>
    <groupId>com.github.spotbugs</groupId>
    <artifactId>spotbugs-maven-plugin</artifactId>
    <version>4.8.6.6</version>
    <configuration>
        <effort>Max</effort>
        <threshold>Medium</threshold>
        <includeFilterFile>spotbugs-exclude.xml</includeFilterFile>
    </configuration>
</plugin>

2. Gradle 導入

plugins {
    id 'com.github.spotbugs' version '6.1.3'
}

spotbugs {
    effort = 'max'
    reportLevel = 'medium'
    excludeFilter = file('spotbugs-exclude.xml')
}

dependencies {
    spotbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.13.0'
}

3. 執行掃描

# Maven
mvn spotbugs:check        # 檢查(CI 用)
mvn spotbugs:gui          # GUI 介面查看
mvn spotbugs:spotbugs     # 產生 XML 報告

# Gradle
./gradlew spotbugsMain

4. 常見偵測問題

4.1 浮點數精度

// ❌ SpotBugs 警告
BigDecimal price = new BigDecimal(0.1);  // NP_NUMBER_TO_STRING_TO BigDecimal constructor

// ✅ 正確寫法
BigDecimal price = new BigDecimal("0.1");

4.2 資源外洩

// ❌ SpotBugs 警告
Connection conn = dataSource.getConnection();
// 忘記 close

// ✅ Try-with-resources
try (Connection conn = dataSource.getConnection()) {
    // ...
}

4.3 NullPointer 風險

// ❌ SpotBugs 警告
String value = map.get(key);
value.length();  // 可能 NPE

// ✅ 檢查 null
String value = map.get(key);
if (value != null) {
    value.length();
}

4.4 SQL Injection

// ❌ SpotBugs 警告 (FindSecBugs)
String query = "SELECT * FROM users WHERE id = " + userId;

// ✅ 參數化查詢
String query = "SELECT * FROM users WHERE id = ?";
PreparedStatement ps = conn.prepareStatement(query);
ps.setInt(1, userId);

5. SpotBugs 規則分類

類別 說明
Correctness 可能是 Bug 的程式碼
Bad Practice 違反良好實踐
Performance 效能問題
Security 安全漏洞 (FindSecBugs)
Multithreaded 多執行續問題
Malicious Code 惡意程式碼指紋

6. 自訂規則

6.1 Exclude 某些檢查

<!-- spotbugs-exclude.xml -->
<FindBugsFilter>
    <Match>
        <Bug pattern="NP_NULL_ON_SOME_PATH"/>
        <Package name="com.example.generated"/>
    </Match>
</FindBugsFilter>

6.2 自訂 Detector

public class CustomBugDetector extends OpcodeStackDetector {
    @Override
    public void sawOpcode(int seen) {
        // 自訂偵測邏輯
        if (seen == INVOKEVIRTUAL && getNameConstantOperand().equals("exec")) {
            reportBadPractice();
        }
    }
}

7. CI 整合

# azure-pipelines.yml
- stage: StaticAnalysis
  jobs:
    - job: SpotBugs
      steps:
        - task: Maven@4
          inputs:
            goals: 'spotbugs:check'
          displayName: 'SpotBugs Analysis'
        - task: PublishTestResults@2
          condition: failed()
          inputs:
            testResultsFiles: '**/spotbugsXml.xml'
            testResultsFormat: 'JUnit'

8. FindSecBugs(安全插件)

<!-- 安裝 FindSecBugs 插件 -->
<plugin>
    <groupId>com.github.spotbugs</groupId>
    <artifactId>spotbugs-maven-plugin</artifactId>
    <version>4.8.6.6</version>
    <configuration>
        <pluginList>
            <plugin>
                <groupId>com.h3xstream.findsecbugs</groupId>
                <artifactId>findsecbugs-plugin</artifactId>
                <version>1.13.0</version>
            </plugin>
        </pluginList>
    </configuration>
</plugin>

9. 與 ErrorProne 比較

特性 ErrorProne SpotBugs
分析層級 編譯期 Source Code Bytecode
執行速度 快(編譯整合) 較慢(獨立掃描)
規則類型 編譯錯誤/警告 深度 Bug 模式
安全分析 基本 FindSecBugs 強化
適用時機 開發時 CI 階段

10. 參考資源