agentleFS
liushikuan63liushikuan63/Qoder-Optimization/skills/java-quality/SKILL.md

java-quality

Skill2 starsChanged 11 days agoMITView on GitHub

Java code quality with Checkstyle, SpotBugs, PMD, and SonarJava。中文触发:Java 后端 JVM

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 1 is distinctive, and 3 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 3

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    SonarQube generic setup: - Use sonarqube skill

    line 9
  2. Distinctive:

    Spring Boot testing: - Use Spring Boot test skills

    line 10
  3. Very specific:

    Security scanning: - Use java-security skill

    line 11
  4. Very specific:

    Coverage reporting: - Use jacoco skill

    line 12

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Java Quality - Quick Reference

When NOT to Use This Skill

  • SonarQube generic setup - Use sonarqube skill
  • Spring Boot testing - Use Spring Boot test skills
  • Security scanning - Use java-security skill
  • Coverage reporting - Use jacoco skill

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: spring-boot for framework-specific patterns.

Tool Overview

ToolFocusSpeedIntegration
CheckstyleCode style, formattingFastMaven/Gradle
SpotBugsBug patterns, bytecodeMediumMaven/Gradle
PMDCode smells, complexityFastMaven/Gradle
SonarJavaAll-in-oneSlowSonarQube
Error ProneCompile-time bugsFastCompiler plugin

Checkstyle Setup

Maven Configuration

<!-- pom.xml -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>3.3.1</version>
    <configuration>
        <configLocation>checkstyle.xml</configLocation>
        <consoleOutput>true</consoleOutput>
        <failsOnError>true</failsOnError>
        <violationSeverity>warning</violationSeverity>
    </configuration>
    <executions>
        <execution>
            <id>validate</id>
            <phase>validate</phase>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>com.puppycrawl.tools</groupId>
            <artifactId>checkstyle</artifactId>
            <version>10.12.5</version>
        </dependency>
    </dependencies>
</plugin>

checkstyle.xml (Google Style Based)

<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
    "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
    "https://checkstyle.org/dtds/configuration_1_3.dtd">

<module name="Checker">
    <property name="severity" value="warning"/>
    <property name="fileExtensions" value="java"/>

    <module name="TreeWalker">
        <!-- Naming -->
        <module name="ConstantName"/>
        <module name="LocalVariableName"/>
        <module name="MemberName"/>
        <module name="MethodName"/>
        <module name="PackageName"/>
        <module name="ParameterName"/>
        <module name="TypeName"/>

        <!-- Imports -->
        <module name="IllegalImport"/>
        <module name="RedundantImport"/>
        <module name="UnusedImports"/>

        <!-- Size -->
        <module name="LineLength">
            <property name="max" value="120"/>
        </module>
        <module name="MethodLength">
            <property name="max" value="50"/>
        </module>
        <module name="ParameterNumber">
            <property name="max" value="5"/>
        </module>

        <!-- Complexity -->
        <module name="CyclomaticComplexity">
            <property name="max" value="10"/>
        </module>
        <module name="NPathComplexity">
            <property name="max" value="200"/>
        </module>

        <!-- Best Practices -->
        <module name="EmptyBlock"/>
        <module name="EqualsHashCode"/>
        <module name="HiddenField"/>
        <module name="MissingSwitchDefault"/>
        <module name="SimplifyBooleanExpression"/>
        <module name="SimplifyBooleanReturn"/>
    </module>

    <!-- File-level checks -->
    <module name="FileLength">
        <property name="max" value="500"/>
    </module>
    <module name="NewlineAtEndOfFile"/>
</module>

Commands

# Run Checkstyle
./mvnw checkstyle:check

# Generate report
./mvnw checkstyle:checkstyle

SpotBugs Setup

Maven Configuration

<!-- pom.xml -->
<plugin>
    <groupId>com.github.spotbugs</groupId>
    <artifactId>spotbugs-maven-plugin</artifactId>
    <version>4.8.3.0</version>
    <configuration>
        <effort>Max</effort>
        <threshold>Medium</threshold>
        <failOnError>true</failOnError>
        <plugins>
            <plugin>
                <groupId>com.h3xstream.findsecbugs</groupId>
                <artifactId>findsecbugs-plugin</artifactId>
                <version>1.12.0</version>
            </plugin>
        </plugins>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Exclude False Positives

<!-- spotbugs-exclude.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<FindBugsFilter>
    <!-- Exclude generated code -->
    <Match>
        <Package name="~.*\.generated\..*"/>
    </Match>

    <!-- Exclude specific patterns -->
    <Match>
        <Bug pattern="EI_EXPOSE_REP"/>
        <Class name="~.*Dto"/>
    </Match>
</FindBugsFilter>

Commands

# Run SpotBugs
./mvnw spotbugs:check

# Generate report
./mvnw spotbugs:spotbugs

# GUI viewer
./mvnw spotbugs:gui

Common SpotBugs Warnings

Bug IDDescriptionFix
NP_NULL_ON_SOME_PATHPossible null dereferenceAdd null check or use Optional
EI_EXPOSE_REPReturns mutable objectReturn defensive copy
MS_SHOULD_BE_FINALStatic field should be finalAdd final modifier
SQL_INJECTIONSQL injection riskUse parameterized queries
DM_DEFAULT_ENCODINGUses default encodingSpecify charset explicitly

PMD Setup

Maven Configuration

<!-- pom.xml -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <version>3.21.2</version>
    <configuration>
        <rulesets>
            <ruleset>pmd-rules.xml</ruleset>
        </rulesets>
        <failOnViolation>true</failOnViolation>
        <printFailingErrors>true</printFailingErrors>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
</plugin>

pmd-rules.xml

<?xml version="1.0"?>
<ruleset name="Custom Rules">
    <description>Custom PMD ruleset</description>

    <!-- Best Practices -->
    <rule ref="category/java/bestpractices.xml">
        <exclude name="JUnitTestContainsTooManyAsserts"/>
    </rule>

    <!-- Code Style -->
    <rule ref="category/java/codestyle.xml">
        <exclude name="AtLeastOneConstructor"/>
        <exclude name="OnlyOneReturn"/>
    </rule>

    <!-- Design -->
    <rule ref="category/java/design.xml">
        <exclude name="LawOfDemeter"/>
    </rule>

    <!-- Error Prone -->
    <rule ref="category/java/errorprone.xml"/>

    <!-- Performance -->
    <rule ref="category/java/performance.xml"/>

    <!-- Custom thresholds -->
    <rule ref="category/java/design.xml/CyclomaticComplexity">
        <properties>
            <property name="methodReportLevel" value="10"/>
        </properties>
    </rule>

    <rule ref="category/java/design.xml/CognitiveComplexity">
        <properties>
            <property name="reportLevel" value="15"/>
        </properties>
    </rule>
</ruleset>

Commands

# Run PMD
./mvnw pmd:check

# Generate report
./mvnw pmd:pmd

# Copy-paste detection
./mvnw pmd:cpd

Error Prone Setup

Maven Configuration

<!-- pom.xml -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.12.1</version>
    <configuration>
        <compilerArgs>
            <arg>-XDcompilePolicy=simple</arg>
            <arg>-Xplugin:ErrorProne</arg>
        </compilerArgs>
        <annotationProcessorPaths>
            <path>
                <groupId>com.google.errorprone</groupId>
                <artifactId>error_prone_core</artifactId>
                <version>2.24.1</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

Combined Quality Profile

All-in-One Maven Profile

<!-- pom.xml -->
<profiles>
    <profile>
        <id>quality</id>
        <build>
            <plugins>
                <!-- Checkstyle -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-checkstyle-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals><goal>check</goal></goals>
                        </execution>
                    </executions>
                </plugin>

                <!-- SpotBugs -->
                <plugin>
                    <groupId>com.github.spotbugs</groupId>
                    <artifactId>spotbugs-maven-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals><goal>check</goal></goals>
                        </execution>
                    </executions>
                </plugin>

                <!-- PMD -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-pmd-plugin</artifactId>
                    <executions>
                        <execution>
                            <goals><goal>check</goal></goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>
# Run all quality checks
./mvnw verify -Pquality

Common Code Smells & Fixes

1. God Class

// BAD - Class does too much
public class OrderService {
    public Order createOrder() { ... }
    public void sendEmail() { ... }
    public void generatePdf() { ... }
    public void calculateTax() { ... }
    public void updateInventory() { ... }
}

// GOOD - Single responsibility
public class OrderService {
    private final EmailService emailService;
    private final PdfGenerator pdfGenerator;
    private final TaxCalculator taxCalculator;
    private final InventoryService inventoryService;

    public Order createOrder(OrderRequest request) {
        Order order = buildOrder(request);
        order.setTax(taxCalculator.calculate(order));
        inventoryService.reserve(order.getItems());
        return orderRepository.save(order);
    }
}

2. Long Parameter List

// BAD
public void createUser(String name, String email, String phone,
    String address, String city, String country, String zipCode) { }

// GOOD - Use builder or DTO
public void createUser(CreateUserRequest request) { }

@Builder
public record CreateUserRequest(
    String name,
    String email,
    String phone,
    Address address
) {}

3. Feature Envy

// BAD - Method uses another object's data excessively
public double calculateTotal(Order order) {
    double total = 0;
    for (OrderItem item : order.getItems()) {
        total += item.getPrice() * item.getQuantity();
        if (item.getDiscount() > 0) {
            total -= item.getPrice() * item.getQuantity() * item.getDiscount();
        }
    }
    return total;
}

// GOOD - Move logic to Order
public class Order {
    public double calculateTotal() {
        return items.stream()
            .mapToDouble(OrderItem::getSubtotal)
            .sum();
    }
}

public class OrderItem {
    public double getSubtotal() {
        double base = price * quantity;
        return discount > 0 ? base * (1 - discount) : base;
    }
}

4. Primitive Obsession

// BAD
public void sendEmail(String email) {
    if (!email.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
        throw new IllegalArgumentException("Invalid email");
    }
}

// GOOD - Value object
public record Email(String value) {
    public Email {
        if (!value.matches("^[A-Za-z0-9+_.-]+@(.+)$")) {
            throw new IllegalArgumentException("Invalid email: " + value);
        }
    }
}

public void sendEmail(Email email) { ... }

5. Deep Nesting

// BAD
public void process(Order order) {
    if (order != null) {
        if (order.isValid()) {
            for (OrderItem item : order.getItems()) {
                if (item.isAvailable()) {
                    if (item.getQuantity() > 0) {
                        // process
                    }
                }
            }
        }
    }
}

// GOOD - Guard clauses
public void process(Order order) {
    if (order == null || !order.isValid()) {
        return;
    }

    order.getItems().stream()
        .filter(OrderItem::isAvailable)
        .filter(item -> item.getQuantity() > 0)
        .forEach(this::processItem);
}

Quality Metrics Targets

MetricTargetTool
Cyclomatic Complexity< 10Checkstyle, PMD
Cognitive Complexity< 15PMD, SonarQube
Method Length< 50 linesCheckstyle
Class Length< 500 linesCheckstyle
Parameters< 5Checkstyle
Nesting Depth< 4PMD

CI/CD Integration

GitHub Actions

name: Quality
on: [push, pull_request]

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'
          cache: maven

      - name: Run quality checks
        run: ./mvnw verify -Pquality

      - name: Upload reports
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: quality-reports
          path: |
            target/checkstyle-result.xml
            target/spotbugsXml.xml
            target/pmd.xml

Anti-Patterns

Anti-PatternWhy It's BadCorrect Approach
Suppressing all warningsHides real issuesFix or justify individually
No static analysis in CIQuality degrades over timeAdd to build pipeline
Only running CheckstyleMisses bugs and smellsCombine with SpotBugs + PMD
High complexity thresholdsAllows unmaintainable codeKeep < 10 cyclomatic
Excluding entire packagesIgnores quality in areasBe specific with exclusions

Quick Troubleshooting

IssueLikely CauseSolution
Checkstyle fails on generated codeNo exclusion patternAdd <exclude> for generated dirs
SpotBugs false positive on DTOEI_EXPOSE_REP on recordsExclude pattern for DTOs
PMD too slowAnalyzing all filesConfigure incremental analysis
Error Prone conflictsVersion mismatchAlign with JDK version
Quality gate fails in CIDifferent config locallyCommit config files

Related Skills

  • SonarQube
  • JaCoCo
  • Clean Code
  • Java Security

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.