You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sl...@apache.org on 2026/08/22 14:52:56 UTC

(maven-resolver-ant-tasks) 01/06: Derive POM dependencies through Maven's own descriptor delegate

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

slachiewicz pushed a commit to branch pom-conversion-parity
in repository https://gitbox.apache.org/repos/asf/maven-resolver-ant-tasks.git

commit 91bba793a70cdd917bede351a5551fee21a4cf87
Author: Sylwester Lachiewicz <sl...@apache.org>
AuthorDate: Sat Aug 22 16:43:27 2026 +0200

    Derive POM dependencies through Maven's own descriptor delegate
    
    The hand-written model-to-CollectRequest conversion had drifted from
    ArtifactDescriptorReaderDelegate, the code Maven runs for the same job:
    it pinned optional to false instead of carrying the model's tri-state
    value, so dependency management could no longer manage optionality.
    
    Do not restore the local conversion to fix a single field. Delegating
    keeps the two in step for every field, now and later.
    
    The POM repositories the delegate collects are deliberately not applied
    here; that is a behaviour change and comes separately.
---
 .../maven/resolver/internal/ant/AntRepoSys.java    | 65 ++++------------
 .../resolver/internal/ant/ConverterUtils.java      | 87 +++++++++++++++++++---
 2 files changed, 91 insertions(+), 61 deletions(-)

diff --git a/src/main/java/org/apache/maven/resolver/internal/ant/AntRepoSys.java b/src/main/java/org/apache/maven/resolver/internal/ant/AntRepoSys.java
index fa31322..a72ffea 100644
--- a/src/main/java/org/apache/maven/resolver/internal/ant/AntRepoSys.java
+++ b/src/main/java/org/apache/maven/resolver/internal/ant/AntRepoSys.java
@@ -95,6 +95,7 @@ import org.eclipse.aether.installation.InstallationException;
 import org.eclipse.aether.repository.AuthenticationSelector;
 import org.eclipse.aether.repository.MirrorSelector;
 import org.eclipse.aether.repository.ProxySelector;
+import org.eclipse.aether.resolution.ArtifactDescriptorResult;
 import org.eclipse.aether.supplier.RepositorySystemSupplier;
 import org.eclipse.aether.supplier.SessionBuilderSupplier;
 import org.eclipse.aether.util.repository.AuthenticationBuilder;
@@ -782,7 +783,7 @@ public class AntRepoSys {
         for (DependencyContainer container : dependencies.getDependencyContainers()) {
             if (container instanceof Dependency) {
                 Dependency dep = (Dependency) container;
-                ids.add(dep.getVersionlessKey());
+                ids.add(ConverterUtils.versionlessKey(dep, session));
                 collectRequest.addDependency(ConverterUtils.toDependency(dep, globalExclusions, session));
             } else {
                 populateCollectRequest(collectRequest, task, session, (Dependencies) container, globalExclusions);
@@ -791,69 +792,31 @@ public class AntRepoSys {
 
         if (dependencies.getPom() != null) {
             Model model = dependencies.getPom().getModel(task);
-            if (model.getDependencyManagement() != null) {
-                for (org.apache.maven.model.Dependency manDep :
-                        model.getDependencyManagement().getDependencies()) {
-                    Dependency dependency = new Dependency();
-                    dependency.setArtifactId(manDep.getArtifactId());
-                    dependency.setClassifier(manDep.getClassifier());
-                    dependency.setGroupId(manDep.getGroupId());
-                    dependency.setScope(manDep.getScope());
-                    dependency.setType(manDep.getType());
-                    dependency.setVersion(manDep.getVersion());
-                    if (manDep.getSystemPath() != null
-                            && !manDep.getSystemPath().isEmpty()) {
-                        dependency.setSystemPath(task.getProject().resolveFile(manDep.getSystemPath()));
-                    }
-                    for (org.apache.maven.model.Exclusion exc : manDep.getExclusions()) {
-                        Exclusion exclusion = new Exclusion();
-                        exclusion.setGroupId(exc.getGroupId());
-                        exclusion.setArtifactId(exc.getArtifactId());
-                        exclusion.setClassifier("*");
-                        exclusion.setExtension("*");
-                        dependency.addExclusion(exclusion);
-                    }
-                    collectRequest.addManagedDependency(
-                            ConverterUtils.toManagedDependency(dependency, globalExclusions, session));
-                }
+            ArtifactDescriptorResult descriptor = ConverterUtils.toArtifactDescriptor(session, model);
+
+            for (org.eclipse.aether.graph.Dependency managedDependency : descriptor.getManagedDependencies()) {
+                collectRequest.addManagedDependency(ConverterUtils.addExclusions(managedDependency, globalExclusions));
             }
 
-            for (org.apache.maven.model.Dependency dep : model.getDependencies()) {
-                Dependency dependency = new Dependency();
-                dependency.setArtifactId(dep.getArtifactId());
-                dependency.setClassifier(dep.getClassifier());
-                dependency.setGroupId(dep.getGroupId());
-                dependency.setScope(dep.getScope());
-                dependency.setType(dep.getType());
-                dependency.setVersion(dep.getVersion());
-                if (ids.contains(dependency.getVersionlessKey())) {
+            for (org.eclipse.aether.graph.Dependency dependency : descriptor.getDependencies()) {
+                String key = ConverterUtils.versionlessKey(dependency.getArtifact());
+                if (ids.contains(key)) {
                     project.log(
-                            "Ignoring dependency " + dependency.getVersionlessKey() + " from " + model.getId()
-                                    + ", already declared locally",
+                            "Ignoring dependency " + key + " from " + model.getId() + ", already declared locally",
                             Project.MSG_VERBOSE);
                     continue;
                 }
-                if (dep.getSystemPath() != null && !dep.getSystemPath().isEmpty()) {
-                    dependency.setSystemPath(task.getProject().resolveFile(dep.getSystemPath()));
-                }
-                for (org.apache.maven.model.Exclusion exc : dep.getExclusions()) {
-                    Exclusion exclusion = new Exclusion();
-                    exclusion.setGroupId(exc.getGroupId());
-                    exclusion.setArtifactId(exc.getArtifactId());
-                    exclusion.setClassifier("*");
-                    exclusion.setExtension("*");
-                    dependency.addExclusion(exclusion);
-                }
-                collectRequest.addDependency(ConverterUtils.toDependency(dependency, globalExclusions, session));
+                collectRequest.addDependency(ConverterUtils.addExclusions(dependency, globalExclusions));
             }
         }
 
         if (dependencies.getFile() != null) {
             List<Dependency> deps = readDependencies(dependencies.getFile());
             for (Dependency dependency : deps) {
-                if (ids.contains(dependency.getVersionlessKey())) {
+                String key = ConverterUtils.versionlessKey(dependency, session);
+                if (ids.contains(key)) {
                     project.log(
-                            "Ignoring dependency " + dependency.getVersionlessKey() + " from " + dependencies.getFile()
+                            "Ignoring dependency " + key + " from " + dependencies.getFile()
                                     + ", already declared locally",
                             Project.MSG_VERBOSE);
                     continue;
diff --git a/src/main/java/org/apache/maven/resolver/internal/ant/ConverterUtils.java b/src/main/java/org/apache/maven/resolver/internal/ant/ConverterUtils.java
index 8bf627d..265948b 100644
--- a/src/main/java/org/apache/maven/resolver/internal/ant/ConverterUtils.java
+++ b/src/main/java/org/apache/maven/resolver/internal/ant/ConverterUtils.java
@@ -26,6 +26,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
+import org.apache.maven.model.Model;
+import org.apache.maven.repository.internal.ArtifactDescriptorReaderDelegate;
 import org.apache.maven.resolver.internal.ant.types.Authentication;
 import org.apache.maven.resolver.internal.ant.types.Dependency;
 import org.apache.maven.resolver.internal.ant.types.Exclusion;
@@ -41,6 +43,8 @@ import org.eclipse.aether.artifact.ArtifactTypeRegistry;
 import org.eclipse.aether.artifact.DefaultArtifact;
 import org.eclipse.aether.artifact.DefaultArtifactType;
 import org.eclipse.aether.repository.RepositoryPolicy;
+import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
+import org.eclipse.aether.resolution.ArtifactDescriptorResult;
 import org.eclipse.aether.util.repository.AuthenticationBuilder;
 
 /**
@@ -48,7 +52,7 @@ import org.eclipse.aether.util.repository.AuthenticationBuilder;
  */
 class ConverterUtils {
 
-    private static org.eclipse.aether.artifact.Artifact toArtifact(Dependency dependency, ArtifactTypeRegistry types) {
+    static org.eclipse.aether.artifact.Artifact toArtifact(Dependency dependency, ArtifactTypeRegistry types) {
         ArtifactType type = types.get(dependency.getType());
         if (type == null) {
             type = new DefaultArtifactType(dependency.getType());
@@ -70,6 +74,78 @@ class ConverterUtils {
                 type);
     }
 
+    /**
+     * Converts a Maven {@link Model} into the artifact descriptor that Maven itself would derive from it.
+     * <p>
+     * The conversion is delegated to Maven's own {@link ArtifactDescriptorReaderDelegate}, the code that turns a
+     * model into resolver input during a Maven build, so that a POM contributes the same dependencies, managed
+     * dependencies and repositories here as it does there.
+     *
+     * @param session the repository system session supplying the artifact type registry
+     * @param model the effective model to convert
+     * @return the artifact descriptor derived from the model
+     */
+    public static ArtifactDescriptorResult toArtifactDescriptor(RepositorySystemSession session, Model model) {
+        org.eclipse.aether.artifact.Artifact pomArtifact =
+                new DefaultArtifact(model.getGroupId(), model.getArtifactId(), "pom", model.getVersion());
+        ArtifactDescriptorRequest request = new ArtifactDescriptorRequest();
+        request.setArtifact(pomArtifact);
+        ArtifactDescriptorResult result = new ArtifactDescriptorResult(request);
+        new ArtifactDescriptorReaderDelegate().populateResult(session, result, model);
+        return result;
+    }
+
+    /**
+     * Returns the {@code groupId:artifactId:extension[:classifier]} key of an artifact, used to detect that a POM
+     * dependency is already declared locally.
+     *
+     * @param artifact the artifact to key
+     * @return the versionless key of the artifact
+     */
+    public static String versionlessKey(org.eclipse.aether.artifact.Artifact artifact) {
+        StringBuilder key = new StringBuilder(128);
+        key.append(artifact.getGroupId())
+                .append(':')
+                .append(artifact.getArtifactId())
+                .append(':')
+                .append(artifact.getExtension());
+        if (!artifact.getClassifier().isEmpty()) {
+            key.append(':').append(artifact.getClassifier());
+        }
+        return key.toString();
+    }
+
+    /**
+     * Returns the versionless key of an Ant {@code <dependency>}, normalized the same way as
+     * {@link #versionlessKey(org.eclipse.aether.artifact.Artifact)} so that both can be compared.
+     *
+     * @param dependency the Ant dependency to key
+     * @param session the repository system session supplying the artifact type registry
+     * @return the versionless key of the dependency
+     */
+    public static String versionlessKey(Dependency dependency, RepositorySystemSession session) {
+        return versionlessKey(toArtifact(dependency, session.getArtifactTypeRegistry()));
+    }
+
+    /**
+     * Returns a copy of the dependency with the given exclusions added to the ones it already carries.
+     *
+     * @param dependency the dependency to extend
+     * @param exclusions the exclusions to add, may be empty
+     * @return the dependency with the merged exclusions
+     */
+    public static org.eclipse.aether.graph.Dependency addExclusions(
+            org.eclipse.aether.graph.Dependency dependency, Collection<Exclusion> exclusions) {
+        if (exclusions == null || exclusions.isEmpty()) {
+            return dependency;
+        }
+        Collection<org.eclipse.aether.graph.Exclusion> merged = new LinkedHashSet<>(dependency.getExclusions());
+        for (Exclusion exclusion : exclusions) {
+            merged.add(toExclusion(exclusion));
+        }
+        return dependency.setExclusions(merged);
+    }
+
     public static org.eclipse.aether.repository.Authentication toAuthentication(Authentication auth) {
         if (auth == null) {
             return null;
@@ -90,15 +166,6 @@ class ConverterUtils {
                 toExclusions(dependency.getExclusions(), exclusions));
     }
 
-    public static org.eclipse.aether.graph.Dependency toManagedDependency(
-            Dependency dependency, List<Exclusion> exclusions, RepositorySystemSession session) {
-        return new org.eclipse.aether.graph.Dependency(
-                toArtifact(dependency, session.getArtifactTypeRegistry()),
-                dependency.getScope(),
-                false,
-                toExclusions(dependency.getExclusions(), exclusions));
-    }
-
     /**
      * Converts the given ant repository type to an Aether repository instance with authentication and proxy filled in
      * via the sessions' selectors.