Checkstyle

Code QualityLinterJavaDevOpsStatic AnalysisCoding StandardsGoogle Java Style

DevOps Tool

Checkstyle

Overview

Checkstyle is a static code analysis tool for Java developers to write code that adheres to coding standards. It supports Google Java Style Guide and Sun Code Conventions by default with highly configurable customization options. Supporting Ant task and command line execution, it integrates with build tools like Maven and Gradle to enable automated quality checks in CI/CD pipelines. As an industry-standard tool with 154 code snippets and a trust score of 8.3, it ensures consistent code quality in Java development.

Details

Checkstyle was initiated by Oliver Burn in 2001 and is now actively developed by the open-source community. It serves as the industry-standard tool for automating coding standard compliance and achieving consistent code quality across teams in Java development.

Key Features

  • Comprehensive Coding Standard Checks: Support for Google Java Style Guide, Sun Code Conventions, and other standards
  • Rich Check Items: 200+ checks including naming conventions, code layout, class design, metrics
  • Advanced Configuration: Detailed customization and rule adjustment via XML configuration files
  • Multiple Execution Methods: Command line, Ant tasks, Maven, Gradle integration
  • IDE Integration: Support for major editors like Eclipse, IntelliJ IDEA, VS Code
  • Suppression Features: Ignore specific violations with SUPPRESS CHECKSTYLE comments
  • Flexible Output Formats: Various report formats including XML, plain text, HTML
  • TreeWalker Architecture: High-precision analysis based on AST
  • Extensibility: Support for custom check module development

2025 Features

  • Java 21+ Support: Full support for latest Java language features (Record, Pattern Matching, etc.)
  • Performance Improvements: Optimized analysis speed for large projects
  • Enhanced CI/CD: Deep integration with GitHub Actions, GitLab CI, etc.
  • Security Checks: Extended vulnerability pattern detection capabilities

Pros and Cons

Pros

  • Automatic enforcement of standard coding conventions in Java development
  • Comprehensive code quality management with 200+ rich check items
  • Full compliance with industry standards like Google Java Style Guide
  • Flexible rule customization for enterprise standards via XML configuration
  • Complete integration with major build tools like Maven and Gradle
  • Real-time code quality feedback through IDE integration
  • Violation suppression capability when necessary via SUPPRESS COMMENTS
  • High-precision static code analysis through AST-based analysis
  • Automated quality gates and code review efficiency through CI/CD integration
  • Detailed quality status visualization through rich output formats

Cons

  • Limited to unified tool usage in multilingual projects due to Java-only focus
  • Complexity of detailed configuration and initial learning costs
  • Long analysis times for large projects
  • Risk of development speed reduction due to excessive rule application
  • Introduction burden from massive warnings in legacy codebases
  • High technical requirements for custom check development
  • Maintenance burden from configuration file complexity
  • Need for coding standard consensus formation within teams
  • False positives from some checks
  • Increased runtime JVM memory requirements

Reference Links

Code Examples

Installation and Basic Setup

JAR File Installation

# Download latest version
wget https://github.com/checkstyle/checkstyle/releases/download/checkstyle-10.18.1/checkstyle-10.18.1-all.jar

# Local installation verification
java -jar checkstyle-10.18.1-all.jar --version

# Basic execution example
java -jar checkstyle-10.18.1-all.jar -c config.xml Test.java

# System path placement
sudo mv checkstyle-10.18.1-all.jar /usr/local/bin/checkstyle.jar
echo 'alias checkstyle="java -jar /usr/local/bin/checkstyle.jar"' >> ~/.bashrc
source ~/.bashrc

Maven Integration

<!-- pom.xml -->
<project>
    <properties>
        <checkstyle.version>10.18.1</checkstyle.version>
        <checkstyle.config.location>config/checkstyle.xml</checkstyle.config.location>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-checkstyle-plugin</artifactId>
                <version>3.4.0</version>
                <configuration>
                    <configLocation>${checkstyle.config.location}</configLocation>
                    <includeTestSourceDirectory>true</includeTestSourceDirectory>
                    <failOnViolation>true</failOnViolation>
                    <violationSeverity>warning</violationSeverity>
                    <consoleOutput>true</consoleOutput>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>com.puppycrawl.tools</groupId>
                        <artifactId>checkstyle</artifactId>
                        <version>${checkstyle.version}</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <id>checkstyle</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>check</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <!-- Report generation -->
    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-checkstyle-plugin</artifactId>
                <version>3.4.0</version>
                <configuration>
                    <configLocation>${checkstyle.config.location}</configLocation>
                </configuration>
            </plugin>
        </plugins>
    </reporting>
</project>

Gradle Integration

// build.gradle
plugins {
    id 'java'
    id 'checkstyle'
}

checkstyle {
    toolVersion = '10.18.1'
    configFile = file('config/checkstyle.xml')
    ignoreFailures = false
    maxWarnings = 0
    maxErrors = 0
    
    // Java 8+ support
    configProperties = [
        'org.checkstyle.google.suppressionfilter.config': 'config/checkstyle-suppressions.xml'
    ]
}

// Source set configuration
checkstyleMain {
    source = 'src/main/java'
    include '**/*.java'
    exclude '**/generated-sources/**'
    
    reports {
        xml.required = true
        html.required = true
        sarif.required = true
    }
}

checkstyleTest {
    source = 'src/test/java'
    include '**/*.java'
}

// Task dependencies
tasks.named('check').configure {
    dependsOn 'checkstyleMain', 'checkstyleTest'
}

// Auto-execution during build
compileJava.dependsOn checkstyleMain
compileTestJava.dependsOn checkstyleTest

Basic Configuration File (checkstyle.xml)

Google Java Style Guide Configuration

<?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="charset" value="UTF-8"/>
    <property name="severity" value="warning"/>
    <property name="fileExtensions" value="java, properties, xml"/>
    
    <!-- Header checks -->
    <module name="FileTabCharacter">
        <property name="eachLine" value="true"/>
    </module>
    
    <module name="NewlineAtEndOfFile">
        <property name="lineSeparator" value="lf"/>
    </module>
    
    <!-- Size Violations -->
    <module name="FileLength">
        <property name="max" value="2000"/>
    </module>
    
    <!-- Whitespace -->
    <module name="LineLength">
        <property name="max" value="100"/>
        <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
    </module>
    
    <module name="TreeWalker">
        <!-- Annotations -->
        <module name="AnnotationLocation">
            <property name="id" value="AnnotationLocationMostCases"/>
            <property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
        </module>
        
        <module name="AnnotationLocation">
            <property name="id" value="AnnotationLocationVariables"/>
            <property name="tokens" value="VARIABLE_DEF"/>
            <property name="allowSamelineMultipleAnnotations" value="true"/>
        </module>
        
        <!-- Block Checks -->
        <module name="EmptyBlock">
            <property name="option" value="TEXT"/>
            <property name="tokens" value="LITERAL_TRY, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
        </module>
        
        <module name="LeftCurly">
            <property name="tokens" value="ANNOTATION_DEF, CLASS_DEF, CTOR_DEF, ENUM_CONSTANT_DEF, ENUM_DEF,
                                           INTERFACE_DEF, LAMBDA, LITERAL_CASE, LITERAL_CATCH, LITERAL_DEFAULT,
                                           LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF,
                                           LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE, METHOD_DEF,
                                           OBJBLOCK, STATIC_INIT"/>
        </module>
        
        <module name="RightCurly">
            <property name="id" value="RightCurlySame"/>
            <property name="tokens" value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE,
                                           LITERAL_DO"/>
        </module>
        
        <!-- Class Design -->
        <module name="FinalClass"/>
        <module name="InterfaceIsType"/>
        <module name="HideUtilityClassConstructor"/>
        
        <!-- Coding -->
        <module name="EmptyStatement"/>
        <module name="EqualsHashCode"/>
        <module name="IllegalInstantiation"/>
        <module name="InnerAssignment"/>
        <module name="MagicNumber">
            <property name="ignoreNumbers" value="-1, 0, 1, 2"/>
            <property name="ignoreHashCodeMethod" value="true"/>
            <property name="ignoreAnnotation" value="true"/>
        </module>
        
        <module name="SimplifyBooleanExpression"/>
        <module name="SimplifyBooleanReturn"/>
        
        <!-- Imports -->
        <module name="AvoidStarImport"/>
        <module name="IllegalImport"/>
        <module name="RedundantImport"/>
        <module name="UnusedImports">
            <property name="processJavadoc" value="false"/>
        </module>
        
        <!-- Javadoc Comments -->
        <module name="InvalidJavadocPosition"/>
        <module name="JavadocMethod">
            <property name="allowMissingParamTags" value="true"/>
            <property name="allowMissingReturnTag" value="true"/>
            <property name="allowedAnnotations" value="Override, Test"/>
        </module>
        
        <!-- Naming Conventions -->
        <module name="ConstantName"/>
        <module name="LocalFinalVariableName"/>
        <module name="LocalVariableName"/>
        <module name="MemberName"/>
        <module name="MethodName"/>
        <module name="PackageName">
            <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
        </module>
        
        <module name="ParameterName"/>
        <module name="StaticVariableName"/>
        <module name="TypeName"/>
        
        <!-- Size Violations -->
        <module name="AnonInnerLength">
            <property name="max" value="20"/>
        </module>
        
        <module name="MethodLength">
            <property name="max" value="150"/>
        </module>
        
        <module name="ParameterNumber">
            <property name="max" value="7"/>
        </module>
        
        <!-- Whitespace -->
        <module name="GenericWhitespace"/>
        <module name="MethodParamPad"/>
        <module name="NoWhitespaceAfter"/>
        <module name="NoWhitespaceBefore"/>
        <module name="OperatorWrap"/>
        <module name="ParenPad"/>
        <module name="TypecastParenPad"/>
        <module name="WhitespaceAfter"/>
        <module name="WhitespaceAround"/>
    </module>
    
    <!-- Suppressions -->
    <module name="SuppressionFilter">
        <property name="file" value="config/checkstyle-suppressions.xml"/>
        <property name="optional" value="true"/>
    </module>
</module>

Suppression Configuration File (checkstyle-suppressions.xml)

<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
        "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
        "https://checkstyle.org/dtds/suppressions_1_2.dtd">

<suppressions>
    <!-- Generated files -->
    <suppress checks="." files=".*[\\/]generated-sources[\\/].*"/>
    <suppress checks="." files=".*[\\/]target[\\/].*"/>
    <suppress checks="." files=".*[\\/]build[\\/].*"/>
    
    <!-- Test files relaxed rules -->
    <suppress checks="MagicNumber" files=".*Test\.java"/>
    <suppress checks="JavadocMethod" files=".*Test\.java"/>
    <suppress checks="JavadocType" files=".*Test\.java"/>
    
    <!-- Legacy code -->
    <suppress checks="LineLength" files="LegacyClass\.java"/>
    <suppress checks="MethodLength" files="LegacyProcessor\.java"/>
    
    <!-- Third-party code -->
    <suppress checks="." files=".*[\\/]vendor[\\/].*"/>
    <suppress checks="." files=".*[\\/]lib[\\/].*"/>
    
    <!-- Configuration classes -->
    <suppress checks="HideUtilityClassConstructor" files=".*Config\.java"/>
    <suppress checks="FinalClass" files=".*Configuration\.java"/>
</suppressions>

Execution Methods and Command Line Usage

Basic Command Line Execution

# Basic execution
java -jar checkstyle-10.18.1-all.jar -c config.xml src/

# Check specific file
java -jar checkstyle-10.18.1-all.jar -c config.xml src/main/java/User.java

# Specify output format
java -jar checkstyle-10.18.1-all.jar -c config.xml -f xml src/ > checkstyle-report.xml
java -jar checkstyle-10.18.1-all.jar -c config.xml -f plain src/

# Specify properties
java -jar checkstyle-10.18.1-all.jar -c config.xml -p checkstyle.properties src/

# Verbose output
java -jar checkstyle-10.18.1-all.jar -c config.xml -v src/

# Exclude specific files
java -jar checkstyle-10.18.1-all.jar -c config.xml -e "**/test/**" src/

Maven Execution Commands

# Run check
mvn checkstyle:check

# Generate report
mvn checkstyle:checkstyle

# Generate report (site)
mvn site

# Specify configuration file
mvn checkstyle:check -Dcheckstyle.config.location=config/custom-checkstyle.xml

# Allow violations (warnings only)
mvn checkstyle:check -Dcheckstyle.failOnViolation=false

# Exclude specific files
mvn checkstyle:check -Dcheckstyle.excludes=**/generated-sources/**

Gradle Execution Commands

# Basic check execution
./gradlew checkstyleMain

# Run all checks
./gradlew check

# Include tests
./gradlew checkstyleMain checkstyleTest

# Check reports
./gradlew checkstyleMain --info

# Continue on failure
./gradlew checkstyleMain --continue

# Check configuration
./gradlew checkstyleMain --dry-run

IDE Integration Configuration

IntelliJ IDEA Configuration

# Install IntelliJ IDEA Checkstyle-IDEA plugin
# File → Settings → Plugins → Search for "Checkstyle-IDEA" and install

# Configuration steps:
# File → Settings → Tools → Checkstyle
# Configuration File: Add config/checkstyle.xml
# Active: Set the added configuration as active

# Enable real-time checking
# File → Settings → Editor → Inspections → Checkstyle
# Select and activate desired rules

Eclipse Configuration

# Install Eclipse Checkstyle Plugin
# Help → Eclipse Marketplace → Search for "Checkstyle"

# Project configuration:
# Project Properties → Checkstyle
# Check "Checkstyle active for this project"
# Local Check Configurations: Add config/checkstyle.xml
# Main: Select the added configuration

# Auto-execution configuration
# Window → Preferences → Checkstyle
# Enable "Check code with Checkstyle"

VS Code Configuration

// .vscode/settings.json
{
    "java.checkstyle.configuration": "./config/checkstyle.xml",
    "java.checkstyle.version": "10.18.1",
    "java.format.settings.url": "./config/checkstyle.xml",
    "java.format.settings.profile": "GoogleStyle",
    "[java]": {
        "editor.defaultFormatter": "redhat.java",
        "editor.formatOnSave": true,
        "editor.rulers": [100]
    },
    "java.saveActions.organizeImports": true,
    "java.completion.importOrder": [
        "java",
        "javax",
        "org",
        "com"
    ]
}

CI/CD Integration Examples

GitHub Actions

# .github/workflows/checkstyle.yml
name: Checkstyle

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  checkstyle:
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Setup Java
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'
    
    - name: Cache Maven dependencies
      uses: actions/cache@v4
      with:
        path: ~/.m2
        key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
        restore-keys: ${{ runner.os }}-m2
    
    - name: Run Checkstyle
      run: mvn checkstyle:check
    
    - name: Generate Checkstyle Report
      if: always()
      run: mvn checkstyle:checkstyle
    
    - name: Upload Checkstyle Report
      if: always()
      uses: actions/upload-artifact@v4
      with:
        name: checkstyle-report
        path: target/site/checkstyle.html
    
    - name: Comment PR with Results
      if: github.event_name == 'pull_request' && failure()
      uses: actions/github-script@v7
      with:
        script: |
          github.rest.issues.createComment({
            issue_number: context.issue.number,
            owner: context.repo.owner,
            repo: context.repo.repo,
            body: '❌ Checkstyle violations found. Please check the uploaded report.'
          })

GitLab CI/CD

# .gitlab-ci.yml
variables:
  MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"

cache:
  paths:
    - .m2/repository/

stages:
  - quality

checkstyle:
  stage: quality
  image: maven:3.9.6-openjdk-17-slim
  script:
    - mvn checkstyle:check
    - mvn checkstyle:checkstyle
  artifacts:
    reports:
      codequality: target/checkstyle-result.xml
    paths:
      - target/site/checkstyle.html
      - target/checkstyle-result.xml
    expire_in: 1 week
  only:
    - main
    - develop
    - merge_requests
  allow_failure: true

Custom Check Development Example

Custom Check Class

// src/main/java/com/company/checkstyle/checks/CustomNamingCheck.java
package com.company.checkstyle.checks;

import com.puppycrawl.tools.checkstyle.StatelessCheck;
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;

@StatelessCheck
public class CustomNamingCheck extends AbstractCheck {
    
    private static final String MSG_INVALID_PATTERN = "name.invalidPattern";
    
    /** Allowed pattern */
    private String format = "^[a-z][a-zA-Z0-9]*$";
    
    @Override
    public int[] getDefaultTokens() {
        return new int[] {
            TokenTypes.VARIABLE_DEF,
            TokenTypes.METHOD_DEF,
            TokenTypes.CLASS_DEF
        };
    }
    
    @Override
    public int[] getAcceptableTokens() {
        return getDefaultTokens();
    }
    
    @Override
    public int[] getRequiredTokens() {
        return new int[0];
    }
    
    @Override
    public void visitToken(DetailAST ast) {
        final DetailAST nameAST = ast.findFirstToken(TokenTypes.IDENT);
        if (nameAST != null) {
            final String name = nameAST.getText();
            if (!name.matches(format)) {
                log(nameAST.getLineNo(),
                    nameAST.getColumnNo(),
                    MSG_INVALID_PATTERN,
                    name,
                    format);
            }
        }
    }
    
    /**
     * Set pattern
     * @param format regex pattern
     */
    public void setFormat(String format) {
        this.format = format;
    }
}

Custom Check Configuration

<!-- config/custom-checkstyle.xml -->
<?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">
    <module name="TreeWalker">
        <!-- Custom check -->
        <module name="com.company.checkstyle.checks.CustomNamingCheck">
            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
            <message key="name.invalidPattern" 
                     value="Name ''{0}'' must match pattern ''{1}''"/>
        </module>
        
        <!-- Standard checks -->
        <module name="MethodName">
            <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
        </module>
    </module>
</module>

Troubleshooting and Debugging

Configuration File Debugging

# Configuration file validation
java -jar checkstyle-10.18.1-all.jar -c config.xml --debug src/

# XML syntax check
xmllint --noout config/checkstyle.xml

# Detailed configuration file analysis
java -jar checkstyle-10.18.1-all.jar -c config.xml -v --debug src/ 2>&1 | grep -E "(ERROR|WARN)"

# Suppression configuration check
java -jar checkstyle-10.18.1-all.jar -c config.xml -s config/checkstyle-suppressions.xml src/

Performance Optimization

# Parallel execution (Gradle)
./gradlew checkstyleMain --parallel --max-workers=4

# Memory settings
export MAVEN_OPTS="-Xmx2g"
mvn checkstyle:check

# Effective cache usage
./gradlew checkstyleMain --build-cache

# Profile execution
java -XX:+PrintGCDetails -jar checkstyle-10.18.1-all.jar -c config.xml src/

Common Issues and Solutions

# XML parsing issues
# Cause: Configuration file syntax errors
# Solution: Validate with xmllint --noout config.xml

# Out of memory
# Cause: OOM in large projects
# Solution: Increase memory with -Xmx4g etc.

# Character encoding issues
# Cause: File encoding mismatch
# Solution: Set <property name="charset" value="UTF-8"/>

# Plugin version conflicts
# Cause: Version mismatch between Checkstyle and plugin
# Solution: Explicit dependency specification

# Massive warnings
# Cause: Overly strict rule configuration
# Solution: Gradual introduction and suppression configuration usage