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

gnodet pushed a commit to branch nullaway-annotations
in repository https://gitbox.apache.org/repos/asf/maven.git

commit ffcc698dd111e4d02bc92544ad308a22cff6fcd5
Author: Guillaume Nodet <[email protected]>
AuthorDate: Fri Mar 20 11:29:38 2026 +0100

    Add @Nullable annotations to Maven 4 API and set up NullAway for 
compile-time null checks
    
    - Add opt-in NullAway profile (-Pnullaway) using Error Prone 2.36.0 + 
NullAway 0.12.6
      for compile-time null safety checking on org.apache.maven.api packages
    - Add @Nullable annotations to fields, method parameters, and return types 
across
      the Maven 4 API where values can genuinely be null
    - Add @Nullable to Velocity model template (model.vm) for generated model 
classes:
      non-primitive, non-collection fields and their getters
    - Add @Nullable to hand-written template files: InputLocation, InputSource,
      InputLocationTracker, ImmutableCollections
    - Add @Nullable to XmlNode builder, XmlService merge methods, 
XmlReaderRequest,
      XmlWriterRequest
    - Add @Nullable to builder fields in request classes (fields start null 
before
      builder methods are called)
    - Add requireNonNull() validation in builder build() methods for parameters
      that must be non-null, preserving existing @Nonnull API contracts
    - Fix InputLocation.locations field: not nullable (always initialized via
      ImmutableCollections which returns empty map for null input)
    - Fix Sources.BuildPathSource.resolve() null safety for Path.getParent()
    - Add @Nullable to Nullable annotation itself (meta-annotation for NullAway)
    - Fix Phase.getEffectiveId() return annotation in lifecycle.mdo
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../org/apache/maven/api/annotations/Nullable.java |   3 +
 .../org/apache/maven/api/cli/ParserRequest.java    |  44 +++++++--
 .../maven/api/cli/logging/AccumulatingLogger.java  |   5 +-
 .../java/org/apache/maven/api/DependencyScope.java |   2 +
 .../java/org/apache/maven/api/JavaPathType.java    |   7 +-
 .../java/org/apache/maven/api/ProtoSession.java    |  38 +++++---
 .../main/java/org/apache/maven/api/Session.java    |  39 ++++++--
 .../org/apache/maven/api/feature/Features.java     |   4 +-
 .../org/apache/maven/api/plugin/MojoException.java |   7 +-
 .../ArtifactCoordinatesFactoryRequest.java         | 103 ++++++++++++++++-----
 .../api/services/ArtifactDeployerRequest.java      |  14 ++-
 .../maven/api/services/ArtifactFactoryRequest.java |  59 ++++++++++--
 .../api/services/ArtifactInstallerRequest.java     |   7 +-
 .../api/services/ArtifactResolverRequest.java      |  15 ++-
 .../maven/api/services/ArtifactResolverResult.java |   1 +
 .../org/apache/maven/api/services/BaseRequest.java |   6 +-
 .../DependencyCoordinatesFactoryRequest.java       |  91 +++++++++++++-----
 .../api/services/DependencyResolverRequest.java    |  39 +++++++-
 .../maven/api/services/MavenBuilderException.java  |   2 +-
 .../apache/maven/api/services/MavenException.java  |   7 +-
 .../maven/api/services/ModelBuilderRequest.java    |  64 ++++++++++---
 .../maven/api/services/ModelProblemCollector.java  |   5 +-
 .../maven/api/services/PathMatcherFactory.java     |   5 +-
 .../maven/api/services/ProjectBuilderRequest.java  |  26 +++++-
 .../maven/api/services/RepositoryAwareRequest.java |   3 +-
 .../apache/maven/api/services/SettingsBuilder.java |   4 +-
 .../maven/api/services/SettingsBuilderRequest.java |  28 +++++-
 .../org/apache/maven/api/services/Sources.java     |  14 ++-
 .../maven/api/services/ToolchainManager.java       |   3 +-
 .../api/services/ToolchainsBuilderRequest.java     |  20 +++-
 .../api/services/VersionRangeResolverRequest.java  |  22 ++++-
 .../maven/api/services/VersionResolverRequest.java |  19 +++-
 .../maven/api/services/xml/XmlReaderRequest.java   |  58 ++++++++++--
 .../maven/api/services/xml/XmlWriterRequest.java   |  41 ++++++--
 .../maven/api/model/ModelObjectProcessor.java      |   7 +-
 api/maven-api-model/src/main/mdo/maven.mdo         |  16 ++--
 api/maven-api-plugin/src/main/mdo/lifecycle.mdo    |   1 +
 .../apache/maven/api/spi/ModelParserException.java |   9 +-
 .../maven/api/spi/ModelTransformerException.java   |   7 +-
 .../apache/maven/api/xml/ImmutableCollections.java |   6 +-
 .../java/org/apache/maven/api/xml/XmlNode.java     |  50 +++++++---
 .../java/org/apache/maven/api/xml/XmlService.java  |  13 ++-
 pom.xml                                            |  47 ++++++++++
 src/mdo/java/ImmutableCollections.java             |   6 +-
 src/mdo/java/InputLocation.java                    |  33 ++++---
 src/mdo/java/InputLocationTracker.java             |   4 +
 src/mdo/java/InputSource.java                      |  32 +++++--
 src/mdo/model.vm                                   |  29 ++++--
 48 files changed, 847 insertions(+), 218 deletions(-)

diff --git 
a/api/maven-api-annotations/src/main/java/org/apache/maven/api/annotations/Nullable.java
 
b/api/maven-api-annotations/src/main/java/org/apache/maven/api/annotations/Nullable.java
index df2517cad9..84cf081033 100644
--- 
a/api/maven-api-annotations/src/main/java/org/apache/maven/api/annotations/Nullable.java
+++ 
b/api/maven-api-annotations/src/main/java/org/apache/maven/api/annotations/Nullable.java
@@ -19,8 +19,10 @@
 package org.apache.maven.api.annotations;
 
 import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
 /**
  * The annotated element can be {@code null}.
@@ -31,4 +33,5 @@
 @Experimental
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
 public @interface Nullable {}
diff --git 
a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ParserRequest.java 
b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ParserRequest.java
index ee25ec63da..9c3ec06ca7 100644
--- 
a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ParserRequest.java
+++ 
b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/ParserRequest.java
@@ -279,12 +279,25 @@ class Builder {
 
         private final Logger logger;
         private Lookup lookup = EMPTY_LOOKUP;
+
+        @Nullable
         private Path cwd;
+
+        @Nullable
         private Path mavenHome;
+
+        @Nullable
         private Path userHome;
+
+        @Nullable
         private InputStream stdIn;
+
+        @Nullable
         private OutputStream stdOut;
+
+        @Nullable
         private OutputStream stdErr;
+
         private boolean embedded = false;
 
         private Builder(
@@ -361,12 +374,25 @@ private static class ParserRequestImpl implements 
ParserRequest {
             private final MessageBuilderFactory messageBuilderFactory;
             private final List<String> args;
             private final Lookup lookup;
+
+            @Nullable
             private final Path cwd;
+
+            @Nullable
             private final Path mavenHome;
+
+            @Nullable
             private final Path userHome;
+
+            @Nullable
             private final InputStream stdIn;
+
+            @Nullable
             private final OutputStream stdOut;
+
+            @Nullable
             private final OutputStream stdErr;
+
             private final boolean embedded;
 
             private ParserRequestImpl(
@@ -376,12 +402,12 @@ private ParserRequestImpl(
                     Logger logger,
                     MessageBuilderFactory messageBuilderFactory,
                     Lookup lookup,
-                    Path cwd,
-                    Path mavenHome,
-                    Path userHome,
-                    InputStream stdIn,
-                    OutputStream stdOut,
-                    OutputStream stdErr,
+                    @Nullable Path cwd,
+                    @Nullable Path mavenHome,
+                    @Nullable Path userHome,
+                    @Nullable InputStream stdIn,
+                    @Nullable OutputStream stdOut,
+                    @Nullable OutputStream stdErr,
                     boolean embedded) {
                 this.command = requireNonNull(command, "command");
                 this.commandName = requireNonNull(commandName, "commandName");
@@ -428,31 +454,37 @@ public Lookup lookup() {
                 return lookup;
             }
 
+            @Nullable
             @Override
             public Path cwd() {
                 return cwd;
             }
 
+            @Nullable
             @Override
             public Path mavenHome() {
                 return mavenHome;
             }
 
+            @Nullable
             @Override
             public Path userHome() {
                 return userHome;
             }
 
+            @Nullable
             @Override
             public InputStream stdIn() {
                 return stdIn;
             }
 
+            @Nullable
             @Override
             public OutputStream stdOut() {
                 return stdOut;
             }
 
+            @Nullable
             @Override
             public OutputStream stdErr() {
                 return stdErr;
diff --git 
a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/logging/AccumulatingLogger.java
 
b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/logging/AccumulatingLogger.java
index 013e73a81a..2f2d425de4 100644
--- 
a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/logging/AccumulatingLogger.java
+++ 
b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/logging/AccumulatingLogger.java
@@ -22,6 +22,7 @@
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.apache.maven.api.annotations.Nullable;
 import org.apache.maven.api.cli.Logger;
 
 import static java.util.Objects.requireNonNull;
@@ -34,10 +35,10 @@ public class AccumulatingLogger implements Logger {
     private final AtomicReference<List<Entry>> entries = new 
AtomicReference<>(new CopyOnWriteArrayList<>());
 
     @Override
-    public void log(Level level, String message, Throwable error) {
+    public void log(Level level, String message, @Nullable Throwable error) {
         requireNonNull(level, "level");
         requireNonNull(message, "message");
-        entries.get().add(new Entry(level, message, error));
+        requireNonNull(entries.get()).add(new Entry(level, message, error));
     }
 
     @Override
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java 
b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java
index f9f788e003..77f6cfc816 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java
@@ -26,6 +26,7 @@
 import org.apache.maven.api.annotations.Experimental;
 import org.apache.maven.api.annotations.Immutable;
 import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
 
 /**
  * Indicates when the dependency will be used.
@@ -106,6 +107,7 @@ public enum DependencyScope {
      *
      * @param id the identifier of the scope (case-sensitive)
      */
+    @Nullable
     public static DependencyScope forId(String id) {
         return IDS.get(id);
     }
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java 
b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java
index bf5dc12a7f..aef3f91cdc 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaPathType.java
@@ -30,6 +30,7 @@
 
 import org.apache.maven.api.annotations.Experimental;
 import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
 
 /**
  * The option of a Java command-line tool where to place the paths to some 
dependencies.
@@ -170,6 +171,7 @@ public static Modular patchModule(@Nonnull String 
moduleName) {
      *
      * @see #location()
      */
+    @Nullable
     private final JavaFileManager.Location location;
 
     /**
@@ -177,6 +179,7 @@ public static Modular patchModule(@Nonnull String 
moduleName) {
      *
      * @see #option()
      */
+    @Nullable
     private final String option;
 
     /**
@@ -185,7 +188,7 @@ public static Modular patchModule(@Nonnull String 
moduleName) {
      * @param location the {@code javax.tool} enumeration value, or {@code 
null} if none.
      * @param option the Java tools option for this path, or {@code null} if 
none
      */
-    JavaPathType(JavaFileManager.Location location, String option) {
+    JavaPathType(@Nullable JavaFileManager.Location location, @Nullable String 
option) {
         this.location = location;
         this.option = option;
     }
@@ -260,7 +263,7 @@ public String[] option(Iterable<? extends Path> paths) {
     /**
      * Implementation shared with {@link Modular}.
      */
-    final String[] format(String moduleName, Iterable<? extends Path> paths) {
+    final String[] format(@Nullable String moduleName, Iterable<? extends 
Path> paths) {
         if (option == null) {
             throw new IllegalStateException("No option is associated to this 
path type.");
         }
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/ProtoSession.java 
b/api/maven-api-core/src/main/java/org/apache/maven/api/ProtoSession.java
index 41300d074e..387165523f 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/ProtoSession.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ProtoSession.java
@@ -116,20 +116,29 @@ static Builder newBuilder() {
     }
 
     class Builder {
+        @Nullable
         private Map<String, String> userProperties;
+
+        @Nullable
         private Map<String, String> systemProperties;
+
+        @Nullable
         private Instant startTime;
+
+        @Nullable
         private Path topDirectory;
+
+        @Nullable
         private Path rootDirectory;
 
         private Builder() {}
 
         private Builder(
-                Map<String, String> userProperties,
-                Map<String, String> systemProperties,
-                Instant startTime,
-                Path topDirectory,
-                Path rootDirectory) {
+                @Nullable Map<String, String> userProperties,
+                @Nullable Map<String, String> systemProperties,
+                @Nullable Instant startTime,
+                @Nullable Path topDirectory,
+                @Nullable Path rootDirectory) {
             this.userProperties = userProperties;
             this.systemProperties = systemProperties;
             this.startTime = startTime;
@@ -163,7 +172,12 @@ public Builder withRootDirectory(@Nullable Path 
rootDirectory) {
         }
 
         public ProtoSession build() {
-            return new Impl(userProperties, systemProperties, startTime, 
topDirectory, rootDirectory);
+            return new Impl(
+                    requireNonNull(userProperties, "userProperties cannot be 
null"),
+                    requireNonNull(systemProperties, "systemProperties cannot 
be null"),
+                    requireNonNull(startTime, "startTime cannot be null"),
+                    requireNonNull(topDirectory, "topDirectory cannot be 
null"),
+                    rootDirectory);
         }
 
         private static class Impl implements ProtoSession {
@@ -172,14 +186,16 @@ private static class Impl implements ProtoSession {
             private final Map<String, String> effectiveProperties;
             private final Instant startTime;
             private final Path topDirectory;
+
+            @Nullable
             private final Path rootDirectory;
 
             private Impl(
-                    Map<String, String> userProperties,
-                    Map<String, String> systemProperties,
-                    Instant startTime,
-                    Path topDirectory,
-                    Path rootDirectory) {
+                    @Nonnull Map<String, String> userProperties,
+                    @Nonnull Map<String, String> systemProperties,
+                    @Nonnull Instant startTime,
+                    @Nonnull Path topDirectory,
+                    @Nullable Path rootDirectory) {
                 this.userProperties = Map.copyOf(userProperties);
                 this.systemProperties = Map.copyOf(systemProperties);
                 Map<String, String> cp = new HashMap<>(systemProperties);
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java 
b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java
index 8ef3802062..71cd67685d 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java
@@ -263,7 +263,11 @@ default Map<String, String> getEffectiveProperties() {
      * @see ArtifactCoordinatesFactory#create(Session, String, String, String, 
String)
      */
     @Nonnull
-    ArtifactCoordinates createArtifactCoordinates(String groupId, String 
artifactId, String version, String extension);
+    ArtifactCoordinates createArtifactCoordinates(
+            @Nullable String groupId,
+            @Nullable String artifactId,
+            @Nullable String version,
+            @Nullable String extension);
 
     /**
      * Shortcut for {@code getService(ArtifactFactory.class).create(...)}.
@@ -280,7 +284,12 @@ default Map<String, String> getEffectiveProperties() {
      */
     @Nonnull
     ArtifactCoordinates createArtifactCoordinates(
-            String groupId, String artifactId, String version, String 
classifier, String extension, String type);
+            @Nullable String groupId,
+            @Nullable String artifactId,
+            @Nullable String version,
+            @Nullable String classifier,
+            @Nullable String extension,
+            @Nullable String type);
 
     /**
      * Shortcut for {@code getService(ArtifactFactory.class).create(...)}.
@@ -327,7 +336,11 @@ ArtifactCoordinates createArtifactCoordinates(
      * @see org.apache.maven.api.services.ArtifactFactory#create(Session, 
String, String, String, String)
      */
     @Nonnull
-    Artifact createArtifact(String groupId, String artifactId, String version, 
String extension);
+    Artifact createArtifact(
+            @Nullable String groupId,
+            @Nullable String artifactId,
+            @Nullable String version,
+            @Nullable String extension);
 
     /**
      * Shortcut for {@code getService(ArtifactFactory.class).create(...)}.
@@ -344,7 +357,12 @@ ArtifactCoordinates createArtifactCoordinates(
      */
     @Nonnull
     Artifact createArtifact(
-            String groupId, String artifactId, String version, String 
classifier, String extension, String type);
+            @Nullable String groupId,
+            @Nullable String artifactId,
+            @Nullable String version,
+            @Nullable String classifier,
+            @Nullable String extension,
+            @Nullable String type);
 
     /**
      * Shortcut for {@code 
getService(ArtifactFactory.class).createProduced(...)}.
@@ -358,7 +376,11 @@ Artifact createArtifact(
      * @see 
org.apache.maven.api.services.ArtifactFactory#createProduced(Session, String, 
String, String, String)
      */
     @Nonnull
-    ProducedArtifact createProducedArtifact(String groupId, String artifactId, 
String version, String extension);
+    ProducedArtifact createProducedArtifact(
+            @Nullable String groupId,
+            @Nullable String artifactId,
+            @Nullable String version,
+            @Nullable String extension);
 
     /**
      * Shortcut for {@code 
getService(ArtifactFactory.class).createProduced(...)}.
@@ -375,7 +397,12 @@ Artifact createArtifact(
      */
     @Nonnull
     ProducedArtifact createProducedArtifact(
-            String groupId, String artifactId, String version, String 
classifier, String extension, String type);
+            @Nullable String groupId,
+            @Nullable String artifactId,
+            @Nullable String version,
+            @Nullable String classifier,
+            @Nullable String extension,
+            @Nullable String type);
 
     /**
      * Shortcut for {@code getService(ArtifactResolver.class).resolve(...)}.
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/feature/Features.java 
b/api/maven-api-core/src/main/java/org/apache/maven/api/feature/Features.java
index 52feae0cd8..20ada0c9cd 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/feature/Features.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/feature/Features.java
@@ -61,11 +61,11 @@ public static boolean deployBuildPom(@Nullable Map<String, 
?> userProperties) {
         return doGet(userProperties, Constants.MAVEN_DEPLOY_BUILD_POM, true);
     }
 
-    private static boolean doGet(Map<String, ?> userProperties, String key, 
boolean def) {
+    private static boolean doGet(@Nullable Map<String, ?> userProperties, 
String key, boolean def) {
         return doGet(userProperties != null ? userProperties.get(key) : null, 
def);
     }
 
-    private static boolean doGet(Object val, boolean def) {
+    private static boolean doGet(@Nullable Object val, boolean def) {
         if (val instanceof Boolean bool) {
             return bool;
         } else if (val != null) {
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
index 2d4b976cee..e15bf7f448 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
@@ -19,6 +19,7 @@
 package org.apache.maven.api.plugin;
 
 import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nullable;
 import org.apache.maven.api.services.MavenException;
 
 /**
@@ -29,15 +30,17 @@
 @Experimental
 public class MojoException extends MavenException {
 
+    @Nullable
     protected Object source;
 
+    @Nullable
     protected String longMessage;
 
     /**
      * Constructs a new {@code MojoException} providing the source and a short 
and long message.
      * These messages are used to improve the message written at the end of 
Maven build.
      */
-    public MojoException(Object source, String shortMessage, String 
longMessage) {
+    public MojoException(@Nullable Object source, String shortMessage, 
@Nullable String longMessage) {
         super(shortMessage);
         this.source = source;
         this.longMessage = longMessage;
@@ -68,10 +71,12 @@ public MojoException(Throwable cause) {
         super(cause);
     }
 
+    @Nullable
     public String getLongMessage() {
         return longMessage;
     }
 
+    @Nullable
     public Object getSource() {
         return source;
     }
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinatesFactoryRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinatesFactoryRequest.java
index d2c3540f3c..5ff73d4139 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinatesFactoryRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinatesFactoryRequest.java
@@ -26,6 +26,7 @@
 import org.apache.maven.api.annotations.Immutable;
 import org.apache.maven.api.annotations.Nonnull;
 import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
 
 import static java.util.Objects.requireNonNull;
 
@@ -38,23 +39,34 @@
 @Immutable
 public interface ArtifactCoordinatesFactoryRequest extends Request<Session> {
 
+    @Nullable
     String getGroupId();
 
+    @Nullable
     String getArtifactId();
 
+    @Nullable
     String getVersion();
 
+    @Nullable
     String getClassifier();
 
+    @Nullable
     String getExtension();
 
+    @Nullable
     String getType();
 
+    @Nullable
     String getCoordinatesString();
 
     @Nonnull
     static ArtifactCoordinatesFactoryRequest build(
-            @Nonnull Session session, String groupId, String artifactId, 
String version, String extension) {
+            @Nonnull Session session,
+            @Nullable String groupId,
+            @Nullable String artifactId,
+            @Nullable String version,
+            @Nullable String extension) {
         return ArtifactCoordinatesFactoryRequest.builder()
                 .session(requireNonNull(session, "session"))
                 .groupId(groupId)
@@ -67,12 +79,12 @@ static ArtifactCoordinatesFactoryRequest build(
     @Nonnull
     static ArtifactCoordinatesFactoryRequest build(
             @Nonnull Session session,
-            String groupId,
-            String artifactId,
-            String version,
-            String classifier,
-            String extension,
-            String type) {
+            @Nullable String groupId,
+            @Nullable String artifactId,
+            @Nullable String version,
+            @Nullable String classifier,
+            @Nullable String extension,
+            @Nullable String type) {
         return ArtifactCoordinatesFactoryRequest.builder()
                 .session(requireNonNull(session, "session"))
                 .groupId(groupId)
@@ -110,14 +122,31 @@ static ArtifactFactoryRequestBuilder builder() {
 
     @NotThreadSafe
     class ArtifactFactoryRequestBuilder {
+        @Nullable
         private Session session;
+
+        @Nullable
         private RequestTrace trace;
+
+        @Nullable
         private String groupId;
+
+        @Nullable
         private String artifactId;
+
+        @Nullable
         private String version;
+
+        @Nullable
         private String classifier;
+
+        @Nullable
         private String extension;
+
+        @Nullable
         private String type;
+
+        @Nullable
         private String coordinateString;
 
         ArtifactFactoryRequestBuilder() {}
@@ -132,67 +161,88 @@ public ArtifactFactoryRequestBuilder trace(RequestTrace 
trace) {
             return this;
         }
 
-        public ArtifactFactoryRequestBuilder groupId(String groupId) {
+        public ArtifactFactoryRequestBuilder groupId(@Nullable String groupId) 
{
             this.groupId = groupId;
             return this;
         }
 
-        public ArtifactFactoryRequestBuilder artifactId(String artifactId) {
+        public ArtifactFactoryRequestBuilder artifactId(@Nullable String 
artifactId) {
             this.artifactId = artifactId;
             return this;
         }
 
-        public ArtifactFactoryRequestBuilder version(String version) {
+        public ArtifactFactoryRequestBuilder version(@Nullable String version) 
{
             this.version = version;
             return this;
         }
 
-        public ArtifactFactoryRequestBuilder classifier(String classifier) {
+        public ArtifactFactoryRequestBuilder classifier(@Nullable String 
classifier) {
             this.classifier = classifier;
             return this;
         }
 
-        public ArtifactFactoryRequestBuilder extension(String extension) {
+        public ArtifactFactoryRequestBuilder extension(@Nullable String 
extension) {
             this.extension = extension;
             return this;
         }
 
-        public ArtifactFactoryRequestBuilder type(String type) {
+        public ArtifactFactoryRequestBuilder type(@Nullable String type) {
             this.type = type;
             return this;
         }
 
-        public ArtifactFactoryRequestBuilder coordinateString(String 
coordinateString) {
+        public ArtifactFactoryRequestBuilder coordinateString(@Nullable String 
coordinateString) {
             this.coordinateString = coordinateString;
             return this;
         }
 
         public ArtifactCoordinatesFactoryRequest build() {
             return new DefaultArtifactFactoryRequestArtifact(
-                    session, trace, groupId, artifactId, version, classifier, 
extension, type, coordinateString);
+                    requireNonNull(session, "session cannot be null"),
+                    trace,
+                    groupId,
+                    artifactId,
+                    version,
+                    classifier,
+                    extension,
+                    type,
+                    coordinateString);
         }
 
         private static class DefaultArtifactFactoryRequestArtifact extends 
BaseRequest<Session>
                 implements ArtifactCoordinatesFactoryRequest {
+            @Nullable
             private final String groupId;
+
+            @Nullable
             private final String artifactId;
+
+            @Nullable
             private final String version;
+
+            @Nullable
             private final String classifier;
+
+            @Nullable
             private final String extension;
+
+            @Nullable
             private final String type;
+
+            @Nullable
             private final String coordinatesString;
 
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultArtifactFactoryRequestArtifact(
                     @Nonnull Session session,
-                    RequestTrace trace,
-                    String groupId,
-                    String artifactId,
-                    String version,
-                    String classifier,
-                    String extension,
-                    String type,
-                    String coordinatesString) {
+                    @Nullable RequestTrace trace,
+                    @Nullable String groupId,
+                    @Nullable String artifactId,
+                    @Nullable String version,
+                    @Nullable String classifier,
+                    @Nullable String extension,
+                    @Nullable String type,
+                    @Nullable String coordinatesString) {
                 super(session, trace);
                 this.groupId = groupId;
                 this.artifactId = artifactId;
@@ -203,36 +253,43 @@ private static class 
DefaultArtifactFactoryRequestArtifact extends BaseRequest<S
                 this.coordinatesString = coordinatesString;
             }
 
+            @Nullable
             @Override
             public String getGroupId() {
                 return groupId;
             }
 
+            @Nullable
             @Override
             public String getArtifactId() {
                 return artifactId;
             }
 
+            @Nullable
             @Override
             public String getVersion() {
                 return version;
             }
 
+            @Nullable
             @Override
             public String getClassifier() {
                 return classifier;
             }
 
+            @Nullable
             @Override
             public String getExtension() {
                 return extension;
             }
 
+            @Nullable
             @Override
             public String getType() {
                 return type;
             }
 
+            @Nullable
             @Override
             public String getCoordinatesString() {
                 return coordinatesString;
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
index 8d54d882c0..d0d3e19e89 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
@@ -67,10 +67,18 @@ static ArtifactDeployerRequest build(
     }
 
     class ArtifactDeployerRequestBuilder {
+        @Nullable
         Session session;
+
+        @Nullable
         RequestTrace trace;
+
+        @Nullable
         RemoteRepository repository;
+
+        @Nullable
         Collection<ProducedArtifact> artifacts;
+
         int retryFailedDeploymentCount;
 
         ArtifactDeployerRequestBuilder() {}
@@ -106,7 +114,11 @@ public ArtifactDeployerRequestBuilder 
retryFailedDeploymentCount(int retryFailed
         @Nonnull
         public ArtifactDeployerRequest build() {
             return new DefaultArtifactDeployerRequest(
-                    session, trace, repository, artifacts, 
retryFailedDeploymentCount);
+                    requireNonNull(session, "session cannot be null"),
+                    trace,
+                    requireNonNull(repository, "repository cannot be null"),
+                    requireNonNull(artifacts, "artifacts cannot be null"),
+                    retryFailedDeploymentCount);
         }
 
         private static class DefaultArtifactDeployerRequest extends 
BaseRequest<Session>
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
index 0d97922374..9b87ee18e0 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
@@ -38,16 +38,22 @@
 @Immutable
 public interface ArtifactFactoryRequest extends Request<Session> {
 
+    @Nullable
     String getGroupId();
 
+    @Nullable
     String getArtifactId();
 
+    @Nullable
     String getVersion();
 
+    @Nullable
     String getClassifier();
 
+    @Nullable
     String getExtension();
 
+    @Nullable
     String getType();
 
     static ArtifactFactoryRequest build(
@@ -86,13 +92,28 @@ static ArtifactFactoryRequestBuilder builder() {
 
     @NotThreadSafe
     class ArtifactFactoryRequestBuilder {
+        @Nullable
         private Session session;
+
+        @Nullable
         private RequestTrace trace;
+
+        @Nullable
         private String groupId;
+
+        @Nullable
         private String artifactId;
+
+        @Nullable
         private String version;
+
+        @Nullable
         private String classifier;
+
+        @Nullable
         private String extension;
+
+        @Nullable
         private String type;
 
         ArtifactFactoryRequestBuilder() {}
@@ -139,28 +160,46 @@ public ArtifactFactoryRequestBuilder type(String type) {
 
         public ArtifactFactoryRequest build() {
             return new DefaultArtifactFactoryRequest(
-                    session, trace, groupId, artifactId, version, classifier, 
extension, type);
+                    requireNonNull(session, "session cannot be null"),
+                    trace,
+                    groupId,
+                    artifactId,
+                    version,
+                    classifier,
+                    extension,
+                    type);
         }
 
         private static class DefaultArtifactFactoryRequest extends 
BaseRequest<Session>
                 implements ArtifactFactoryRequest {
+            @Nullable
             private final String groupId;
+
+            @Nullable
             private final String artifactId;
+
+            @Nullable
             private final String version;
+
+            @Nullable
             private final String classifier;
+
+            @Nullable
             private final String extension;
+
+            @Nullable
             private final String type;
 
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultArtifactFactoryRequest(
                     @Nonnull Session session,
                     @Nullable RequestTrace trace,
-                    String groupId,
-                    String artifactId,
-                    String version,
-                    String classifier,
-                    String extension,
-                    String type) {
+                    @Nullable String groupId,
+                    @Nullable String artifactId,
+                    @Nullable String version,
+                    @Nullable String classifier,
+                    @Nullable String extension,
+                    @Nullable String type) {
                 super(session, trace);
                 this.groupId = groupId;
                 this.artifactId = artifactId;
@@ -170,31 +209,37 @@ private static class DefaultArtifactFactoryRequest 
extends BaseRequest<Session>
                 this.type = type;
             }
 
+            @Nullable
             @Override
             public String getGroupId() {
                 return groupId;
             }
 
+            @Nullable
             @Override
             public String getArtifactId() {
                 return artifactId;
             }
 
+            @Nullable
             @Override
             public String getVersion() {
                 return version;
             }
 
+            @Nullable
             @Override
             public String getClassifier() {
                 return classifier;
             }
 
+            @Nullable
             @Override
             public String getExtension() {
                 return extension;
             }
 
+            @Nullable
             @Override
             public String getType() {
                 return type;
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
index 6f5a57e0ea..aaf5251843 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
@@ -60,8 +60,12 @@ static ArtifactInstallerRequest build(Session session, 
Collection<ProducedArtifa
 
     @NotThreadSafe
     class ArtifactInstallerRequestBuilder {
+        @Nullable
         Session session;
+
+        @Nullable
         RequestTrace trace;
+
         Collection<ProducedArtifact> artifacts = Collections.emptyList();
 
         ArtifactInstallerRequestBuilder() {}
@@ -86,7 +90,8 @@ public ArtifactInstallerRequestBuilder artifacts(@Nullable 
Collection<ProducedAr
 
         @Nonnull
         public ArtifactInstallerRequest build() {
-            return new DefaultArtifactInstallerRequest(session, trace, 
artifacts);
+            return new DefaultArtifactInstallerRequest(
+                    requireNonNull(session, "session cannot be null"), trace, 
artifacts);
         }
 
         static class DefaultArtifactInstallerRequest extends 
BaseRequest<Session> implements ArtifactInstallerRequest {
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
index 7e832a95e4..893b9352c4 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
@@ -73,9 +73,16 @@ static ArtifactResolverRequest build(
 
     @NotThreadSafe
     class ArtifactResolverRequestBuilder {
+        @Nullable
         Session session;
+
+        @Nullable
         RequestTrace trace;
+
+        @Nullable
         Collection<? extends ArtifactCoordinates> coordinates;
+
+        @Nullable
         List<RemoteRepository> repositories;
 
         ArtifactResolverRequestBuilder() {}
@@ -106,7 +113,11 @@ public ArtifactResolverRequestBuilder 
repositories(List<RemoteRepository> reposi
 
         @Nonnull
         public ArtifactResolverRequest build() {
-            return new DefaultArtifactResolverRequest(session, trace, 
coordinates, repositories);
+            return new DefaultArtifactResolverRequest(
+                    requireNonNull(session, "session cannot be null"),
+                    trace,
+                    requireNonNull(coordinates, "coordinates cannot be null"),
+                    repositories);
         }
 
         private static class DefaultArtifactResolverRequest extends 
BaseRequest<Session>
@@ -121,7 +132,7 @@ private static class DefaultArtifactResolverRequest extends 
BaseRequest<Session>
                     @Nonnull Session session,
                     @Nullable RequestTrace trace,
                     @Nonnull Collection<? extends ArtifactCoordinates> 
coordinates,
-                    @Nonnull List<RemoteRepository> repositories) {
+                    @Nullable List<RemoteRepository> repositories) {
                 super(session, trace);
                 this.coordinates = List.copyOf(requireNonNull(coordinates, 
"coordinates cannot be null"));
                 this.repositories = validate(repositories);
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
index 5f76c2c7bf..b2ca6bc217 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
@@ -74,6 +74,7 @@ public interface ArtifactResolverResult extends 
Result<ArtifactResolverRequest>
      * @param coordinates The {@link ArtifactCoordinates} identifying the 
artifact.
      * @return The corresponding {@link ResultItem}, or {@code null} if no 
result exists.
      */
+    @Nullable
     default ResultItem getResult(ArtifactCoordinates coordinates) {
         return getResults().get(coordinates);
     }
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
index b5e338466a..748a48e599 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
@@ -21,6 +21,7 @@
 import org.apache.maven.api.ProtoSession;
 import org.apache.maven.api.annotations.Experimental;
 import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
 
 import static java.util.Objects.requireNonNull;
 
@@ -33,13 +34,15 @@
 abstract class BaseRequest<S extends ProtoSession> implements Request<S> {
 
     private final S session;
+
+    @Nullable
     private final RequestTrace trace;
 
     protected BaseRequest(@Nonnull S session) {
         this(session, null);
     }
 
-    protected BaseRequest(@Nonnull S session, RequestTrace trace) {
+    protected BaseRequest(@Nonnull S session, @Nullable RequestTrace trace) {
         this.session = requireNonNull(session, "session cannot be null");
         this.trace = trace;
     }
@@ -50,6 +53,7 @@ public S getSession() {
         return session;
     }
 
+    @Nullable
     @Override
     public RequestTrace getTrace() {
         return trace;
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinatesFactoryRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinatesFactoryRequest.java
index c0314b2078..4f46d9bfe3 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinatesFactoryRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinatesFactoryRequest.java
@@ -43,6 +43,7 @@
 @Immutable
 public interface DependencyCoordinatesFactoryRequest extends 
ArtifactCoordinatesFactoryRequest {
 
+    @Nullable
     String getScope();
 
     boolean isOptional();
@@ -53,12 +54,12 @@ public interface DependencyCoordinatesFactoryRequest 
extends ArtifactCoordinates
     @Nonnull
     static DependencyCoordinatesFactoryRequest build(
             @Nonnull Session session,
-            String groupId,
-            String artifactId,
-            String version,
-            String classifier,
-            String extension,
-            String type) {
+            @Nullable String groupId,
+            @Nullable String artifactId,
+            @Nullable String version,
+            @Nullable String classifier,
+            @Nullable String extension,
+            @Nullable String type) {
         return DependencyCoordinatesFactoryRequest.builder()
                 .session(requireNonNull(session, "session cannot be null"))
                 .groupId(groupId)
@@ -106,16 +107,36 @@ static DependencyCoordinatesFactoryRequestBuilder 
builder() {
 
     @NotThreadSafe
     class DependencyCoordinatesFactoryRequestBuilder {
+        @Nullable
         private Session session;
+
+        @Nullable
         private RequestTrace trace;
+
+        @Nullable
         private String groupId;
+
+        @Nullable
         private String artifactId;
+
+        @Nullable
         private String version;
+
+        @Nullable
         private String classifier;
+
+        @Nullable
         private String extension;
+
+        @Nullable
         private String type;
+
+        @Nullable
         private String coordinateString;
+
+        @Nullable
         private String scope;
+
         private boolean optional;
         private Collection<Exclusion> exclusions = Collections.emptyList();
 
@@ -131,42 +152,42 @@ public DependencyCoordinatesFactoryRequestBuilder 
trace(RequestTrace trace) {
             return this;
         }
 
-        public DependencyCoordinatesFactoryRequestBuilder groupId(String 
groupId) {
+        public DependencyCoordinatesFactoryRequestBuilder groupId(@Nullable 
String groupId) {
             this.groupId = groupId;
             return this;
         }
 
-        public DependencyCoordinatesFactoryRequestBuilder artifactId(String 
artifactId) {
+        public DependencyCoordinatesFactoryRequestBuilder artifactId(@Nullable 
String artifactId) {
             this.artifactId = artifactId;
             return this;
         }
 
-        public DependencyCoordinatesFactoryRequestBuilder version(String 
version) {
+        public DependencyCoordinatesFactoryRequestBuilder version(@Nullable 
String version) {
             this.version = version;
             return this;
         }
 
-        public DependencyCoordinatesFactoryRequestBuilder classifier(String 
classifier) {
+        public DependencyCoordinatesFactoryRequestBuilder classifier(@Nullable 
String classifier) {
             this.classifier = classifier;
             return this;
         }
 
-        public DependencyCoordinatesFactoryRequestBuilder extension(String 
extension) {
+        public DependencyCoordinatesFactoryRequestBuilder extension(@Nullable 
String extension) {
             this.extension = extension;
             return this;
         }
 
-        public DependencyCoordinatesFactoryRequestBuilder type(String type) {
+        public DependencyCoordinatesFactoryRequestBuilder type(@Nullable 
String type) {
             this.type = type;
             return this;
         }
 
-        public DependencyCoordinatesFactoryRequestBuilder 
coordinateString(String coordinateString) {
+        public DependencyCoordinatesFactoryRequestBuilder 
coordinateString(@Nullable String coordinateString) {
             this.coordinateString = coordinateString;
             return this;
         }
 
-        public DependencyCoordinatesFactoryRequestBuilder scope(String scope) {
+        public DependencyCoordinatesFactoryRequestBuilder scope(@Nullable 
String scope) {
             this.scope = scope;
             return this;
         }
@@ -198,7 +219,7 @@ public DependencyCoordinatesFactoryRequestBuilder 
exclusion(Exclusion exclusion)
 
         public DependencyCoordinatesFactoryRequest build() {
             return new DefaultDependencyCoordinatesFactoryRequest(
-                    session,
+                    requireNonNull(session, "session cannot be null"),
                     trace,
                     groupId,
                     artifactId,
@@ -214,14 +235,30 @@ public DependencyCoordinatesFactoryRequest build() {
 
         private static class DefaultDependencyCoordinatesFactoryRequest 
extends BaseRequest<Session>
                 implements DependencyCoordinatesFactoryRequest {
+            @Nullable
             private final String groupId;
+
+            @Nullable
             private final String artifactId;
+
+            @Nullable
             private final String version;
+
+            @Nullable
             private final String classifier;
+
+            @Nullable
             private final String extension;
+
+            @Nullable
             private final String type;
+
+            @Nullable
             private final String coordinateString;
+
+            @Nullable
             private final String scope;
+
             private final boolean optional;
             private final Collection<Exclusion> exclusions;
 
@@ -229,14 +266,14 @@ private static class 
DefaultDependencyCoordinatesFactoryRequest extends BaseRequ
             private DefaultDependencyCoordinatesFactoryRequest(
                     @Nonnull Session session,
                     @Nullable RequestTrace trace,
-                    String groupId,
-                    String artifactId,
-                    String version,
-                    String classifier,
-                    String extension,
-                    String type,
-                    String coordinateString,
-                    String scope,
+                    @Nullable String groupId,
+                    @Nullable String artifactId,
+                    @Nullable String version,
+                    @Nullable String classifier,
+                    @Nullable String extension,
+                    @Nullable String type,
+                    @Nullable String coordinateString,
+                    @Nullable String scope,
                     boolean optional,
                     Collection<Exclusion> exclusions) {
                 super(session, trace);
@@ -252,41 +289,49 @@ private DefaultDependencyCoordinatesFactoryRequest(
                 this.exclusions = exclusions;
             }
 
+            @Nullable
             @Override
             public String getGroupId() {
                 return groupId;
             }
 
+            @Nullable
             @Override
             public String getArtifactId() {
                 return artifactId;
             }
 
+            @Nullable
             @Override
             public String getVersion() {
                 return version;
             }
 
+            @Nullable
             @Override
             public String getClassifier() {
                 return classifier;
             }
 
+            @Nullable
             @Override
             public String getExtension() {
                 return extension;
             }
 
+            @Nullable
             @Override
             public String getType() {
                 return type;
             }
 
+            @Nullable
             @Override
             public String getCoordinatesString() {
                 return coordinateString;
             }
 
+            @Nullable
             @Override
             public String getScope() {
                 return scope;
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
index 5be250824d..2bb516b24b 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyResolverRequest.java
@@ -191,18 +191,38 @@ static DependencyResolverRequest build(
     @NotThreadSafe
     class DependencyResolverRequestBuilder {
 
+        @Nullable
         Session session;
+
+        @Nullable
         RequestTrace trace;
+
+        @Nullable
         RequestType requestType;
+
+        @Nullable
         Project project;
+
+        @Nullable
         Artifact rootArtifact;
+
+        @Nullable
         DependencyCoordinates root;
+
         List<DependencyCoordinates> dependencies = Collections.emptyList();
         List<DependencyCoordinates> managedDependencies = 
Collections.emptyList();
         boolean verbose;
+
+        @Nullable
         PathScope pathScope;
+
+        @Nullable
         Predicate<PathType> pathTypeFilter;
+
+        @Nullable
         Version targetVersion;
+
+        @Nullable
         List<RemoteRepository> repositories;
 
         DependencyResolverRequestBuilder() {}
@@ -388,16 +408,16 @@ public DependencyResolverRequestBuilder 
repositories(@Nonnull List<RemoteReposit
         @Nonnull
         public DependencyResolverRequest build() {
             return new DefaultDependencyResolverRequest(
-                    session,
+                    requireNonNull(session, "session cannot be null"),
                     trace,
-                    requestType,
+                    requireNonNull(requestType, "requestType cannot be null"),
                     project,
                     rootArtifact,
                     root,
                     dependencies,
                     managedDependencies,
                     verbose,
-                    pathScope,
+                    requireNonNull(pathScope, "pathScope cannot be null"),
                     pathTypeFilter,
                     targetVersion,
                     repositories);
@@ -431,15 +451,26 @@ public String toString() {
             private static final Predicate<PathType> DEFAULT_FILTER = new 
AlwaysTrueFilter();
 
             private final RequestType requestType;
+
+            @Nullable
             private final Project project;
+
+            @Nullable
             private final Artifact rootArtifact;
+
+            @Nullable
             private final DependencyCoordinates root;
+
             private final Collection<DependencyCoordinates> dependencies;
             private final Collection<DependencyCoordinates> 
managedDependencies;
             private final boolean verbose;
             private final PathScope pathScope;
             private final Predicate<PathType> pathTypeFilter;
+
+            @Nullable
             private final Version targetVersion;
+
+            @Nullable
             private final List<RemoteRepository> repositories;
 
             /**
@@ -533,11 +564,13 @@ public Predicate<PathType> getPathTypeFilter() {
                 return pathTypeFilter;
             }
 
+            @Nullable
             @Override
             public Version getTargetVersion() {
                 return targetVersion;
             }
 
+            @Nullable
             @Override
             public List<RemoteRepository> getRepositories() {
                 return repositories;
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenBuilderException.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenBuilderException.java
index a39cb9aa1a..97b83bf54f 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenBuilderException.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenBuilderException.java
@@ -53,7 +53,7 @@ public MavenBuilderException(String message, Throwable cause) 
{
      * @param problems the collection of problems associated with this 
exception
      */
     public MavenBuilderException(String message, 
ProblemCollector<BuilderProblem> problems) {
-        super(buildMessage(message, problems), null);
+        super(buildMessage(message, problems), (Throwable) null);
         this.problems = problems;
     }
 
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenException.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenException.java
index cdd9ced96c..a5f42e9417 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenException.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenException.java
@@ -19,6 +19,7 @@
 package org.apache.maven.api.services;
 
 import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nullable;
 
 /**
  * Base class for all maven exceptions.
@@ -30,15 +31,15 @@ public class MavenException extends RuntimeException {
 
     public MavenException() {}
 
-    public MavenException(String message) {
+    public MavenException(@Nullable String message) {
         super(message);
     }
 
-    public MavenException(String message, Throwable cause) {
+    public MavenException(@Nullable String message, @Nullable Throwable cause) 
{
         super(message, cause);
     }
 
-    public MavenException(Throwable cause) {
+    public MavenException(@Nullable Throwable cause) {
         super(cause);
     }
 }
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
index 826ffe8fc4..53bf1592cd 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelBuilderRequest.java
@@ -130,7 +130,7 @@ enum RepositoryMerging {
     @Nonnull
     Map<String, String> getUserProperties();
 
-    @Nonnull
+    @Nullable
     RepositoryMerging getRepositoryMerging();
 
     @Nullable
@@ -171,19 +171,43 @@ static ModelBuilderRequestBuilder 
builder(ModelBuilderRequest request) {
 
     @NotThreadSafe
     class ModelBuilderRequestBuilder {
+        @Nullable
         Session session;
+
+        @Nullable
         RequestTrace trace;
+
+        @Nullable
         RequestType requestType;
+
         boolean locationTracking;
         boolean recursive;
+
+        @Nullable
         ModelSource source;
+
+        @Nullable
         Collection<Profile> profiles;
+
+        @Nullable
         List<String> activeProfileIds;
+
+        @Nullable
         List<String> inactiveProfileIds;
+
+        @Nullable
         Map<String, String> systemProperties;
+
+        @Nullable
         Map<String, String> userProperties;
+
+        @Nullable
         RepositoryMerging repositoryMerging;
+
+        @Nullable
         List<RemoteRepository> repositories;
+
+        @Nullable
         ModelTransformer lifecycleBindingsInjector;
 
         ModelBuilderRequestBuilder() {}
@@ -277,12 +301,12 @@ public ModelBuilderRequestBuilder 
lifecycleBindingsInjector(ModelTransformer lif
 
         public ModelBuilderRequest build() {
             return new DefaultModelBuilderRequest(
-                    session,
+                    requireNonNull(session, "session cannot be null"),
                     trace,
-                    requestType,
+                    requireNonNull(requestType, "requestType cannot be null"),
                     locationTracking,
                     recursive,
-                    source,
+                    requireNonNull(source, "source cannot be null"),
                     profiles,
                     activeProfileIds,
                     inactiveProfileIds,
@@ -297,14 +321,22 @@ private static class DefaultModelBuilderRequest extends 
BaseRequest<Session> imp
             private final RequestType requestType;
             private final boolean locationTracking;
             private final boolean recursive;
+
             private final ModelSource source;
+
             private final Collection<Profile> profiles;
             private final List<String> activeProfileIds;
             private final List<String> inactiveProfileIds;
             private final Map<String, String> systemProperties;
             private final Map<String, String> userProperties;
+
+            @Nullable
             private final RepositoryMerging repositoryMerging;
+
+            @Nullable
             private final List<RemoteRepository> repositories;
+
+            @Nullable
             private final ModelTransformer lifecycleBindingsInjector;
 
             @SuppressWarnings("checkstyle:ParameterNumber")
@@ -315,15 +347,16 @@ private static class DefaultModelBuilderRequest extends 
BaseRequest<Session> imp
                     boolean locationTracking,
                     boolean recursive,
                     @Nonnull ModelSource source,
-                    Collection<Profile> profiles,
-                    List<String> activeProfileIds,
-                    List<String> inactiveProfileIds,
-                    Map<String, String> systemProperties,
-                    Map<String, String> userProperties,
-                    RepositoryMerging repositoryMerging,
-                    List<RemoteRepository> repositories,
-                    ModelTransformer lifecycleBindingsInjector) {
+                    @Nullable Collection<Profile> profiles,
+                    @Nullable List<String> activeProfileIds,
+                    @Nullable List<String> inactiveProfileIds,
+                    @Nullable Map<String, String> systemProperties,
+                    @Nullable Map<String, String> userProperties,
+                    @Nullable RepositoryMerging repositoryMerging,
+                    @Nullable List<RemoteRepository> repositories,
+                    @Nullable ModelTransformer lifecycleBindingsInjector) {
                 super(session, trace);
+                Session s = getSession();
                 this.requestType = requireNonNull(requestType, "requestType 
cannot be null");
                 this.locationTracking = locationTracking;
                 this.recursive = recursive;
@@ -332,8 +365,8 @@ private static class DefaultModelBuilderRequest extends 
BaseRequest<Session> imp
                 this.activeProfileIds = activeProfileIds != null ? 
List.copyOf(activeProfileIds) : List.of();
                 this.inactiveProfileIds = inactiveProfileIds != null ? 
List.copyOf(inactiveProfileIds) : List.of();
                 this.systemProperties =
-                        systemProperties != null ? 
Map.copyOf(systemProperties) : session.getSystemProperties();
-                this.userProperties = userProperties != null ? 
Map.copyOf(userProperties) : session.getUserProperties();
+                        systemProperties != null ? 
Map.copyOf(systemProperties) : s.getSystemProperties();
+                this.userProperties = userProperties != null ? 
Map.copyOf(userProperties) : s.getUserProperties();
                 this.repositoryMerging = repositoryMerging;
                 this.repositories = repositories != null ? 
List.copyOf(validate(repositories)) : null;
                 this.lifecycleBindingsInjector = lifecycleBindingsInjector;
@@ -385,16 +418,19 @@ public Map<String, String> getUserProperties() {
                 return userProperties;
             }
 
+            @Nullable
             @Override
             public RepositoryMerging getRepositoryMerging() {
                 return repositoryMerging;
             }
 
+            @Nullable
             @Override
             public List<RemoteRepository> getRepositories() {
                 return repositories;
             }
 
+            @Nullable
             @Override
             public ModelTransformer getLifecycleBindingsInjector() {
                 return lifecycleBindingsInjector;
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblemCollector.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblemCollector.java
index 66c1fcc31e..9acffca804 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblemCollector.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ModelProblemCollector.java
@@ -18,6 +18,7 @@
  */
 package org.apache.maven.api.services;
 
+import org.apache.maven.api.annotations.Nullable;
 import org.apache.maven.api.model.InputLocation;
 import org.apache.maven.api.model.Model;
 
@@ -59,8 +60,8 @@ void add(
             BuilderProblem.Severity severity,
             ModelProblem.Version version,
             String message,
-            InputLocation location,
-            Exception exception);
+            @Nullable InputLocation location,
+            @Nullable Exception exception);
 
     default void add(ModelProblem problem) {
         getProblemCollector().reportProblem(problem);
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathMatcherFactory.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathMatcherFactory.java
index 9f83e2e0f8..3d7b7113c8 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathMatcherFactory.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PathMatcherFactory.java
@@ -26,6 +26,7 @@
 import org.apache.maven.api.Service;
 import org.apache.maven.api.annotations.Experimental;
 import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
 
 /**
  * Service for creating {@link PathMatcher} objects that can be used to filter 
files
@@ -66,8 +67,8 @@ public interface PathMatcherFactory extends Service {
     @Nonnull
     PathMatcher createPathMatcher(
             @Nonnull Path baseDirectory,
-            Collection<String> includes,
-            Collection<String> excludes,
+            @Nullable Collection<String> includes,
+            @Nullable Collection<String> excludes,
             boolean useDefaultExcludes);
 
     /**
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
index 307ee19559..b15263ce1c 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
@@ -146,13 +146,23 @@ static ProjectBuilderRequestBuilder builder() {
      */
     @NotThreadSafe
     class ProjectBuilderRequestBuilder {
+        @Nullable
         Session session;
+
+        @Nullable
         RequestTrace trace;
+
+        @Nullable
         Path path;
+
+        @Nullable
         Source source;
+
         boolean allowStubModel;
         boolean recursive;
         boolean processPlugins = true;
+
+        @Nullable
         List<RemoteRepository> repositories;
 
         ProjectBuilderRequestBuilder() {}
@@ -237,16 +247,29 @@ public ProjectBuilderRequestBuilder 
repositories(List<RemoteRepository> reposito
          */
         public ProjectBuilderRequest build() {
             return new DefaultProjectBuilderRequest(
-                    session, trace, path, source, allowStubModel, recursive, 
processPlugins, repositories);
+                    requireNonNull(session, "session cannot be null"),
+                    trace,
+                    path,
+                    source,
+                    allowStubModel,
+                    recursive,
+                    processPlugins,
+                    repositories);
         }
 
         private static class DefaultProjectBuilderRequest extends 
BaseRequest<Session>
                 implements ProjectBuilderRequest {
+            @Nullable
             private final Path path;
+
+            @Nullable
             private final Source source;
+
             private final boolean allowStubModel;
             private final boolean recursive;
             private final boolean processPlugins;
+
+            @Nullable
             private final List<RemoteRepository> repositories;
 
             @SuppressWarnings("checkstyle:ParameterNumber")
@@ -295,6 +318,7 @@ public boolean isProcessPlugins() {
                 return processPlugins;
             }
 
+            @Nullable
             @Override
             public List<RemoteRepository> getRepositories() {
                 return repositories;
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryAwareRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryAwareRequest.java
index f948ecdea4..845399582f 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryAwareRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryAwareRequest.java
@@ -97,7 +97,8 @@ public interface RepositoryAwareRequest extends 
Request<Session> {
      * @throws IllegalArgumentException if the list contains duplicate 
repositories
      * @throws IllegalArgumentException if the list contains null repository 
entries
      */
-    default List<RemoteRepository> validate(List<RemoteRepository> 
repositories) {
+    @Nullable
+    default List<RemoteRepository> validate(@Nullable List<RemoteRepository> 
repositories) {
         if (repositories == null) {
             return null;
         }
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilder.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilder.java
index 000ebb8837..086d5a0b25 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilder.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilder.java
@@ -53,7 +53,7 @@ public interface SettingsBuilder extends Service {
     @Nonnull
     default SettingsBuilderResult build(
             @Nonnull Session session, @Nonnull Source 
installationSettingsSource, @Nonnull Source userSettingsSource) {
-        return build(session, installationSettingsSource, null, 
userSettingsSource);
+        return build(SettingsBuilderRequest.build(session, 
installationSettingsSource, null, userSettingsSource));
     }
 
     /**
@@ -65,7 +65,7 @@ default SettingsBuilderResult build(
     @Nonnull
     default SettingsBuilderResult build(
             @Nonnull Session session, @Nonnull Path installationSettingsPath, 
@Nonnull Path userSettingsPath) {
-        return build(session, installationSettingsPath, null, 
userSettingsPath);
+        return build(SettingsBuilderRequest.build(session, 
installationSettingsPath, null, userSettingsPath));
     }
 
     /**
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
index 1ab8a9a15b..7a23421d70 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
@@ -130,11 +130,22 @@ static SettingsBuilderRequestBuilder builder() {
 
     @NotThreadSafe
     class SettingsBuilderRequestBuilder {
+        @Nullable
         ProtoSession session;
+
+        @Nullable
         RequestTrace trace;
+
+        @Nullable
         Source installationSettingsSource;
+
+        @Nullable
         Source projectSettingsSource;
+
+        @Nullable
         Source userSettingsSource;
+
+        @Nullable
         UnaryOperator<String> interpolationSource;
 
         public SettingsBuilderRequestBuilder session(ProtoSession session) {
@@ -147,29 +158,29 @@ public SettingsBuilderRequestBuilder trace(RequestTrace 
trace) {
             return this;
         }
 
-        public SettingsBuilderRequestBuilder installationSettingsSource(Source 
installationSettingsSource) {
+        public SettingsBuilderRequestBuilder 
installationSettingsSource(@Nullable Source installationSettingsSource) {
             this.installationSettingsSource = installationSettingsSource;
             return this;
         }
 
-        public SettingsBuilderRequestBuilder projectSettingsSource(Source 
projectSettingsSource) {
+        public SettingsBuilderRequestBuilder projectSettingsSource(@Nullable 
Source projectSettingsSource) {
             this.projectSettingsSource = projectSettingsSource;
             return this;
         }
 
-        public SettingsBuilderRequestBuilder userSettingsSource(Source 
userSettingsSource) {
+        public SettingsBuilderRequestBuilder userSettingsSource(@Nullable 
Source userSettingsSource) {
             this.userSettingsSource = userSettingsSource;
             return this;
         }
 
-        public SettingsBuilderRequestBuilder 
interpolationSource(UnaryOperator<String> interpolationSource) {
+        public SettingsBuilderRequestBuilder interpolationSource(@Nullable 
UnaryOperator<String> interpolationSource) {
             this.interpolationSource = interpolationSource;
             return this;
         }
 
         public SettingsBuilderRequest build() {
             return new DefaultSettingsBuilderRequest(
-                    session,
+                    requireNonNull(session, "session cannot be null"),
                     trace,
                     installationSettingsSource,
                     projectSettingsSource,
@@ -179,9 +190,16 @@ public SettingsBuilderRequest build() {
 
         private static class DefaultSettingsBuilderRequest extends 
BaseRequest<ProtoSession>
                 implements SettingsBuilderRequest {
+            @Nullable
             private final Source installationSettingsSource;
+
+            @Nullable
             private final Source projectSettingsSource;
+
+            @Nullable
             private final Source userSettingsSource;
+
+            @Nullable
             private final UnaryOperator<String> interpolationSource;
 
             @SuppressWarnings("checkstyle:ParameterNumber")
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Sources.java 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Sources.java
index 73d8978424..77003d0004 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Sources.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Sources.java
@@ -109,7 +109,7 @@ static class PathSource implements Source {
          * @param path the filesystem path to the source content
          * @throws NullPointerException if path is null
          */
-        PathSource(Path path) {
+        PathSource(@Nonnull Path path) {
             this(path, null);
         }
 
@@ -120,7 +120,7 @@ static class PathSource implements Source {
          * @param location the logical location of the source, used for 
reporting purposes.
          *                 If null, the path string representation is used
          */
-        protected PathSource(Path path, String location) {
+        protected PathSource(@Nonnull Path path, @Nullable String location) {
             this.path = requireNonNull(path, "path").normalize();
             this.location = location != null ? location : this.path.toString();
         }
@@ -173,12 +173,13 @@ static class ResolvedPathSource extends PathSource 
implements ModelSource {
         @Nullable
         private final String modelId;
 
-        ResolvedPathSource(Path path, String location, String modelId) {
+        ResolvedPathSource(@Nonnull Path path, @Nonnull String location, 
@Nullable String modelId) {
             super(path, location);
             this.modelId = modelId;
         }
 
         @Override
+        @Nullable
         public Path getPath() {
             return null;
         }
@@ -190,6 +191,7 @@ public String getModelId() {
         }
 
         @Override
+        @Nullable
         public Source resolve(String relative) {
             return null;
         }
@@ -238,7 +240,11 @@ public Source resolve(@Nonnull String relative) {
         @Nullable
         public ModelSource resolve(@Nonnull ModelLocator locator, @Nonnull 
String relative) {
             String norm = relative.replace('\\', 
File.separatorChar).replace('/', File.separatorChar);
-            Path path = getPath().getParent().resolve(norm);
+            Path parent = getPath().getParent();
+            if (parent == null) {
+                return null;
+            }
+            Path path = parent.resolve(norm);
             Path relatedPom = locator.locateExistingPom(path);
             if (relatedPom != null) {
                 return new BuildPathSource(relatedPom);
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManager.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManager.java
index b867cd4f08..888020c872 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManager.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManager.java
@@ -27,6 +27,7 @@
 import org.apache.maven.api.Toolchain;
 import org.apache.maven.api.annotations.Experimental;
 import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
 
 /**
  * Service interface for managing Maven toolchains, which provide abstraction 
for different
@@ -51,7 +52,7 @@ public interface ToolchainManager extends Service {
      * @throws ToolchainManagerException if toolchain retrieval fails
      */
     @Nonnull
-    List<Toolchain> getToolchains(@Nonnull Session session, String type, 
Map<String, String> requirements);
+    List<Toolchain> getToolchains(@Nonnull Session session, String type, 
@Nullable Map<String, String> requirements);
 
     /**
      * Retrieves all toolchains of the specified type without additional 
requirements.
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
index 0257ae6760..d45d285440 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
@@ -91,9 +91,16 @@ static ToolchainsBuilderRequestBuilder builder() {
 
     @NotThreadSafe
     class ToolchainsBuilderRequestBuilder {
+        @Nullable
         ProtoSession session;
+
+        @Nullable
         RequestTrace trace;
+
+        @Nullable
         Source installationToolchainsSource;
+
+        @Nullable
         Source userToolchainsSource;
 
         public ToolchainsBuilderRequestBuilder session(ProtoSession session) {
@@ -106,24 +113,31 @@ public ToolchainsBuilderRequestBuilder trace(RequestTrace 
trace) {
             return this;
         }
 
-        public ToolchainsBuilderRequestBuilder 
installationToolchainsSource(Source installationToolchainsSource) {
+        public ToolchainsBuilderRequestBuilder installationToolchainsSource(
+                @Nullable Source installationToolchainsSource) {
             this.installationToolchainsSource = installationToolchainsSource;
             return this;
         }
 
-        public ToolchainsBuilderRequestBuilder userToolchainsSource(Source 
userToolchainsSource) {
+        public ToolchainsBuilderRequestBuilder userToolchainsSource(@Nullable 
Source userToolchainsSource) {
             this.userToolchainsSource = userToolchainsSource;
             return this;
         }
 
         public ToolchainsBuilderRequest build() {
             return new 
ToolchainsBuilderRequestBuilder.DefaultToolchainsBuilderRequest(
-                    session, trace, installationToolchainsSource, 
userToolchainsSource);
+                    requireNonNull(session, "session cannot be null"),
+                    trace,
+                    installationToolchainsSource,
+                    userToolchainsSource);
         }
 
         private static class DefaultToolchainsBuilderRequest extends 
BaseRequest<ProtoSession>
                 implements ToolchainsBuilderRequest {
+            @Nullable
             private final Source installationToolchainsSource;
+
+            @Nullable
             private final Source userToolchainsSource;
 
             @SuppressWarnings("checkstyle:ParameterNumber")
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
index 50de8e9a80..207f93cfcc 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverRequest.java
@@ -148,10 +148,18 @@ static VersionResolverRequestBuilder builder() {
      */
     @NotThreadSafe
     class VersionResolverRequestBuilder {
+        @Nullable
         Session session;
+
+        @Nullable
         RequestTrace trace;
+
+        @Nullable
         ArtifactCoordinates artifactCoordinates;
+
+        @Nullable
         List<RemoteRepository> repositories;
+
         Nature nature = Nature.RELEASE_OR_SNAPSHOT;
 
         /**
@@ -194,7 +202,7 @@ public VersionResolverRequestBuilder 
artifactCoordinates(ArtifactCoordinates art
          * @param nature the repository nature, or {@code null} to use the 
default
          * @return this builder, never {@code null}
          */
-        public VersionResolverRequestBuilder nature(Nature nature) {
+        public VersionResolverRequestBuilder nature(@Nullable Nature nature) {
             this.nature = Objects.requireNonNullElse(nature, 
Nature.RELEASE_OR_SNAPSHOT);
             return this;
         }
@@ -205,7 +213,7 @@ public VersionResolverRequestBuilder nature(Nature nature) {
          * @param repositories the repositories, or {@code null} to use the 
session's repositories
          * @return this builder, never {@code null}
          */
-        public VersionResolverRequestBuilder 
repositories(List<RemoteRepository> repositories) {
+        public VersionResolverRequestBuilder repositories(@Nullable 
List<RemoteRepository> repositories) {
             this.repositories = repositories;
             return this;
         }
@@ -216,13 +224,21 @@ public VersionResolverRequestBuilder 
repositories(List<RemoteRepository> reposit
          * @return the version range resolver request, never {@code null}
          */
         public VersionRangeResolverRequest build() {
-            return new DefaultVersionResolverRequest(session, trace, 
artifactCoordinates, repositories, nature);
+            return new DefaultVersionResolverRequest(
+                    requireNonNull(session, "session cannot be null"),
+                    trace,
+                    requireNonNull(artifactCoordinates, "artifactCoordinates 
cannot be null"),
+                    repositories,
+                    nature);
         }
 
         private static class DefaultVersionResolverRequest extends 
BaseRequest<Session>
                 implements VersionRangeResolverRequest {
             private final ArtifactCoordinates artifactCoordinates;
+
+            @Nullable
             private final List<RemoteRepository> repositories;
+
             private final Nature nature;
 
             @SuppressWarnings("checkstyle:ParameterNumber")
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
index b510dcc2de..c44e91e76a 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionResolverRequest.java
@@ -68,9 +68,16 @@ static VersionResolverRequestBuilder builder() {
 
     @NotThreadSafe
     class VersionResolverRequestBuilder {
+        @Nullable
         Session session;
+
+        @Nullable
         RequestTrace trace;
+
+        @Nullable
         ArtifactCoordinates artifactCoordinates;
+
+        @Nullable
         List<RemoteRepository> repositories;
 
         public VersionResolverRequestBuilder session(Session session) {
@@ -88,18 +95,24 @@ public VersionResolverRequestBuilder 
artifactCoordinates(ArtifactCoordinates art
             return this;
         }
 
-        public VersionResolverRequestBuilder 
repositories(List<RemoteRepository> repositories) {
+        public VersionResolverRequestBuilder repositories(@Nullable 
List<RemoteRepository> repositories) {
             this.repositories = repositories;
             return this;
         }
 
         public VersionResolverRequest build() {
-            return new DefaultVersionResolverRequest(session, trace, 
artifactCoordinates, repositories);
+            return new DefaultVersionResolverRequest(
+                    requireNonNull(session, "session cannot be null"),
+                    trace,
+                    requireNonNull(artifactCoordinates, "artifactCoordinates 
cannot be null"),
+                    repositories);
         }
 
         private static class DefaultVersionResolverRequest extends 
BaseRequest<Session>
                 implements VersionResolverRequest {
             private final ArtifactCoordinates artifactCoordinates;
+
+            @Nullable
             private final List<RemoteRepository> repositories;
 
             @SuppressWarnings("checkstyle:ParameterNumber")
@@ -109,7 +122,7 @@ private static class DefaultVersionResolverRequest extends 
BaseRequest<Session>
                     @Nonnull ArtifactCoordinates artifactCoordinates,
                     @Nullable List<RemoteRepository> repositories) {
                 super(session, trace);
-                this.artifactCoordinates = artifactCoordinates;
+                this.artifactCoordinates = requireNonNull(artifactCoordinates, 
"artifactCoordinates cannot be null");
                 this.repositories = validate(repositories);
             }
 
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
index 41733eb08b..7aa8da1446 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
@@ -85,15 +85,32 @@ static XmlReaderRequestBuilder builder() {
 
     @NotThreadSafe
     class XmlReaderRequestBuilder {
+        @Nullable
         Path path;
+
+        @Nullable
         Path rootDirectory;
+
+        @Nullable
         URL url;
+
+        @Nullable
         InputStream inputStream;
+
+        @Nullable
         Reader reader;
+
+        @Nullable
         Transformer transformer;
+
         boolean strict;
+
+        @Nullable
         String modelId;
+
+        @Nullable
         String location;
+
         boolean addDefaultEntities = true;
 
         public XmlReaderRequestBuilder path(Path path) {
@@ -161,28 +178,45 @@ public XmlReaderRequest build() {
         }
 
         private static class DefaultXmlReaderRequest implements 
XmlReaderRequest {
+            @Nullable
             final Path path;
+
+            @Nullable
             final Path rootDirectory;
+
+            @Nullable
             final URL url;
+
+            @Nullable
             final InputStream inputStream;
+
+            @Nullable
             final Reader reader;
+
+            @Nullable
             final Transformer transformer;
+
             final boolean strict;
+
+            @Nullable
             final String modelId;
+
+            @Nullable
             final String location;
+
             final boolean addDefaultEntities;
 
             @SuppressWarnings("checkstyle:ParameterNumber")
             DefaultXmlReaderRequest(
-                    Path path,
-                    Path rootDirectory,
-                    URL url,
-                    InputStream inputStream,
-                    Reader reader,
-                    Transformer transformer,
+                    @Nullable Path path,
+                    @Nullable Path rootDirectory,
+                    @Nullable URL url,
+                    @Nullable InputStream inputStream,
+                    @Nullable Reader reader,
+                    @Nullable Transformer transformer,
                     boolean strict,
-                    String modelId,
-                    String location,
+                    @Nullable String modelId,
+                    @Nullable String location,
                     boolean addDefaultEntities) {
                 this.path = path;
                 this.rootDirectory = rootDirectory;
@@ -196,31 +230,37 @@ private static class DefaultXmlReaderRequest implements 
XmlReaderRequest {
                 this.addDefaultEntities = addDefaultEntities;
             }
 
+            @Nullable
             @Override
             public Path getPath() {
                 return path;
             }
 
+            @Nullable
             @Override
             public Path getRootDirectory() {
                 return rootDirectory;
             }
 
+            @Nullable
             @Override
             public URL getURL() {
                 return url;
             }
 
+            @Nullable
             @Override
             public InputStream getInputStream() {
                 return inputStream;
             }
 
+            @Nullable
             @Override
             public Reader getReader() {
                 return reader;
             }
 
+            @Nullable
             @Override
             public Transformer getTransformer() {
                 return transformer;
@@ -231,11 +271,13 @@ public boolean isStrict() {
                 return strict;
             }
 
+            @Nullable
             @Override
             public String getModelId() {
                 return modelId;
             }
 
+            @Nullable
             @Override
             public String getLocation() {
                 return location;
diff --git 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterRequest.java
 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterRequest.java
index 46ee89c8cf..e3c6bdb1b2 100644
--- 
a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterRequest.java
+++ 
b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterRequest.java
@@ -27,6 +27,8 @@
 import org.apache.maven.api.annotations.Nonnull;
 import org.apache.maven.api.annotations.Nullable;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * An XML writer request.
  *
@@ -56,10 +58,19 @@ static <T> XmlWriterRequestBuilder<T> builder() {
     }
 
     class XmlWriterRequestBuilder<T> {
+        @Nullable
         Path path;
+
+        @Nullable
         OutputStream outputStream;
+
+        @Nullable
         Writer writer;
+
+        @Nullable
         T content;
+
+        @Nullable
         Function<Object, String> inputLocationFormatter;
 
         public XmlWriterRequestBuilder<T> path(Path path) {
@@ -88,22 +99,35 @@ public XmlWriterRequestBuilder<T> 
inputLocationFormatter(Function<Object, String
         }
 
         public XmlWriterRequest<T> build() {
-            return new DefaultXmlWriterRequest<>(path, outputStream, writer, 
content, inputLocationFormatter);
+            return new DefaultXmlWriterRequest<>(
+                    path,
+                    outputStream,
+                    writer,
+                    requireNonNull(content, "content cannot be null"),
+                    inputLocationFormatter);
         }
 
         private static class DefaultXmlWriterRequest<T> implements 
XmlWriterRequest<T> {
+            @Nullable
             final Path path;
+
+            @Nullable
             final OutputStream outputStream;
+
+            @Nullable
             final Writer writer;
+
             final T content;
+
+            @Nullable
             final Function<Object, String> inputLocationFormatter;
 
             DefaultXmlWriterRequest(
-                    Path path,
-                    OutputStream outputStream,
-                    Writer writer,
-                    T content,
-                    Function<Object, String> inputLocationFormatter) {
+                    @Nullable Path path,
+                    @Nullable OutputStream outputStream,
+                    @Nullable Writer writer,
+                    @Nonnull T content,
+                    @Nullable Function<Object, String> inputLocationFormatter) 
{
                 this.path = path;
                 this.outputStream = outputStream;
                 this.writer = writer;
@@ -111,26 +135,31 @@ private static class DefaultXmlWriterRequest<T> 
implements XmlWriterRequest<T> {
                 this.inputLocationFormatter = inputLocationFormatter;
             }
 
+            @Nullable
             @Override
             public Path getPath() {
                 return path;
             }
 
+            @Nullable
             @Override
             public OutputStream getOutputStream() {
                 return outputStream;
             }
 
+            @Nullable
             @Override
             public Writer getWriter() {
                 return writer;
             }
 
+            @Nonnull
             @Override
             public T getContent() {
                 return content;
             }
 
+            @Nullable
             @Override
             public Function<Object, String> getInputLocationFormatter() {
                 return inputLocationFormatter;
diff --git 
a/api/maven-api-model/src/main/java/org/apache/maven/api/model/ModelObjectProcessor.java
 
b/api/maven-api-model/src/main/java/org/apache/maven/api/model/ModelObjectProcessor.java
index f1030709c0..eb9527f7d3 100644
--- 
a/api/maven-api-model/src/main/java/org/apache/maven/api/model/ModelObjectProcessor.java
+++ 
b/api/maven-api-model/src/main/java/org/apache/maven/api/model/ModelObjectProcessor.java
@@ -84,9 +84,12 @@ class ProcessorHolder {
 
         ModelObjectProcessor processor = 
ProcessorHolder.CACHED_PROCESSOR.get();
         if (processor == null) {
-            processor = loadProcessor();
-            ProcessorHolder.CACHED_PROCESSOR.compareAndSet(null, processor);
+            ModelObjectProcessor newProcessor = loadProcessor();
+            ProcessorHolder.CACHED_PROCESSOR.compareAndSet(null, newProcessor);
             processor = ProcessorHolder.CACHED_PROCESSOR.get();
+            if (processor == null) {
+                processor = newProcessor;
+            }
         }
         return processor.process(object);
     }
diff --git a/api/maven-api-model/src/main/mdo/maven.mdo 
b/api/maven-api-model/src/main/mdo/maven.mdo
index 74aff7785e..1ff0be615d 100644
--- a/api/maven-api-model/src/main/mdo/maven.mdo
+++ b/api/maven-api-model/src/main/mdo/maven.mdo
@@ -498,6 +498,7 @@
      * @return The base directory for the corresponding project or {@code 
null} if this model does not belong to a local
      *         project (e.g. describes the metadata of some artifact from the 
repository).
      */
+    @Nullable
     public Path getProjectDirectory() {
         return (pomFile != null) ? pomFile.getParent() : null;
     }
@@ -707,7 +708,7 @@
           <version>4.1.0+</version>
           <code>
             <![CDATA[
-    volatile Map<String, Plugin> pluginMap;
+    @Nullable volatile Map<String, Plugin> pluginMap;
 
     /**
      * @return a Map of plugins field with {@code Plugins#getKey()} as key
@@ -1371,7 +1372,7 @@
           <version>4.0.0+</version>
           <code>
             <![CDATA[
-    private volatile String managementKey;
+    @Nullable private volatile String managementKey;
 
     /**
      * @return the management key as {@code 
groupId:artifactId:type[:classifier]}
@@ -2285,6 +2286,7 @@
      * @deprecated this was unused and has no replacement, this method returns 
{@code null} now.
      */
     @Deprecated(since = "4.0.0")
+    @Nullable
     public String getMergeId() {
         return null;
     }
@@ -2755,7 +2757,7 @@
      * @param artifactId the artifact ID of the reporting plugin in the 
repository
      * @return the key of the plugin, ie {@code groupId:artifactId}
      */
-    public static String constructKey(String groupId, String artifactId) {
+    public static String constructKey(@Nullable String groupId, @Nullable 
String artifactId) {
         return groupId + ":" + artifactId;
     }
 
@@ -2850,7 +2852,7 @@
 
     @Override
     public String toString() {
-        return getId();
+        return String.valueOf(getId());
     }
             ]]>
           </code>
@@ -3365,7 +3367,7 @@
           <version>4.0.0+</version>
           <code>
             <![CDATA[
-    private java.util.Map<String, ReportSet> reportSetMap = null;
+    @Nullable private java.util.Map<String, ReportSet> reportSetMap = null;
 
     /**
      * Reset the {@code reportSetMap} field to {@code null}
@@ -3404,7 +3406,7 @@
      * @param artifactId The artifact ID of the reporting plugin in the 
repository
      * @return the key of the report plugin, ie {@code groupId:artifactId}
      */
-    public static String constructKey(String groupId, String artifactId) {
+    public static String constructKey(@Nullable String groupId, @Nullable 
String artifactId) {
         return groupId + ":" + artifactId;
     }
             ]]>
@@ -3445,7 +3447,7 @@
             <![CDATA[
     @Override
     public String toString() {
-        return getId();
+        return String.valueOf(getId());
     }
             ]]>
           </code>
diff --git a/api/maven-api-plugin/src/main/mdo/lifecycle.mdo 
b/api/maven-api-plugin/src/main/mdo/lifecycle.mdo
index c7e4539adb..577846281b 100644
--- a/api/maven-api-plugin/src/main/mdo/lifecycle.mdo
+++ b/api/maven-api-plugin/src/main/mdo/lifecycle.mdo
@@ -120,6 +120,7 @@ under the License.
      *
      * @return String
      */
+    @Nullable
     public String getEffectiveId() {
         if (executionPoint == null) {
             if (priority == 0) {
diff --git 
a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParserException.java
 
b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParserException.java
index 4520f0650b..91d5f8d5ec 100644
--- 
a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParserException.java
+++ 
b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParserException.java
@@ -19,6 +19,7 @@
 package org.apache.maven.api.spi;
 
 import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nullable;
 import org.apache.maven.api.services.MavenException;
 
 @Experimental
@@ -38,21 +39,21 @@ public ModelParserException() {
         this(null, null);
     }
 
-    public ModelParserException(String message) {
+    public ModelParserException(@Nullable String message) {
         this(message, null);
     }
 
-    public ModelParserException(String message, Throwable cause) {
+    public ModelParserException(@Nullable String message, @Nullable Throwable 
cause) {
         this(message, -1, -1, cause);
     }
 
-    public ModelParserException(String message, int lineNumber, int 
columnNumber, Throwable cause) {
+    public ModelParserException(@Nullable String message, int lineNumber, int 
columnNumber, @Nullable Throwable cause) {
         super(message, cause);
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
     }
 
-    public ModelParserException(Throwable cause) {
+    public ModelParserException(@Nullable Throwable cause) {
         this(null, cause);
     }
 
diff --git 
a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelTransformerException.java
 
b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelTransformerException.java
index d2f8443826..b72d4d507a 100644
--- 
a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelTransformerException.java
+++ 
b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelTransformerException.java
@@ -19,6 +19,7 @@
 package org.apache.maven.api.spi;
 
 import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nullable;
 import org.apache.maven.api.services.MavenException;
 
 @Experimental
@@ -28,15 +29,15 @@ public ModelTransformerException() {
         this(null, null);
     }
 
-    public ModelTransformerException(String message) {
+    public ModelTransformerException(@Nullable String message) {
         this(message, null);
     }
 
-    public ModelTransformerException(Throwable cause) {
+    public ModelTransformerException(@Nullable Throwable cause) {
         this(null, cause);
     }
 
-    public ModelTransformerException(String message, Throwable cause) {
+    public ModelTransformerException(@Nullable String message, @Nullable 
Throwable cause) {
         super(message, cause);
     }
 }
diff --git 
a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/ImmutableCollections.java
 
b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/ImmutableCollections.java
index 80abc22030..dbd12ad460 100644
--- 
a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/ImmutableCollections.java
+++ 
b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/ImmutableCollections.java
@@ -31,6 +31,8 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 
+import org.apache.maven.api.annotations.Nullable;
+
 /**
  * This should be removed when https://bugs.openjdk.org/browse/JDK-8323729
  * is released in our minimum JDK.
@@ -64,11 +66,11 @@ public int size() {
         }
     };
 
-    static <E1, E2 extends E1> List<E1> copy(Collection<E2> collection) {
+    static <E1, E2 extends E1> List<E1> copy(@Nullable Collection<E2> 
collection) {
         return collection == null ? List.of() : List.copyOf(collection);
     }
 
-    static <K, V> Map<K, V> copy(Map<K, V> map) {
+    static <K, V> Map<K, V> copy(@Nullable Map<K, V> map) {
         if (map == null) {
             return emptyMap();
         } else if (map instanceof AbstractImmutableMap) {
diff --git 
a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java 
b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java
index a78357a091..9b5303d1b3 100644
--- a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java
+++ b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java
@@ -244,6 +244,7 @@ default Object getInputLocation() {
      * @deprecated use {@link XmlService#merge(XmlNode, XmlNode, Boolean)} 
instead
      */
     @Deprecated(since = "4.0.0", forRemoval = true)
+    @Nullable
     default XmlNode merge(@Nullable XmlNode source) {
         return XmlService.merge(this, source);
     }
@@ -252,6 +253,7 @@ default XmlNode merge(@Nullable XmlNode source) {
      * @deprecated use {@link XmlService#merge(XmlNode, XmlNode, Boolean)} 
instead
      */
     @Deprecated(since = "4.0.0", forRemoval = true)
+    @Nullable
     default XmlNode merge(@Nullable XmlNode source, @Nullable Boolean 
childMergeOverride) {
         return XmlService.merge(this, source, childMergeOverride);
     }
@@ -353,12 +355,25 @@ static Builder newBuilder() {
      * {@link #build()}.
      */
     class Builder {
+        @Nullable
         private String name;
+
+        @Nullable
         private String value;
+
+        @Nullable
         private String namespaceUri;
+
+        @Nullable
         private String prefix;
+
+        @Nullable
         private Map<String, String> attributes;
+
+        @Nullable
         private List<XmlNode> children;
+
+        @Nullable
         private Object inputLocation;
 
         /**
@@ -458,30 +473,41 @@ public XmlNode build() {
         }
 
         private record Impl(
-                String prefix,
-                String namespaceUri,
+                @Nonnull String prefix,
+                @Nonnull String namespaceUri,
                 @Nonnull String name,
-                String value,
+                @Nullable String value,
                 @Nonnull Map<String, String> attributes,
                 @Nonnull List<XmlNode> children,
-                Object inputLocation)
+                @Nullable Object inputLocation)
                 implements XmlNode, Serializable {
 
-            private Impl {
+            private Impl(
+                    @Nullable String prefix,
+                    @Nullable String namespaceUri,
+                    @Nullable String name,
+                    @Nullable String value,
+                    @Nullable Map<String, String> attributes,
+                    @Nullable List<XmlNode> children,
+                    @Nullable Object inputLocation) {
                 // Validation and normalization from the original constructor
-                prefix = prefix == null ? "" : prefix;
-                namespaceUri = namespaceUri == null ? "" : namespaceUri;
-                name = Objects.requireNonNull(name);
-                attributes = ImmutableCollections.copy(attributes);
-                children = ImmutableCollections.copy(children);
+                this.prefix = prefix == null ? "" : prefix;
+                this.namespaceUri = namespaceUri == null ? "" : namespaceUri;
+                this.name = Objects.requireNonNull(name);
+                this.value = value;
+                this.attributes = ImmutableCollections.copy(attributes);
+                this.children = ImmutableCollections.copy(children);
+                this.inputLocation = inputLocation;
             }
 
             @Override
+            @Nullable
             public String attribute(@Nonnull String name) {
                 return attributes.get(name);
             }
 
             @Override
+            @Nullable
             public XmlNode child(String name) {
                 if (name != null) {
                     ListIterator<XmlNode> it = 
children.listIterator(children.size());
@@ -528,7 +554,7 @@ private String toStringObject() {
                 w = addToStringField(sb, prefix, o -> !o.isEmpty(), "prefix", 
w);
                 w = addToStringField(sb, namespaceUri, o -> !o.isEmpty(), 
"namespaceUri", w);
                 w = addToStringField(sb, name, o -> !o.isEmpty(), "name", w);
-                w = addToStringField(sb, value, o -> !o.isEmpty(), "value", w);
+                w = addToStringField(sb, value, o -> o != null && 
!o.isEmpty(), "value", w);
                 w = addToStringField(sb, attributes, o -> !o.isEmpty(), 
"attributes", w);
                 w = addToStringField(sb, children, o -> !o.isEmpty(), 
"children", w);
                 w = addToStringField(sb, inputLocation, Objects::nonNull, 
"inputLocation", w);
@@ -537,7 +563,7 @@ private String toStringObject() {
             }
 
             private static <T> boolean addToStringField(
-                    StringBuilder sb, T o, Function<T, Boolean> p, String n, 
boolean w) {
+                    StringBuilder sb, @Nullable T o, Function<T, Boolean> p, 
String n, boolean w) {
                 if (!p.apply(o)) {
                     if (w) {
                         sb.append(", ");
diff --git 
a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlService.java 
b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlService.java
index e6735e255f..a173026968 100644
--- a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlService.java
+++ b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlService.java
@@ -106,7 +106,7 @@ public abstract class XmlService {
      * Convenience method to merge two XML nodes using default settings.
      */
     @Nullable
-    public static XmlNode merge(XmlNode dominant, XmlNode recessive) {
+    public static XmlNode merge(@Nullable XmlNode dominant, @Nullable XmlNode 
recessive) {
         return merge(dominant, recessive, null);
     }
 
@@ -184,7 +184,7 @@ public interface InputLocationBuilder {
      * @return the parsed XML node
      * @throws XMLStreamException if there is an error parsing the XML
      */
-    protected abstract XmlNode doRead(InputStream input, InputLocationBuilder 
locationBuilder)
+    protected abstract XmlNode doRead(InputStream input, @Nullable 
InputLocationBuilder locationBuilder)
             throws XMLStreamException;
 
     /**
@@ -195,7 +195,8 @@ protected abstract XmlNode doRead(InputStream input, 
InputLocationBuilder locati
      * @return the parsed XML node
      * @throws XMLStreamException if there is an error parsing the XML
      */
-    protected abstract XmlNode doRead(Reader reader, InputLocationBuilder 
locationBuilder) throws XMLStreamException;
+    protected abstract XmlNode doRead(Reader reader, @Nullable 
InputLocationBuilder locationBuilder)
+            throws XMLStreamException;
 
     /**
      * Implementation method for reading an XML node from an XMLStreamReader.
@@ -205,7 +206,7 @@ protected abstract XmlNode doRead(InputStream input, 
InputLocationBuilder locati
      * @return the parsed XML node
      * @throws XMLStreamException if there is an error parsing the XML
      */
-    protected abstract XmlNode doRead(XMLStreamReader reader, 
InputLocationBuilder locationBuilder)
+    protected abstract XmlNode doRead(XMLStreamReader reader, @Nullable 
InputLocationBuilder locationBuilder)
             throws XMLStreamException;
 
     /**
@@ -225,7 +226,9 @@ protected abstract XmlNode doRead(XMLStreamReader reader, 
InputLocationBuilder l
      * @param childMergeOverride optional override for the child merge mode
      * @return the merged XML node, or null if both inputs are null
      */
-    protected abstract XmlNode doMerge(XmlNode dominant, XmlNode recessive, 
Boolean childMergeOverride);
+    @Nullable
+    protected abstract XmlNode doMerge(
+            @Nullable XmlNode dominant, @Nullable XmlNode recessive, @Nullable 
Boolean childMergeOverride);
 
     /**
      * Gets the singleton instance of the XmlService.
diff --git a/pom.xml b/pom.xml
index 6437ae1709..7ef12f71a4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1254,5 +1254,52 @@ under the License.
         </plugins>
       </build>
     </profile>
+    <profile>
+      <id>nullaway</id>
+      <properties>
+        <errorProneVersion>2.36.0</errorProneVersion>
+        <nullawayVersion>0.12.6</nullawayVersion>
+      </properties>
+      <build>
+        <pluginManagement>
+          <plugins>
+            <plugin>
+              <groupId>org.apache.maven.plugins</groupId>
+              <artifactId>maven-compiler-plugin</artifactId>
+              <configuration>
+                <fork>true</fork>
+                <compilerArgs>
+                  
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
+                  
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
+                  
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
+                  
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
+                  
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
+                  
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
+                  
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
+                  
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
+                  
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
+                  
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
+                  <arg>-XDcompilePolicy=simple</arg>
+                  <arg>-XDshould-stop.ifError=FLOW</arg>
+                  <arg>-Xplugin:ErrorProne -XepDisableAllChecks 
-Xep:NullAway:WARN -XepOpt:NullAway:AnnotatedPackages=org.apache.maven 
-XepOpt:NullAway:CustomNullableAnnotations=org.apache.maven.api.annotations.Nullable
 
-XepOpt:NullAway:CustomNonnullAnnotations=org.apache.maven.api.annotations.Nonnull</arg>
+                </compilerArgs>
+                <annotationProcessorPaths>
+                  <path>
+                    <groupId>com.google.errorprone</groupId>
+                    <artifactId>error_prone_core</artifactId>
+                    <version>${errorProneVersion}</version>
+                  </path>
+                  <path>
+                    <groupId>com.uber.nullaway</groupId>
+                    <artifactId>nullaway</artifactId>
+                    <version>${nullawayVersion}</version>
+                  </path>
+                </annotationProcessorPaths>
+              </configuration>
+            </plugin>
+          </plugins>
+        </pluginManagement>
+      </build>
+    </profile>
   </profiles>
 </project>
diff --git a/src/mdo/java/ImmutableCollections.java 
b/src/mdo/java/ImmutableCollections.java
index 9e205f18cf..ff5eb059b7 100644
--- a/src/mdo/java/ImmutableCollections.java
+++ b/src/mdo/java/ImmutableCollections.java
@@ -31,6 +31,8 @@
 import java.util.function.Function;
 import java.util.function.Predicate;
 
+import org.apache.maven.api.annotations.Nullable;
+
 /**
  * This should be removed when https://bugs.openjdk.org/browse/JDK-8323729
  * is released in our minimum JDK.
@@ -64,11 +66,11 @@ public int size() {
         }
     };
 
-    static <E1, E2 extends E1> List<E1> copy(Collection<E2> collection) {
+    static <E1, E2 extends E1> List<E1> copy(@Nullable Collection<E2> 
collection) {
         return collection == null ? List.of() : List.copyOf(collection);
     }
 
-    static <K, V> Map<K, V> copy(Map<K, V> map) {
+    static <K, V> Map<K, V> copy(@Nullable Map<K, V> map) {
         if (map == null) {
             return emptyMap();
         } else if (map instanceof AbstractImmutableMap) {
diff --git a/src/mdo/java/InputLocation.java b/src/mdo/java/InputLocation.java
index c01343ad67..5ba8170175 100644
--- a/src/mdo/java/InputLocation.java
+++ b/src/mdo/java/InputLocation.java
@@ -25,6 +25,8 @@
 import java.util.Map;
 import java.util.Objects;
 
+import org.apache.maven.api.annotations.Nullable;
+
 /**
  * Represents the location of an element within a model source file.
  * <p>
@@ -42,14 +44,14 @@
 public final class InputLocation implements Serializable, InputLocationTracker 
{
     private final int lineNumber;
     private final int columnNumber;
-    private final InputSource source;
+    @Nullable private final InputSource source;
     private final Map<Object, InputLocation> locations;
 #if ( $isMavenModel )
-    private final InputLocation importedFrom;
+    @Nullable private final InputLocation importedFrom;
 
     private volatile int hashCode = 0; // Cached hashCode for performance
 #else
-    private final InputLocation importedFrom;
+    @Nullable private final InputLocation importedFrom;
 #end
 
     private static final InputLocation EMPTY = new InputLocation(-1, -1);
@@ -75,7 +77,7 @@ public final class InputLocation implements Serializable, 
InputLocationTracker {
      * @param columnNumber the column number in the source file (1-based)
      */
     InputLocation(int lineNumber, int columnNumber) {
-        this(lineNumber, columnNumber, null, null);
+        this(lineNumber, columnNumber, (InputSource) null, null);
     }
 
     /**
@@ -85,7 +87,7 @@ public final class InputLocation implements Serializable, 
InputLocationTracker {
      * @param columnNumber the column number in the source file (1-based)
      * @param source the input source where this location originates from
      */
-    InputLocation(int lineNumber, int columnNumber, InputSource source) {
+    InputLocation(int lineNumber, int columnNumber, @Nullable InputSource 
source) {
         this(lineNumber, columnNumber, source, null);
     }
 
@@ -97,7 +99,7 @@ public final class InputLocation implements Serializable, 
InputLocationTracker {
      * @param source the input source where this location originates from
      * @param selfLocationKey the key to map this location to itself in the 
locations map
      */
-    InputLocation(int lineNumber, int columnNumber, InputSource source, Object 
selfLocationKey) {
+    InputLocation(int lineNumber, int columnNumber, @Nullable InputSource 
source, @Nullable Object selfLocationKey) {
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
         this.source = source;
@@ -115,7 +117,7 @@ public final class InputLocation implements Serializable, 
InputLocationTracker {
      * @param source the input source where this location originates from
      * @param locations a map of keys to InputLocation instances for nested 
elements
      */
-    InputLocation(int lineNumber, int columnNumber, InputSource source, 
Map<Object, InputLocation> locations) {
+    InputLocation(int lineNumber, int columnNumber, @Nullable InputSource 
source, @Nullable Map<Object, InputLocation> locations) {
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
         this.source = source;
@@ -250,6 +252,7 @@ public int getColumnNumber() {
      *
      * @return the input source, or null if unknown
      */
+    @Nullable
     public InputSource getSource() {
         return source;
     }
@@ -260,10 +263,11 @@ public InputSource getSource() {
      * @param key the key to look up
      * @return the InputLocation for the specified key, or null if not found
      */
+    @Nullable
     @Override
     public InputLocation getLocation(Object key) {
         Objects.requireNonNull(key, "key");
-        return locations != null ? locations.get(key) : null;
+        return locations.get(key);
     }
 
     /**
@@ -282,6 +286,7 @@ public Map<Object, InputLocation> getLocations() {
      * @return InputLocation
      * @since 4.0.0
      */
+    @Nullable
     @Override
     public InputLocation getImportedFrom() {
         return importedFrom;
@@ -295,7 +300,8 @@ public InputLocation getImportedFrom() {
      * @param sourceDominant the boolean indicating of {@code source} is 
dominant compared to {@code target}
      * @return the merged location
      */
-    public static InputLocation merge(InputLocation target, InputLocation 
source, boolean sourceDominant) {
+    @Nullable
+    public static InputLocation merge(@Nullable InputLocation target, 
@Nullable InputLocation source, boolean sourceDominant) {
         if (source == null) {
             return target;
         } else if (target == null) {
@@ -332,7 +338,8 @@ public static InputLocation merge(InputLocation target, 
InputLocation source, bo
      * @param indices the list of integers for the indices
      * @return the merged location
      */
-    public static InputLocation merge(InputLocation target, InputLocation 
source, Collection<Integer> indices) {
+    @Nullable
+    public static InputLocation merge(@Nullable InputLocation target, 
@Nullable InputLocation source, Collection<Integer> indices) {
         if (source == null) {
             return target;
         } else if (target == null) {
@@ -389,9 +396,9 @@ && safeLocationsEquals(this, locations, that, 
that.locations)
      */
     private static boolean safeLocationsEquals(
             InputLocation this1,
-            Map<Object, InputLocation> map1,
+            @Nullable Map<Object, InputLocation> map1,
             InputLocation this2,
-            Map<Object, InputLocation> map2) {
+            @Nullable Map<Object, InputLocation> map2) {
         if (map1 == map2) {
             return true;
         }
@@ -433,7 +440,7 @@ public int hashCode() {
         return result;
     }
 
-    public int safeHash(Map<Object, InputLocation> locations) {
+    public int safeHash(@Nullable Map<Object, InputLocation> locations) {
         if (locations == null) {
             return 0;
         }
diff --git a/src/mdo/java/InputLocationTracker.java 
b/src/mdo/java/InputLocationTracker.java
index a70ac293cf..f4212817c8 100644
--- a/src/mdo/java/InputLocationTracker.java
+++ b/src/mdo/java/InputLocationTracker.java
@@ -18,6 +18,8 @@
  */
 package ${package};
 
+import org.apache.maven.api.annotations.Nullable;
+
 /**
  * Tracks input source locations for model fields.
  * <p>
@@ -35,6 +37,7 @@ public interface InputLocationTracker {
      * @return the location of the field in the input source or {@code null} 
if unknown
      * @throws NullPointerException if {@code field} is {@code null}
      */
+    @Nullable
     InputLocation getLocation(Object field);
 
     /**
@@ -44,5 +47,6 @@ public interface InputLocationTracker {
      * @return InputLocation
      * @since 4.0.0
      */
+    @Nullable
     InputLocation getImportedFrom();
 }
diff --git a/src/mdo/java/InputSource.java b/src/mdo/java/InputSource.java
index 79eb0fb0f7..ee5bc7e7fc 100644
--- a/src/mdo/java/InputSource.java
+++ b/src/mdo/java/InputSource.java
@@ -25,6 +25,8 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
+import org.apache.maven.api.annotations.Nullable;
+
 /**
  * Represents the source of a model input, such as a POM file.
  * <p>
@@ -41,22 +43,22 @@
 public final class InputSource implements Serializable {
 
 #if ( $isMavenModel )
-    private final String modelId;
+    @Nullable private final String modelId;
 #end
-    private final String location;
-    private final List<InputSource> inputs;
-    private final InputLocation importedFrom;
+    @Nullable private final String location;
+    @Nullable private final List<InputSource> inputs;
+    @Nullable private final InputLocation importedFrom;
 
 #if ( $isMavenModel )
     private volatile int hashCode = 0; // Cached hashCode for performance
 #end
 
 #if ( $isMavenModel )
-    public InputSource(String modelId, String location) {
+    public InputSource(@Nullable String modelId, @Nullable String location) {
         this(modelId, location, null);
     }
 
-    public InputSource(String modelId, String location, InputLocation 
importedFrom) {
+    public InputSource(@Nullable String modelId, @Nullable String location, 
@Nullable InputLocation importedFrom) {
         this.modelId = modelId;
         this.location = location;
         this.inputs = null;
@@ -69,7 +71,7 @@ public InputSource(String modelId, String location, 
InputLocation importedFrom)
      *
      * @param location the path/URL of the input source, may be null
      */
-    InputSource(String location) {
+    InputSource(@Nullable String location) {
 #if ( $isMavenModel )
         this.modelId = null;
 #end
@@ -150,6 +152,7 @@ public static InputSource of(Collection<InputSource> 
inputs) {
      *
      * @return the location string, or null if unknown
      */
+    @Nullable
     public String getLocation() {
         return this.location;
     }
@@ -160,6 +163,7 @@ public String getLocation() {
      *
      * @return the model id
      */
+    @Nullable
     public String getModelId() {
         return this.modelId;
     }
@@ -172,6 +176,7 @@ public String getModelId() {
      * @return InputLocation
      * @since 4.0.0
      */
+    @Nullable
     public InputLocation getImportedFrom() {
         return importedFrom;
     }
@@ -237,9 +242,9 @@ public String toString() {
             return 
inputs.stream().map(InputSource::toString).collect(Collectors.joining(", ", 
"merged[", "]"));
         }
 #if ( $isMavenModel )
-        return getModelId() != null ? getModelId() + " " + getLocation() : 
getLocation();
+        return getModelId() != null ? getModelId() + " " + getLocation() : 
String.valueOf(getLocation());
 #else
-        return getLocation();
+        return String.valueOf(getLocation());
 #end
     }
 
@@ -251,7 +256,14 @@ public String toString() {
      * @param src2 the second input source to merge
      * @return a new merged InputSource containing all distinct sources from 
both inputs
      */
-    public static InputSource merge(InputSource src1, InputSource src2) {
+    @Nullable
+    public static InputSource merge(@Nullable InputSource src1, @Nullable 
InputSource src2) {
+        if (src1 == null) {
+            return src2;
+        }
+        if (src2 == null) {
+            return src1;
+        }
 #if ( $isMavenModel )
         return new InputSource(
                 Stream.concat(src1.sources(), 
src2.sources()).distinct().toList());
diff --git a/src/mdo/model.vm b/src/mdo/model.vm
index 481ee0b489..935d266a4a 100644
--- a/src/mdo/model.vm
+++ b/src/mdo/model.vm
@@ -59,6 +59,7 @@
     #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Immutable" 
) )
     #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Nonnull" ) 
)
     #set ( $dummy = $imports.add( 
"org.apache.maven.api.annotations.NotThreadSafe" ) )
+    #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Nullable" 
) )
     #set ( $dummy = $imports.add( 
"org.apache.maven.api.annotations.ThreadSafe" ) )
     #if ( $package == "org.apache.maven.api.model" )
     #set ( $dummy = $imports.add( 
"org.apache.maven.api.model.ModelObjectProcessor" ) )
@@ -133,7 +134,9 @@ public class ${class.name}
     #end
 {
     #if ( $class == $root )
+    @Nullable
     final String namespaceUri;
+    @Nullable
     final String modelEncoding;
     #end
     #foreach ( $field in $class.getFields($version) )
@@ -146,12 +149,16 @@ public class ${class.name}
       #foreach( $ann in ${field.annotations} )
     ${ann}
       #end
+      #if ( $field.type != "java.util.List" && $field.type != 
"java.util.Properties" && $field.type != "java.util.Map" && $field.type != 
"boolean" && $field.type != "int" )
+    @Nullable
+      #end
     final ${type} $field.name;
     #end
     #if ( $locationTracking && ! $class.superClass )
     /** Locations */
     final Map<Object, InputLocation> locations;
     /** Location tracking */
+    @Nullable
     final InputLocation importedFrom;
     #end
 
@@ -204,10 +211,12 @@ public class ${class.name}
 
     #end
     #if ( $class == $root )
+    @Nullable
     public String getNamespaceUri() {
         return namespaceUri;
     }
 
+    @Nullable
     public String getModelEncoding() {
         return modelEncoding;
     }
@@ -234,6 +243,8 @@ public class ${class.name}
       #end
       #if ( $field.type == "java.util.List" || $field.type == 
"java.util.Properties" )
     @Nonnull
+      #elseif ( $field.type != "boolean" && $field.type != "int" )
+    @Nullable
       #end
     public ${type} ${pfx}${cap}() {
         return this.${field.name};
@@ -248,6 +259,7 @@ public class ${class.name}
      * @return the location of the field in the input source or {@code null} 
if unknown
      * @throws NullPointerException if {@code key} is {@code null}
      */
+    @Nullable
     public InputLocation getLocation(Object key) {
         Objects.requireNonNull(key, "key");
         return locations.get(key);
@@ -267,6 +279,7 @@ public class ${class.name}
     /**
      * Gets the input location that caused this model to be read.
      */
+    @Nullable
     public InputLocation getImportedFrom() {
         return importedFrom;
     }
@@ -384,10 +397,10 @@ public class ${class.name}
         extends ${class.superClass}.Builder
     #end
     {
-        ${class.name} base;
+        @Nullable ${class.name} base;
     #if ( $class == $root )
-        String namespaceUri;
-        String modelEncoding;
+        @Nullable String namespaceUri;
+        @Nullable String modelEncoding;
     #end
     #foreach ( $field in $class.getFields($version) )
       #set ( $type = 
${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
@@ -395,16 +408,16 @@ public class ${class.name}
         #set ( $type = ${type.replace('List<','Collection<')} )
       #end
       #if ( $type == 'boolean' )
-        Boolean ${field.name};
+        @Nullable Boolean ${field.name};
       #elseif ( $type == 'int' )
-        Integer ${field.name};
+        @Nullable Integer ${field.name};
       #else
-        ${type} ${field.name};
+        @Nullable ${type} ${field.name};
     #end
     #end
     #if ( ! $class.superClass && $locationTracking )
-        Map<Object, InputLocation> locations;
-        InputLocation importedFrom;
+        @Nullable Map<Object, InputLocation> locations;
+        @Nullable InputLocation importedFrom;
     #end
 
         protected Builder(boolean withDefaults) {

Reply via email to