You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/07/31 12:58:57 UTC

(maven) branch fix/12643-structured-problems created (now 32ffc788a5)

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a change to branch fix/12643-structured-problems
in repository https://gitbox.apache.org/repos/asf/maven.git


      at 32ffc788a5 Fix #12643: Pipe structured BuilderProblems directly into DiagnosticCollector

This branch includes the following new commits:

     new 32ffc788a5 Fix #12643: Pipe structured BuilderProblems directly into DiagnosticCollector

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(maven) 01/01: Fix #12643: Pipe structured BuilderProblems directly into DiagnosticCollector

Posted by gn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch fix/12643-structured-problems
in repository https://gitbox.apache.org/repos/asf/maven.git

commit 32ffc788a54be193210587e0ae42c25a4f167eb9
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Fri Jul 31 14:58:46 2026 +0200

    Fix #12643: Pipe structured BuilderProblems directly into DiagnosticCollector
    
    Route structured validation problems from 4 pathways (settings, toolchains,
    model validation, graph building) into DefaultDiagnosticCollector so they
    appear in the build report with full key/suggestion/documentationUrl metadata
    instead of being re-logged as plain text.
    
    Pathways:
    - LookupInvoker: settings validation problems
    - MavenInvoker: toolchains validation problems
    - DefaultProjectsSelector: model validation problems (ModelProblem → BuilderProblem)
    - DefaultMaven: graph building problems (ModelProblem → BuilderProblem)
    
    Also adds EXCLUDED_LOGGERS in BuildReportCollector to prevent double-counting
    when the same problems are both piped structurally and logged via SLF4J.
    
    Migrates all test files from DefaultBuilderProblem constructor to
    BuilderProblem.builder() API.
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---
 .../apache/maven/cling/invoker/LookupInvoker.java  | 22 +++++++++++
 .../maven/cling/invoker/mvn/MavenInvoker.java      | 12 ++++++
 .../main/java/org/apache/maven/DefaultMaven.java   | 34 ++++++++++++++++-
 .../maven/internal/build/BuildReportCollector.java | 20 ++++++++--
 .../project/collector/DefaultProjectsSelector.java | 36 +++++++++++++++++-
 .../maven/graph/DefaultGraphBuilderTest.java       |  3 +-
 .../internal/build/BuildReportCollectorTest.java   |  9 +++--
 .../internal/build/BuildReportIntegrationTest.java | 33 +++++++++++++----
 .../internal/build/BuildReportJsonWriterTest.java  | 39 +++++++++-----------
 .../build/DefaultDiagnosticCollectorTest.java      | 43 ++++++++++++++--------
 10 files changed, 197 insertions(+), 54 deletions(-)

diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java
index 42f8758c14..f5605f13c7 100644
--- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java
+++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java
@@ -76,6 +76,7 @@
 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.impl.SettingsUtilsV4;
+import org.apache.maven.internal.build.DefaultDiagnosticCollector;
 import org.apache.maven.jline.FastTerminal;
 import org.apache.maven.jline.MessageUtils;
 import org.apache.maven.logging.BuildEventListener;
@@ -747,6 +748,13 @@ protected Runnable settings(C context, boolean emitSettingsWarnings, SettingsBui
                 }
             }
             context.logger.info("");
+
+            // Pipe structured problems directly to DiagnosticCollector so that
+            // key, suggestion, documentationUrl, and source location are preserved
+            // in the build report (instead of being lost to plain-text logging).
+            // This runs before SessionStarted, so the SLF4J auto-collection hook
+            // is not active yet — no double-counting risk.
+            pipeSettingsProblems(context, settingsResult);
         }
         return () -> {
             context.installationSettingsPath = null;
@@ -758,6 +766,20 @@ protected Runnable settings(C context, boolean emitSettingsWarnings, SettingsBui
         };
     }
 
+    /**
+     * Pipes structured settings validation problems to the DiagnosticCollector.
+     * This preserves key, suggestion, documentationUrl, and source location
+     * that would otherwise be lost when problems are logged as plain text.
+     */
+    private void pipeSettingsProblems(C context, SettingsBuilderResult settingsResult) {
+        context.lookup.lookupOptional(DefaultDiagnosticCollector.class).ifPresent(collector -> {
+            for (BuilderProblem problem :
+                    settingsResult.getProblems().problems().toList()) {
+                collector.report(problem);
+            }
+        });
+    }
+
     protected void customizeSettingsRequest(C context, SettingsBuilderRequest settingsBuilderRequest)
             throws Exception {}
 
diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java
index 3924977e56..7a3cadce86 100644
--- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java
+++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/MavenInvoker.java
@@ -69,6 +69,7 @@
 import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.execution.ProfileActivation;
 import org.apache.maven.execution.ProjectActivation;
+import org.apache.maven.internal.build.DefaultDiagnosticCollector;
 import org.apache.maven.jline.MessageUtils;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.logging.BuildEventListener;
@@ -220,6 +221,17 @@ protected void toolchains(MavenContext context, MavenExecutionRequest request) t
             }
 
             context.logger.info("");
+
+            // Pipe structured problems directly to DiagnosticCollector so that
+            // key, suggestion, documentationUrl, and source location are preserved
+            // in the build report. This runs before SessionStarted, so the SLF4J
+            // auto-collection hook is not active yet — no double-counting risk.
+            context.lookup.lookupOptional(DefaultDiagnosticCollector.class).ifPresent(collector -> {
+                for (BuilderProblem problem :
+                        toolchainsResult.getProblems().problems().toList()) {
+                    collector.report(problem);
+                }
+            });
         }
     }
 
diff --git a/impl/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/impl/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index 23e85a14b0..91769faf50 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -43,6 +43,7 @@
 import org.apache.maven.api.model.Model;
 import org.apache.maven.api.model.Prerequisites;
 import org.apache.maven.api.model.Profile;
+import org.apache.maven.api.services.BuilderProblem;
 import org.apache.maven.api.services.Lookup;
 import org.apache.maven.api.services.LookupException;
 import org.apache.maven.artifact.ArtifactUtils;
@@ -59,6 +60,7 @@
 import org.apache.maven.execution.ProjectDependencyGraph;
 import org.apache.maven.graph.GraphBuilder;
 import org.apache.maven.graph.ProjectSelector;
+import org.apache.maven.internal.build.DefaultDiagnosticCollector;
 import org.apache.maven.internal.impl.DefaultSessionFactory;
 import org.apache.maven.internal.impl.InternalMavenSession;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
@@ -113,6 +115,8 @@ public class DefaultMaven implements Maven {
 
     private final ProjectSelector projectSelector;
 
+    private final DefaultDiagnosticCollector diagnosticCollector;
+
     @Inject
     @SuppressWarnings("checkstyle:ParameterNumber")
     public DefaultMaven(
@@ -126,7 +130,8 @@ public DefaultMaven(
             BuildResumptionDataRepository buildResumptionDataRepository,
             SuperPomProvider superPomProvider,
             DefaultSessionFactory defaultSessionFactory,
-            @Nullable @Named("ide") WorkspaceReader ideWorkspaceReader) {
+            @Nullable @Named("ide") WorkspaceReader ideWorkspaceReader,
+            DefaultDiagnosticCollector diagnosticCollector) {
         this.lookup = lookup;
         this.eventCatapult = eventCatapult;
         this.legacySupport = legacySupport;
@@ -138,6 +143,7 @@ public DefaultMaven(
         this.superPomProvider = superPomProvider;
         this.ideWorkspaceReader = ideWorkspaceReader;
         this.defaultSessionFactory = defaultSessionFactory;
+        this.diagnosticCollector = diagnosticCollector;
         this.projectSelector = new ProjectSelector(); // if necessary switch to DI
     }
 
@@ -648,6 +654,10 @@ private Result<? extends ProjectDependencyGraph> buildGraph(MavenSession session
             } else {
                 logger.error(problem.getMessage());
             }
+            // Pipe structured problem directly to DiagnosticCollector so that
+            // source location and severity are preserved in the build report.
+            // The SLF4J hook excludes this logger to avoid double-counting.
+            diagnosticCollector.report(toBuilderProblem(problem));
         }
 
         if (!graphResult.hasErrors()) {
@@ -660,6 +670,28 @@ private Result<? extends ProjectDependencyGraph> buildGraph(MavenSession session
         return graphResult;
     }
 
+    /**
+     * Converts a compat {@link ModelProblem} to the Maven 4 {@link BuilderProblem} API,
+     * preserving source, line, column, severity, and message.
+     */
+    private static BuilderProblem toBuilderProblem(ModelProblem problem) {
+        BuilderProblem.Severity severity =
+                switch (problem.getSeverity()) {
+                    case FATAL -> BuilderProblem.Severity.FATAL;
+                    case ERROR -> BuilderProblem.Severity.ERROR;
+                    default -> BuilderProblem.Severity.WARNING;
+                };
+        return BuilderProblem.builder()
+                .source(problem.getSource())
+                .lineNumber(problem.getLineNumber())
+                .columnNumber(problem.getColumnNumber())
+                .exception(problem.getException())
+                .message(problem.getMessage())
+                .severity(severity)
+                .key("model:" + problem.getMessage().hashCode())
+                .build();
+    }
+
     @Deprecated
     // 5 January 2014
     protected Logger getLogger() {
diff --git a/impl/maven-core/src/main/java/org/apache/maven/internal/build/BuildReportCollector.java b/impl/maven-core/src/main/java/org/apache/maven/internal/build/BuildReportCollector.java
index 8df72cc4ea..9425cc15ee 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/internal/build/BuildReportCollector.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/internal/build/BuildReportCollector.java
@@ -92,6 +92,18 @@ public final class BuildReportCollector extends AbstractEventSpy {
 
     private static final int MAX_STACKTRACE_LINES = 30;
 
+    /**
+     * Logger names excluded from SLF4J auto-collection because these classes
+     * already pipe structured {@link org.apache.maven.api.services.BuilderProblem}
+     * objects directly to the {@link DefaultDiagnosticCollector}. Without this
+     * exclusion, each problem would be counted twice: once from the direct pipe
+     * and once from the SLF4J WARN interception.
+     */
+    private static final Set<String> EXCLUDED_LOGGERS = Set.of(
+            BuildReportCollector.class.getName(),
+            "org.apache.maven.DefaultMaven",
+            "org.apache.maven.project.collector.DefaultProjectsSelector");
+
     private final DefaultDiagnosticCollector diagnosticCollector;
 
     @Inject
@@ -353,10 +365,10 @@ private void captureLogEvent(int level, String loggerName, String message, Throw
 
         // Auto-collect WARN-level log events as build problems, giving Maven 3 plugins
         // automatic deduplication and summary at end of build without code changes.
-        // Skip our own logger to avoid feedback loops from problem summary printing.
-        if (level == LocationAwareLogger.WARN_INT
-                && message != null
-                && !loggerName.equals(BuildReportCollector.class.getName())) {
+        // Skip loggers that already pipe structured BuilderProblems directly to the
+        // DiagnosticCollector (avoiding double-counting), and our own logger to avoid
+        // feedback loops from problem summary printing.
+        if (level == LocationAwareLogger.WARN_INT && message != null && !EXCLUDED_LOGGERS.contains(loggerName)) {
             String syntheticKey = syntheticDiagnosticKey(loggerName, message);
             diagnosticCollector.report(BuilderProblem.builder()
                     .source(loggerName)
diff --git a/impl/maven-core/src/main/java/org/apache/maven/project/collector/DefaultProjectsSelector.java b/impl/maven-core/src/main/java/org/apache/maven/project/collector/DefaultProjectsSelector.java
index 0be344384a..bd5664d1eb 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/project/collector/DefaultProjectsSelector.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/project/collector/DefaultProjectsSelector.java
@@ -26,7 +26,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.maven.api.services.BuilderProblem;
 import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.internal.build.DefaultDiagnosticCollector;
 import org.apache.maven.model.building.ModelProblem;
 import org.apache.maven.model.building.ModelProblemUtils;
 import org.apache.maven.project.MavenProject;
@@ -45,10 +47,12 @@
 public class DefaultProjectsSelector implements ProjectsSelector {
     private static final Logger LOGGER = LoggerFactory.getLogger(DefaultProjectsSelector.class);
     private final ProjectBuilder projectBuilder;
+    private final DefaultDiagnosticCollector diagnosticCollector;
 
     @Inject
-    public DefaultProjectsSelector(ProjectBuilder projectBuilder) {
+    public DefaultProjectsSelector(ProjectBuilder projectBuilder, DefaultDiagnosticCollector diagnosticCollector) {
         this.projectBuilder = projectBuilder;
+        this.diagnosticCollector = diagnosticCollector;
     }
 
     @Override
@@ -83,6 +87,14 @@ public List<MavenProject> selectProjects(List<File> files, MavenExecutionRequest
                         LOGGER.warn("{}{}", problem.getMessage(), ((loc != null && !loc.isEmpty()) ? " @ " + loc : ""));
                     }
                 }
+
+                // Pipe structured problems directly to DiagnosticCollector so that
+                // source location and severity are preserved in the build report
+                // (instead of being lost to plain-text logging). The SLF4J hook
+                // excludes this logger to avoid double-counting.
+                for (ModelProblem problem : result.getProblems()) {
+                    diagnosticCollector.report(toBuilderProblem(problem));
+                }
             }
         }
 
@@ -100,4 +112,26 @@ public List<MavenProject> selectProjects(List<File> files, MavenExecutionRequest
 
         return projects;
     }
+
+    /**
+     * Converts a compat {@link ModelProblem} to the Maven 4 {@link BuilderProblem} API,
+     * preserving source, line, column, severity, and message.
+     */
+    private static BuilderProblem toBuilderProblem(ModelProblem problem) {
+        BuilderProblem.Severity severity =
+                switch (problem.getSeverity()) {
+                    case FATAL -> BuilderProblem.Severity.FATAL;
+                    case ERROR -> BuilderProblem.Severity.ERROR;
+                    default -> BuilderProblem.Severity.WARNING;
+                };
+        return BuilderProblem.builder()
+                .source(problem.getSource())
+                .lineNumber(problem.getLineNumber())
+                .columnNumber(problem.getColumnNumber())
+                .exception(problem.getException())
+                .message(problem.getMessage())
+                .severity(severity)
+                .key("model:" + problem.getMessage().hashCode())
+                .build();
+    }
 }
diff --git a/impl/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java b/impl/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
index 72dad0b244..6982db4b97 100644
--- a/impl/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
+++ b/impl/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
@@ -101,7 +101,8 @@ class DefaultGraphBuilderTest {
     private final MavenSession session = mock(MavenSession.class);
     private final MavenExecutionRequest mavenExecutionRequest = mock(MavenExecutionRequest.class);
 
-    private final ProjectsSelector projectsSelector = new DefaultProjectsSelector(projectBuilder);
+    private final ProjectsSelector projectsSelector = new DefaultProjectsSelector(
+            projectBuilder, new org.apache.maven.internal.build.DefaultDiagnosticCollector());
 
     // Not using mocks for these strategies - a mock would just copy the actual implementation.
 
diff --git a/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportCollectorTest.java b/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportCollectorTest.java
index 5733daf74d..2358d5d3a9 100644
--- a/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportCollectorTest.java
+++ b/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportCollectorTest.java
@@ -35,7 +35,6 @@
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.execution.MavenSession;
-import org.apache.maven.impl.DefaultBuilderProblem;
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
@@ -334,8 +333,12 @@ void testDiagnosticSuppressionWildcard() {
     // ---- Test helpers ----
 
     private static BuilderProblem warning(String key, String message, String source) {
-        return new DefaultBuilderProblem(
-                source, -1, -1, null, message, BuilderProblem.Severity.WARNING, key, null, null);
+        return BuilderProblem.builder()
+                .source(source)
+                .message(message)
+                .severity(BuilderProblem.Severity.WARNING)
+                .key(key)
+                .build();
     }
 
     private MavenProject createProject(String groupId, String artifactId, String version) {
diff --git a/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportIntegrationTest.java b/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportIntegrationTest.java
index e200cd06b6..10f2dc1ae7 100644
--- a/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportIntegrationTest.java
+++ b/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportIntegrationTest.java
@@ -35,7 +35,6 @@
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.execution.MavenSession;
-import org.apache.maven.impl.DefaultBuilderProblem;
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
@@ -72,21 +71,41 @@ void setUp() {
     }
 
     private static BuilderProblem warning(String key, String message, String source) {
-        return new DefaultBuilderProblem(
-                source, -1, -1, null, message, BuilderProblem.Severity.WARNING, key, null, null);
+        return BuilderProblem.builder()
+                .source(source)
+                .message(message)
+                .severity(BuilderProblem.Severity.WARNING)
+                .key(key)
+                .build();
     }
 
     private static BuilderProblem warning(String key, String message, String source, String suggestion, String docUrl) {
-        return new DefaultBuilderProblem(
-                source, -1, -1, null, message, BuilderProblem.Severity.WARNING, key, suggestion, docUrl);
+        return BuilderProblem.builder()
+                .source(source)
+                .message(message)
+                .severity(BuilderProblem.Severity.WARNING)
+                .key(key)
+                .suggestion(suggestion)
+                .documentationUrl(docUrl)
+                .build();
     }
 
     private static BuilderProblem info(String key, String message, String source) {
-        return new DefaultBuilderProblem(source, -1, -1, null, message, BuilderProblem.Severity.INFO, key, null, null);
+        return BuilderProblem.builder()
+                .source(source)
+                .message(message)
+                .severity(BuilderProblem.Severity.INFO)
+                .key(key)
+                .build();
     }
 
     private static BuilderProblem error(String key, String message, String source) {
-        return new DefaultBuilderProblem(source, -1, -1, null, message, BuilderProblem.Severity.ERROR, key, null, null);
+        return BuilderProblem.builder()
+                .source(source)
+                .message(message)
+                .severity(BuilderProblem.Severity.ERROR)
+                .key(key)
+                .build();
     }
 
     /**
diff --git a/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportJsonWriterTest.java b/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportJsonWriterTest.java
index 073072c4a5..831bb8a061 100644
--- a/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportJsonWriterTest.java
+++ b/impl/maven-core/src/test/java/org/apache/maven/internal/build/BuildReportJsonWriterTest.java
@@ -30,7 +30,6 @@
 import org.apache.maven.api.build.report.ModuleReport;
 import org.apache.maven.api.build.report.MojoReport;
 import org.apache.maven.api.services.BuilderProblem;
-import org.apache.maven.impl.DefaultBuilderProblem;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -334,27 +333,23 @@ void testNullMojoFields() {
 
     @Test
     void testProblemsSerialization() {
-        BuilderProblem p1 = new DefaultBuilderProblem(
-                "maven-compiler-plugin:3.15.0:compile",
-                42,
-                1,
-                null,
-                "source/target value 8 is deprecated",
-                BuilderProblem.Severity.WARNING,
-                "deprecated-source-target",
-                "Update <maven.compiler.source> to 11 or higher",
-                "https://example.com/docs/compiler");
-
-        BuilderProblem p2 = new DefaultBuilderProblem(
-                "maven-compiler-plugin",
-                -1,
-                -1,
-                null,
-                "3 errors found",
-                BuilderProblem.Severity.ERROR,
-                "compilation-failure",
-                null,
-                null);
+        BuilderProblem p1 = BuilderProblem.builder()
+                .source("maven-compiler-plugin:3.15.0:compile")
+                .lineNumber(42)
+                .columnNumber(1)
+                .message("source/target value 8 is deprecated")
+                .severity(BuilderProblem.Severity.WARNING)
+                .key("deprecated-source-target")
+                .suggestion("Update <maven.compiler.source> to 11 or higher")
+                .documentationUrl("https://example.com/docs/compiler")
+                .build();
+
+        BuilderProblem p2 = BuilderProblem.builder()
+                .source("maven-compiler-plugin")
+                .message("3 errors found")
+                .severity(BuilderProblem.Severity.ERROR)
+                .key("compilation-failure")
+                .build();
 
         BuildReport report = new DefaultBuildReport(
                 BuildStatus.FAILURE,
diff --git a/impl/maven-core/src/test/java/org/apache/maven/internal/build/DefaultDiagnosticCollectorTest.java b/impl/maven-core/src/test/java/org/apache/maven/internal/build/DefaultDiagnosticCollectorTest.java
index 3276c3c533..90dfeefe14 100644
--- a/impl/maven-core/src/test/java/org/apache/maven/internal/build/DefaultDiagnosticCollectorTest.java
+++ b/impl/maven-core/src/test/java/org/apache/maven/internal/build/DefaultDiagnosticCollectorTest.java
@@ -27,7 +27,6 @@
 import java.util.concurrent.Future;
 
 import org.apache.maven.api.services.BuilderProblem;
-import org.apache.maven.impl.DefaultBuilderProblem;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
@@ -45,16 +44,30 @@ void setUp() {
     }
 
     private static BuilderProblem warning(String key, String message, String source) {
-        return new DefaultBuilderProblem(
-                source, -1, -1, null, message, BuilderProblem.Severity.WARNING, key, null, null);
+        return BuilderProblem.builder()
+                .source(source)
+                .message(message)
+                .severity(BuilderProblem.Severity.WARNING)
+                .key(key)
+                .build();
     }
 
     private static BuilderProblem error(String key, String message, String source) {
-        return new DefaultBuilderProblem(source, -1, -1, null, message, BuilderProblem.Severity.ERROR, key, null, null);
+        return BuilderProblem.builder()
+                .source(source)
+                .message(message)
+                .severity(BuilderProblem.Severity.ERROR)
+                .key(key)
+                .build();
     }
 
     private static BuilderProblem info(String key, String message, String source) {
-        return new DefaultBuilderProblem(source, -1, -1, null, message, BuilderProblem.Severity.INFO, key, null, null);
+        return BuilderProblem.builder()
+                .source(source)
+                .message(message)
+                .severity(BuilderProblem.Severity.INFO)
+                .key(key)
+                .build();
     }
 
     @Test
@@ -175,16 +188,16 @@ void testSummaryListIsUnmodifiable() {
 
     @Test
     void testFullProblemFields() {
-        BuilderProblem p = new DefaultBuilderProblem(
-                "maven-compiler-plugin:3.15.0:compile",
-                42,
-                15,
-                null,
-                "unchecked cast from Object to List<String>",
-                BuilderProblem.Severity.WARNING,
-                "unchecked-cast",
-                "Add @SuppressWarnings(\"unchecked\") or use a type-safe alternative",
-                "https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html");
+        BuilderProblem p = BuilderProblem.builder()
+                .source("maven-compiler-plugin:3.15.0:compile")
+                .lineNumber(42)
+                .columnNumber(15)
+                .message("unchecked cast from Object to List<String>")
+                .severity(BuilderProblem.Severity.WARNING)
+                .key("unchecked-cast")
+                .suggestion("Add @SuppressWarnings(\"unchecked\") or use a type-safe alternative")
+                .documentationUrl("https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html")
+                .build();
 
         collector.report(p);