Skip to content

Enable the javac -Xlint categories that Error Prone cannot see - #67

Open
ThoSap wants to merge 3 commits into
replace-checkstyle-rules-with-error-pronefrom
enable-javac-lint-categories-and-fix-deprecations
Open

Enable the javac -Xlint categories that Error Prone cannot see#67
ThoSap wants to merge 3 commits into
replace-checkstyle-rules-with-error-pronefrom
enable-javac-lint-categories-and-fix-deprecations

Conversation

@ThoSap

@ThoSap ThoSap commented Sep 6, 2026

Copy link
Copy Markdown
Member

Follow-up to the Checkstyle removal #66
Error Prone reads the typed javac AST, so it cannot see everything the compiler sees.
This PR turns on the 14 lint categories that only javac can check, and fixes the 4 warnings they surfaced.

The build now compiles with 0 warnings and 0 notes.

Why

Error Prone and javac lint look at different things:

Error Prone javac -Xlint
Input The typed AST - types, symbols, dataflow, a parsed Javadoc AST The compiler's own view: erasure, deprecation metadata, class-file resolution, raw source text
Owns Everything expressible on the AST, bug rules and style rules alike Type-system results, the deprecation machinery, language-evolution traps, and the build itself

The 82 Error Prone checks cover the AST side well. This PR closes the other side.
It deliberately does not enable a category that an Error Prone check already owns, so no problem is reported twice.

Where both can check a rule, Error Prone wins: it has per-check severity, so a rule fails the build on its own, while a javac lint category can only warn unless -Werror promotes every warning at once.

The 14 enabled categories

Code quality (11)

Category Why it earns its place here
deprecation Was reported only as a summary note before, so 3 real hits sat unseen
removal API marked for removal. Already on by default in javac; listed so the policy is explicit
unchecked Unchecked conversions. Also only a note before
cast Unnecessary casts. No Error Prone counterpart exists
rawtypes Raw type use. No Error Prone counterpart exists
divzero Division by constant zero. No Error Prone counterpart exists
this-escape A constructor calls a method an external subclass could override. Relevant with Lombok generating constructors
identity Locking on a value-based class. The JDK 25 name; synchronization is now a deprecated alias. Error Prone's ValueClassIdentity exists only at HEAD, not in 2.50.0
text-blocks Inconsistent whitespace in text-block indentation. The project writes SQL in text blocks
dangling-doc-comments A doc comment attached to no declaration. The best fit for this codebase, which documents with /// markdown comments
restricted A call to a restricted method: the FFM downcall surface, MemorySegment.reinterpret, System.load and System.loadLibrary. Zero use today, so this is pure insurance

Build hygiene (3)

Category Why
options A bad command-line option, such as a stale --release or source/target pair
path An invalid classpath or sourcepath element
output-file-clash Two outputs collide. On Windows/macOS the filesystem is case-insensitive, so this is a real local-versus-CI trap

The categories left off, and why

A. Error Prone already owns it - 11 categories

Enabling these in javac would report the same problem twice, and at a lower severity. Every Error Prone check below runs at ERROR.

javac category Owned by Match
empty EmptyIf exact
dep-ann DepAnn exact
fallthrough FallThrough exact
finally Finally exact
lossy-conversions NarrowingCompoundAssignment exact
overrides Overrides exact - both are about varargs disagreeing on an override
static StaticQualifiedUsingExpression exact
auxiliaryclass MultipleTopLevelClasses, ClassName exact in effect: an auxiliary class cannot exist once no file holds a second top-level class
overloads AmbiguousMethodReference, FunctionalInterfaceClash partial, and the Error Prone pair is stricter
varargs ExplicitArrayForVarargs, PrimitiveArrayPassedToVarargsMethod, plus 4 varargs checks that are ERROR by default partial, wider coverage than the lint
try TryWithResourcesVariable, MustBeClosedChecker partial

There is also a severity argument. javac has no per-category severity: a lint category can only warn unless -Werror promotes every warning at once. An Error Prone check fails the build on its own.

B. Third-party noise - 3 categories

Category Measured Why it stays off
classfile 37 warnings All from microprofile-config-api-3.1.jar (35) and microprofile-health-api-4.0.1.jar (2). They reference OSGi annotations - org.osgi.annotation.bundle.Requirement, Requirements, versioning.Version - that are not on the compile classpath. Not our code, not fixable here.
serial 6 warnings All six CRD classes: Grant, Role, Schema, Database, DefaultPrivilege, ClusterConnection. They inherit Serializable from the fabric8 CustomResource, but they travel as JSON and are never Java-serialized. A serialVersionUID on each would be pure ceremony
processing 2 warnings "No processor claimed any of these annotations", an artefact of the Lombok and Quarkus processor setup. Not actionable

C. Not applicable - 8 categories

module, exports, opens, requires-automatic, requires-transitive-automatic and missing-explicit-ctor all need a named module.
The project has no module-info.java. incubating needs an incubator module, and preview needs a preview language feature.
Neither is used, and preview is on by default anyway.

D. Deliberate aliases and near-misses

  • synchronization is not listed.
    It is a deprecated alias of identity since JDK 25, and the toolchain's own --help-lint says so. identity is listed instead.
  • strictfp is not listed.
    It flags an unnecessary strictfp modifier, but all floating-point has been strict since Java 17, so the modifier has been meaningless for four releases.
    For it to fire, somebody would have to type a keyword that does nothing, in a codebase with zero float and double declarations.
    It is harmless to add and guards a mistake nobody here can make.

The 4 warnings that were fixed

removal - 1

GrantReconcilerTest: SQLDataType.BIGINT.identity(true)generatedByDefaultAsIdentity().
The jOOQ method is deprecated and marked for removal.
Worth noting for a reviewer: removal is on by default, so this warning was already visible before this PR. Nobody had looked.

deprecation - 3

HelmTest: Serialization.yamlMapper() twice and Serialization.jsonMapper() once, replaced by a KubernetesSerialization instance held in a constant, with unmarshal(...).
Reading also moves from File to Files.readString and Files.newInputStream.

unchecked - 1

ClusterConnectionReconcilerErrorTest: the mock creation carried //noinspection unchecked, an IntelliJ-only comment that javac ignores.
It is now a real @SuppressWarnings("unchecked") on a local variable declaration, with the value assigned to the field afterwards, because the annotation cannot sit on an assignment expression.

Review notes

  • removal is redundant today, the same way two Error Prone entries are. javac enables it by default. It is listed so the intent is explicit and survives a JDK that changes the default.
  • -Werror is now viable, and is not in this PR. The build is at zero warnings, so the ratchet would hold today. It is a separate decision, because javac promotes every warning, including a deprecation that arrives with the next jOOQ or fabric8 bump, and including any Error Prone check left at WARNING.
  • Nothing here overlaps with the Error Prone config. The 11 categories in section A are the proof: each is deliberately absent from the -Xlint list because a check in errorprone.args already fails the build for it.

Test scope

  • ./gradlew --rerun-tasks :operator:compileJava :operator:compileTestJava :generated:compileJava - BUILD SUCCESSFUL, 0 warnings, 0 notes.
  • Every category was measured with -Xlint:all on the JDK 25 Amazon Corretto toolchain across all three source sets, with the warning cap raised so nothing was truncated. The category list came from that toolchain's own javac --help-lint, not from documentation.
  • No production source changed. All three fixes are in test sources.

@ThoSap
ThoSap requested a review from stplasim September 6, 2026 18:27
@ThoSap ThoSap self-assigned this Sep 6, 2026
@ThoSap ThoSap added the enhancement New feature or request label Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant