Skip to content

Emit structured BuilderProblems from maven-compiler-plugin for build report integration #12644

Description

@gnodet

Context

PR #12572 (Build Report Foundation) introduced a structured problem reporting system using BuilderProblem with key, suggestion, documentationUrl, and severity. Currently, plugin warnings are captured via SLF4J WARN-level log interception, which loses structured metadata.

Plugins should emit structured BuilderProblem objects directly to the build report system, starting with maven-compiler-plugin as the highest-impact target.

Problem

Today, compiler warnings flow through:

javac DiagnosticCollector → compiler plugin Log.warn(text) → SLF4J → BuildReportCollector

This means:

  • Compiler warnings appear as flat text with auto-generated keys
  • No structured source location from the compiler diagnostic
  • No per-warning deduplication control

API Design — Resolved

The plugin API question was resolved with a new injectable service in Maven 4.1.0:

@Inject DiagnosticReporter diagnosticReporter;
diagnosticReporter.report(BuilderProblem.builder()
    .key("compiler:compiler.warn.unchecked:src/main/java/Foo.java:42")
    .severity(BuilderProblem.Severity.WARNING)
    .message("unchecked cast")
    .source("src/main/java/Foo.java")
    .lineNumber(42)
    .columnNumber(15)
    .build());

DiagnosticReporter is a simple injectable service that pipes BuilderProblem objects directly into the DefaultDiagnosticCollector.

Implementation Status

✅ Done — maven-compiler-plugin (PR apache/maven-compiler-plugin#1101)

The compiler plugin now maps each javax.tools.Diagnostic to a Maven BuilderProblem and reports it via DiagnosticReporter:

  • Per-location dedup keys: compiler:<code>:<source>:<line> — each unique file+line gets its own entry in the build report. 50 unchecked warnings across 50 files produce 50 separate entries (not collapsed into one).
  • Source location: source, lineNumber, columnNumber from the compiler diagnostic
  • Severity mapping: Diagnostic.Kind.ERRORERROR, WARNING/MANDATORY_WARNINGWARNING, others → INFO
  • Suppression: Users can suppress via -Dmaven.diagnostic.suppress=compiler:* (all) or compiler:compiler.warn.unchecked (specific prefix)
  • No behavior change: Existing logging behavior is unchanged — DiagnosticReporter is additive

CI note: PR #1101 expects Maven 4.1.0-SNAPSHOT (for DiagnosticReporter API); CI will pass once #12572 is merged and a snapshot is published.

🔲 Future — Other high-impact plugins

After the compiler plugin, the same DiagnosticReporter pattern can extend to:

  • maven-surefire-plugin — test failures as structured problems with test class/method
  • maven-enforcer-plugin — rule violations with rule name as key
  • maven-dependency-plugin — unused/undeclared dependency warnings
  • maven-javadoc-plugin — javadoc warnings with source location

🔲 Future — Maven 3 plugin bridge

For backward compatibility, Maven 3 plugins that use getLog().warn() already have their warnings captured by the SLF4J hook (implemented in #12572). A bridge could be provided to let Maven 3 plugins opt in to structured reporting without requiring a full Maven 4 API migration.

Expected Outcome

$ mvnlog --diagnostics
Problems (3): 3 warnings

  [WARN]  unchecked cast
          key: compiler:compiler.warn.unchecked:src/main/java/com/example/Service.java:42
          source: src/main/java/com/example/Service.java:42:15

  [WARN]  [deprecation] OldApi.method() has been deprecated
          key: compiler:compiler.warn.has.been.deprecated:src/main/java/com/example/Client.java:87
          source: src/main/java/com/example/Client.java:87:8

Depends on

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions