Опирается на правила: JS-CS-1JS-CS-5 и JS-CS-X1JS-CS-X3 из Java Style Guide → раздел 9. Enforcement через Checkstyle.

Важно знать

  • Checkstyle обязателен через стандартный gradle plugin.
  • Конфиг в репо (config/checkstyle/checkstyle.xml), не submodule, не external.
  • Только механические правила: именование, импорты, отступы, whitespace.
  • Семантика (Lombok, комментарии, Java 21+) — НЕ в Checkstyle, через ucp-java-style-review.
  • maxWarnings = 0 + ignoreFailures = false обязательно.
  • Suppression с justify и до: YYYY-MM-DD.
  • Привязка к check, не checkSecurity — lint-уровень.
  • @SuppressWarnings без justify ≥ 30 символов — запрещено.

Style Guide делится на две части: механические правила (нейминг, импорты, отступы) — проверяемы регулярками, выносим в Checkstyle. Семантические правила (Lombok defaults, комментарии, Java 21+ фичи) — требуют контекста, остаются для AI-скилла ucp-java-style-review. Checkstyle и скилл — дополняющие, не альтернативные.

Подключение Checkstyle

JS-CS-1: gradle plugin + config в репо.

plugins {
    id 'checkstyle'
}

checkstyle {
    toolVersion = '10.20.2'
    configFile = file('config/checkstyle/checkstyle.xml')
    configProperties = [ 'baseDir': rootDir ]
    maxWarnings = 0
    ignoreFailures = false
}

tasks.withType(Checkstyle).configureEach {
    reports {
        xml.required = true
        html.required = true
        sarif.required = true
    }
}

sarif.required = true — output в SARIF формат публикуется в GitHub Code Scanning (как SpotBugs).

Конфиг в репо сервиса:

  • Не как submodule (тогда update требует submodule pull).
  • Не как зависимость в Maven (тогда invisible инструменты управляют правилами).
  • В config/checkstyle/checkstyle.xml — явно, читабельно, в diff.

Базовый шаблон конфига поставляется через ucp-bootstrap-design при создании нового сервиса.

Что покрывает Checkstyle

JS-CS-2: только механика.

Именование (JS-2.1JS-2.8)

<module name="TypeName">
    <property name="format" value="^[A-Z][a-zA-Z0-9]*$"/>
</module>
<module name="MethodName">
    <property name="format" value="^[a-z][a-zA-Z0-9_]*$"/>
</module>
<module name="PackageName">
    <property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
</module>
<module name="ConstantName">
    <property name="format" value="^[A-Z][A-Z0-9_]*$"/>
</module>
<module name="LocalVariableName">
    <property name="format" value="^[a-z][a-zA-Z0-9]*$"/>
</module>

MethodName разрешает _ в test methods (createOrder_whenValid_returns201JS-2.6.1).

Импорты (JS-3.1, JS-3.2)

<module name="AvoidStarImport">
    <property name="excludes" value="java.util"/>
</module>
<module name="UnusedImports"/>
<module name="CustomImportOrder">
    <property name="customImportOrderRules"
              value="STANDARD_JAVA_PACKAGE###THIRD_PARTY_PACKAGE###SPECIAL_IMPORTS"/>
    <property name="separateLineBetweenGroups" value="true"/>
</module>

AvoidStarImport с исключением java.util (см. Импорты).

Отступы (JS-5.1JS-5.3)

<module name="LineLength">
    <property name="max" value="120"/>
</module>
<module name="Indentation">
    <property name="basicOffset" value="4"/>
    <property name="braceAdjustment" value="0"/>
    <property name="caseIndent" value="4"/>
</module>

Whitespace

<module name="WhitespaceAround"/>
<module name="EmptyLineSeparator">
    <property name="allowMultipleEmptyLines" value="false"/>
</module>
<module name="NoWhitespaceBefore"/>

Что НЕ покрывает Checkstyle

JS-CS-2 (запрет): семантика остаётся скиллу.

ПравилоПочему не Checkstyle
JS-6.1 @RequiredArgsConstructor обязателенТребует контекста (есть ли DI-зависимости в final fields)
JS-6.5 @Data запрещёнRegex может ловить, но в legacy местах есть много false positive
JS-7.5 Javadoc не используем/** ... */ блок может быть obvious-комментарием
JS-8.4 Exhaustive switch без defaultТребует знания sealed-иерархии
JS-2.5 Аббревиатуры 2 vs 3 буквыRegex слишком complex для надёжности

Эти проверяет ucp-java-style-review (AI-скилл) при PR review.

Не пытайтесь натянуть semantic-правила через regex в Checkstyle — false positives заспамят dashboard, команда начнёт игнорировать.

maxWarnings + ignoreFailures

JS-CS-3: жёсткий enforcement.

checkstyle {
    maxWarnings = 0
    ignoreFailures = false
}
  • maxWarnings = 0 — любой warning ломает сборку.
  • ignoreFailures = false./gradlew check упадёт при finding.

Без этого — Checkstyle выводит warnings, никто не смотрит. Через год — тысячи warnings, любая попытка добавить новое правило заваливается на старом долге.

Suppression

JS-CS-3 (suppression): срок и justify обязательны.

<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
    "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
    "https://checkstyle.org/dtds/suppressions_1_2.dtd">
<suppressions>
    <!-- justify: legacy package с auto-generated классами; рефакторинг до 2026-09-01 -->
    <suppress files=".*[/\\]generated[/\\].*" checks="."/>

    <!-- justify: jOOQ generated POJOs требуют CamelCase с большой буквы (ConnectorsPojo); до: never (generated code) -->
    <suppress files=".*Pojo\.java" checks="TypeName"/>
</suppressions>

По аналогии с security suppressions:

  • justify обязателен.
  • до: YYYY-MM-DD — срок пересмотра. Для generated кода — never.

Раз в квартал — script ищет expired suppressions.

Привязка к check

JS-CS-4: lint-уровень.

tasks.named('check') {
    dependsOn 'checkstyleMain', 'checkstyleTest'
}

Checkstyle прогоняется на каждом ./gradlew check (включая тесты). Не security-уровень (как SpotBugs+FindSecBugs в checkSecurity), а lint — проверяется быстро, на каждом локальном build.

В CI:

  • PR build./gradlew check (включает Checkstyle).
  • Merge build — то же.
  • Release build — то же.

@SuppressWarnings в коде

JS-CS-X1: только с justification.

// ✓ — явная причина
@SuppressWarnings("checkstyle:MethodLength")
// justify: complex state machine, decomposition планируется до 2026-09-30
public void processOrderStateMachine(Order order, OrderEvent event) {
    // 200+ lines of state logic
}

// ✗ — без justification
@SuppressWarnings("checkstyle:MethodLength")
public void processOrderStateMachine(Order order, OrderEvent event) { ... }

ucp-java-style-review проверяет: при наличии @SuppressWarnings("checkstyle:...") — должен быть комментарий-justify ≥ 30 символов в соседних строках.

Что запрещено

АнтипаттернПравилоЧто взамен
@SuppressWarnings("checkstyle:...") без justifyJS-CS-X1комментарий ≥ 30 символов
Удалить правило из checkstyle.xml локальноJS-CS-X2обсудить с командой, обновить для всех
Checkstyle для семантики (regex для cyclomatic)JS-CS-X3ucp-java-style-review
maxWarnings > 0JS-CS-30
ignoreFailures = trueJS-CS-3false
Конфиг как submoduleJS-CS-1в репо сервиса
Suppression без до:JS-CS-3срок обязателен
Без SARIF outputJS-CS-1sarif.required = true

Куда дальше

  • Java → раздел 9. Enforcement через Checkstyle — нормативные формулировки.
  • Именование — TypeName, MethodName, etc.
  • Импорты — AvoidStarImport, UnusedImports.
  • Отступы и форматирование — LineLength, Indentation.
  • Lombok — НЕ в Checkstyle, в AI-скилле.
  • Комментарии — Javadoc НЕ в Checkstyle.
  • Security → SAST — параллельный enforcement через SpotBugs.
  • Security → findings response — общий suppression-паттерн.