Skip to content

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.

10 rules. Each links to its section below, which explains the check and shows its definition.

RuleReports
java-manifest-exists
error
Java project: pom.xml (Maven) or build.gradle / build.gradle.kts (Gradle) at the root is required.
java-build-wrapper-committed
info
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-target
error
Maven's target/ is a build directory and shouldn't be committed.
java-no-tracked-build
error
Gradle's build/ is a build directory and shouldn't be committed.
java-no-class-files
error
Compiled .class files don't belong in version control.
java-sources-pascal-case
warning
Java filenames should match the public class name (PascalCase).
java-sources-final-newline
info
File must end with a single \n.
java-sources-no-trailing-whitespace
info
No line may end with space or tab.
java-sources-no-bidi
error
Trojan Source (CVE-2021-42574): bidi override chars in Java sources are rejected.
java-sources-no-zero-width
error
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.

Maven (pom.xml) or Gradle (Groovy or Kotlin DSL). Either is fine; mixed setups are unusual but valid.

Java project: pom.xml (Maven) or build.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"

mvnw (Maven Wrapper) or gradlew (Gradle Wrapper) make CI builds and contributor onboarding deterministic. Either script suffices.

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.

- 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"

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. Add target/ 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`.
  • kind: dir_absent
  • level: error
  • when: facts.has_java

Gradle's build/ is a build directory and shouldn't be committed. Add build/ 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`.

Compiled .class files don't belong in version control. Build them from the .java sources 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'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.

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)."
  • kind: final_newline
  • level: info
  • when: facts.has_java
  • fix: file_append_final_newline (applied by alint 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 by alint 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: {}

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/"

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"

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: error

To 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.

The full ruleset definition, comments included, is committed at crates/alint-dsl/rulesets/v1/java.yml in the alint repo.