java@v1
Hygiene checks for Java projects (Maven + Gradle). Adopt it with:
extends: - alint://bundled/java@v1 Gated with when: facts.has_java (true if any Java build
manifest exists anywhere in the tree) plus a per-rule
scope_filter: { has_ancestor: [pom.xml, build.gradle, build.gradle.kts] } on per-file content rules so they only
apply to files inside a Java module — useful in polyglot
monorepos where Java modules sit alongside Rust / Node /
Python subdirectories.
Build outputs (target/ for Maven, build/ for Gradle) are
checked with git_tracked_only: true so a developer's
locally-built artefacts don't trigger the rule — only
committed contents do, and those are what the rule checks.
What it checks
Section titled "What it checks"10 rules. Each links to its section below, which explains the check and shows its definition.
| Rule | Reports |
|---|---|
java-manifest-existserror | Java project: pom.xml (Maven) or build.gradle / build.gradle.kts (Gradle) at the root is required. |
java-build-wrapper-committedinfo | A committed build wrapper (mvnw for Maven, gradlew for Gradle) lets contributors and CI build the project without pre-installing the right Maven / Gradle version. |
java-no-tracked-targeterror | Maven's target/ is a build directory and shouldn't be committed. |
java-no-tracked-builderror | Gradle's build/ is a build directory and shouldn't be committed. |
java-no-class-fileserror | Compiled .class files don't belong in version control. |
java-sources-pascal-casewarning | Java filenames should match the public class name (PascalCase). |
java-sources-final-newlineinfo | File must end with a single \n. |
java-sources-no-trailing-whitespaceinfo | No line may end with space or tab. |
java-sources-no-bidierror | Trojan Source (CVE-2021-42574): bidi override chars in Java sources are rejected. |
java-sources-no-zero-widtherror | Zero-width characters in Java sources are rejected (review hazard). |
All 10 rules run only when facts.has_java holds, so the ruleset stays quiet in repositories it doesn't apply to.
java-manifest-exists
Section titled "java-manifest-exists"Maven (pom.xml) or Gradle (Groovy or Kotlin DSL). Either is fine; mixed setups are unusual but valid.
- kind:
file_exists - level:
error - when:
facts.has_java - policy: https://maven.apache.org/guides/introduction/introduction-to-the-pom.html
Java project:
pom.xml(Maven) orbuild.gradle/build.gradle.kts(Gradle) at the root is required.
- id: java-manifest-exists when: facts.has_java kind: file_exists paths: - pom.xml - build.gradle - build.gradle.kts root_only: true level: error message: >- Java project: `pom.xml` (Maven) or `build.gradle` / `build.gradle.kts` (Gradle) at the root is required. policy_url: "https://maven.apache.org/guides/introduction/introduction-to-the-pom.html" java-build-wrapper-committed
Section titled "java-build-wrapper-committed"mvnw (Maven Wrapper) or gradlew (Gradle Wrapper) make CI builds and contributor onboarding deterministic. Either script suffices.
- kind:
file_exists - level:
info - when:
facts.has_java - policy: https://docs.gradle.org/current/userguide/gradle_wrapper.html
A committed build wrapper (
mvnwfor Maven,gradlewfor Gradle) lets contributors and CI build the project without pre-installing the right Maven / Gradle version.
- id: java-build-wrapper-committed when: facts.has_java kind: file_exists paths: - mvnw - gradlew root_only: true level: info message: >- A committed build wrapper (`mvnw` for Maven, `gradlew` for Gradle) lets contributors and CI build the project without pre-installing the right Maven / Gradle version. policy_url: "https://docs.gradle.org/current/userguide/gradle_wrapper.html" java-no-tracked-target
Section titled "java-no-tracked-target"git_tracked_only: true makes the rule fire only if target/ is *committed* — a developer's locally-built target/ (gitignored, no tracked content) is silently OK. Same shape for Gradle's build/.
- kind:
dir_absent - level:
error - when:
facts.has_java
Maven's
target/is a build directory and shouldn't be committed. Addtarget/to your.gitignore.
- id: java-no-tracked-target when: facts.has_java kind: dir_absent paths: "**/target" git_tracked_only: true level: error message: >- Maven's `target/` is a build directory and shouldn't be committed. Add `target/` to your `.gitignore`. java-no-tracked-build
Section titled "java-no-tracked-build"- kind:
dir_absent - level:
error - when:
facts.has_java
Gradle's
build/is a build directory and shouldn't be committed. Addbuild/to your.gitignore.
- id: java-no-tracked-build when: facts.has_java kind: dir_absent paths: "**/build" git_tracked_only: true level: error message: >- Gradle's `build/` is a build directory and shouldn't be committed. Add `build/` to your `.gitignore`. java-no-class-files
Section titled "java-no-class-files"- kind:
file_absent - level:
error - when:
facts.has_java
Compiled
.classfiles don't belong in version control. Build them from the.javasources instead.
- id: java-no-class-files when: facts.has_java kind: file_absent paths: "**/*.class" git_tracked_only: true level: error message: >- Compiled `.class` files don't belong in version control. Build them from the `.java` sources instead.java-sources-pascal-case
Section titled "java-sources-pascal-case"Java's class-file convention: every public top-level type lives in a file named after it, in PascalCase. Some repositories ship package-info.java / module-info.java (lowercase, snake-shaped) — those are the only standard exceptions, so they're excluded.
- kind:
filename_case - level:
warning - when:
facts.has_java
Java filenames should match the public class name (PascalCase).
- id: java-sources-pascal-case when: facts.has_java kind: filename_case paths: include: ["**/*.java" ] exclude: - "**/package-info.java" - "**/module-info.java" case: pascal level: warning message: "Java filenames should match the public class name (PascalCase)."java-sources-final-newline
Section titled "java-sources-final-newline"- kind:
final_newline - level:
info - when:
facts.has_java - fix:
file_append_final_newline(applied byalint fix)
- id: java-sources-final-newline when: facts.has_java kind: final_newline paths: "**/*.java" scope_filter: has_ancestor: [pom.xml, build.gradle, build.gradle.kts] level: info fix: file_append_final_newline: {}java-sources-no-trailing-whitespace
Section titled "java-sources-no-trailing-whitespace"- kind:
no_trailing_whitespace - level:
info - when:
facts.has_java - fix:
file_trim_trailing_whitespace(applied byalint fix)
- id: java-sources-no-trailing-whitespace when: facts.has_java kind: no_trailing_whitespace paths: "**/*.java" scope_filter: has_ancestor: [pom.xml, build.gradle, build.gradle.kts] level: info fix: file_trim_trailing_whitespace: {}java-sources-no-bidi
Section titled "java-sources-no-bidi"- kind:
no_bidi_controls - level:
error - when:
facts.has_java - policy: https://trojansource.codes/
Trojan Source (CVE-2021-42574): bidi override chars in Java sources are rejected.
- id: java-sources-no-bidi when: facts.has_java kind: no_bidi_controls paths: "**/*.java" scope_filter: has_ancestor: [pom.xml, build.gradle, build.gradle.kts] level: error message: "Trojan Source (CVE-2021-42574): bidi override chars in Java sources are rejected." policy_url: "https://trojansource.codes/" java-sources-no-zero-width
Section titled "java-sources-no-zero-width"- kind:
no_zero_width_chars - level:
error - when:
facts.has_java
Zero-width characters in Java sources are rejected (review hazard).
- id: java-sources-no-zero-width when: facts.has_java kind: no_zero_width_chars paths: "**/*.java" scope_filter: has_ancestor: [pom.xml, build.gradle, build.gradle.kts] level: error message: "Zero-width characters in Java sources are rejected (review hazard)."The when: clauses above read these facts. Each is resolved once per run; alint facts prints what they resolved to in your repository.
facts: - id: has_java any_file_exists: - pom.xml - "**/pom.xml" - build.gradle - "**/build.gradle" - build.gradle.kts - "**/build.gradle.kts" - settings.gradle - "**/settings.gradle" - settings.gradle.kts - "**/settings.gradle.kts" Customize
Section titled "Customize"Every rule here can be overridden by id from your own .alint.yml: change its level, or set level: off to drop it. An id that doesn't exist is an error at config load, so a typo can't silently pass.
extends: - alint://bundled/java@v1 rules: - id: java-manifest-exists level: off - id: java-build-wrapper-committed level: errorTo take only part of the ruleset, filter it where you extend it with only: or except::
extends: - url: alint://bundled/java@v1 except: [java-manifest-exists]Bundled rulesets covers versioning and how rulesets combine.
Source
Section titled "Source"The full ruleset definition, comments included, is committed at crates/alint-dsl/rulesets/v1/java.yml in the alint repo.