This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a commit to branch maven-3.10.x
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/maven-3.10.x by this push:
new c64fbe4aa7 Feat: Align CP ordering with Maven 4 (#12327)
c64fbe4aa7 is described below
commit c64fbe4aa7e348a30bfecf8c5118d6d399627301
Author: Tamas Cservenak <[email protected]>
AuthorDate: Fri Jun 19 13:57:26 2026 +0200
Feat: Align CP ordering with Maven 4 (#12327)
This PR aligns classpath ordering with Maven 4 (level order). All Maven 2/3
versions released so far has "pre-order" flattening (historical reasons, Maven
2 did it like that). Maven 3.10.0 switches to Resolver 2, where resolver
exposes flattening configuration too, and defaults to safer "level order",
preventing issues like described here https://arxiv.org/abs/2407.18760v3
For resolver configuration, see configuration key
`aether.system.dependencyVisitor` in
https://maven.apache.org/resolver/configuration.html If _full Maven 3
behaviour needed_, user can simply set
`-Daether.system.dependencyVisitor=preOrder` and it restores CP ordering to
that used in Maven 3.9 and older.
This PR changes:
* remove scattered "flattening" happening in multiple spots in Maven, it is
(and in fact was, but result was thrown away) fully delegating to Resolver.
* simplify spots that was doing repeated deprecated pre-order flattening
(which already happened in plugin dependencies resolver)
---
.../plugin/internal/DefaultMavenPluginManager.java | 38 +++++++------------
.../DefaultPluginDependenciesResolver.java | 43 ++++++++++++++++++----
.../internal/PluginDependenciesResolver.java | 41 +++++++++++++++++++++
.../internal/BootstrapCoreExtensionManager.java | 22 +++++------
4 files changed, 101 insertions(+), 43 deletions(-)
diff --git
a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
index edd9bb129b..44aac42459 100644
---
a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
+++
b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
@@ -32,9 +32,7 @@
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -107,10 +105,10 @@
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.graph.DependencyFilter;
-import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.util.filter.AndDependencyFilter;
-import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
/**
* Provides basic services to manage Maven plugins and their mojos. This
component is kept general in its design such
@@ -389,17 +387,17 @@ private void createPluginRealm(
DependencyFilter dependencyFilter =
project.getExtensionDependencyFilter();
dependencyFilter = AndDependencyFilter.newInstance(dependencyFilter,
filter);
- DependencyNode root = pluginDependenciesResolver.resolve(
+ DependencyResult result =
pluginDependenciesResolver.resolvePluginAndFlatten(
plugin,
RepositoryUtils.toArtifact(pluginArtifact),
dependencyFilter,
project.getRemotePluginRepositories(),
repositorySession);
- PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
- root.accept(nlg);
-
- pluginArtifacts = toMavenArtifacts(root, nlg);
+ pluginArtifacts = result.getArtifactResults().stream()
+ .filter(ArtifactResult::isResolved)
+ .map(r -> RepositoryUtils.toArtifact(r.getArtifact()))
+ .collect(Collectors.toList());
pluginRealm = classRealmManager.createPluginRealm(
plugin, parent, null, foreignImports,
toAetherArtifacts(pluginArtifacts));
@@ -437,18 +435,6 @@ private List<org.eclipse.aether.artifact.Artifact>
toAetherArtifacts(final List<
return new ArrayList<>(RepositoryUtils.toArtifacts(pluginArtifacts));
}
- private List<Artifact> toMavenArtifacts(DependencyNode root,
PreorderNodeListGenerator nlg) {
- List<Artifact> artifacts = new ArrayList<>(nlg.getNodes().size());
- RepositoryUtils.toArtifacts(artifacts, Collections.singleton(root),
Collections.<String>emptyList(), null);
- for (Iterator<Artifact> it = artifacts.iterator(); it.hasNext(); ) {
- Artifact artifact = it.next();
- if (artifact.getFile() == null) {
- it.remove();
- }
- }
- return Collections.unmodifiableList(artifacts);
- }
-
private Map<String, ClassLoader> calcImports(MavenProject project,
ClassLoader parent, List<String> imports) {
Map<String, ClassLoader> foreignImports = new HashMap<>();
@@ -841,9 +827,11 @@ public ExtensionRealmCache.CacheRecord
setupExtensionsRealm(
private List<Artifact> resolveExtensionArtifacts(
Plugin extensionPlugin, List<RemoteRepository> repositories,
RepositorySystemSession session)
throws PluginResolutionException {
- DependencyNode root =
pluginDependenciesResolver.resolve(extensionPlugin, null, null, repositories,
session);
- PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
- root.accept(nlg);
- return toMavenArtifacts(root, nlg);
+ DependencyResult result =
+
pluginDependenciesResolver.resolvePluginAndFlatten(extensionPlugin, null, null,
repositories, session);
+ return result.getArtifactResults().stream()
+ .filter(ArtifactResult::isResolved)
+ .map(r -> RepositoryUtils.toArtifact(r.getArtifact()))
+ .collect(Collectors.toList());
}
}
diff --git
a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
index b2284661d6..ca7c1fcf08 100644
---
a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
+++
b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
@@ -57,6 +57,7 @@
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.DependencyRequest;
import org.eclipse.aether.resolution.DependencyResolutionException;
+import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.util.artifact.JavaScopes;
import org.eclipse.aether.util.filter.AndDependencyFilter;
import org.eclipse.aether.util.filter.ScopeDependencyFilter;
@@ -98,6 +99,7 @@ private Artifact toArtifact(Plugin plugin,
RepositorySystemSession session) {
session.getArtifactTypeRegistry().get("maven-plugin"));
}
+ @Override
public Artifact resolve(Plugin plugin, List<RemoteRepository>
repositories, RepositorySystemSession session)
throws PluginResolutionException {
RequestTrace trace = RequestTrace.newChild(null, plugin);
@@ -154,16 +156,33 @@ public Artifact resolve(Plugin plugin,
List<RemoteRepository> repositories, Repo
/**
* @since 3.3.0
+ * @deprecated Is unused since 3.10.0
*/
+ @Deprecated
public DependencyNode resolveCoreExtension(
Plugin plugin,
DependencyFilter dependencyFilter,
List<RemoteRepository> repositories,
RepositorySystemSession session)
throws PluginResolutionException {
+ return resolveInternal(plugin, null /* pluginArtifact */,
dependencyFilter, repositories, session)
+ .getRoot();
+ }
+
+ /**
+ * @since 3.10.0
+ */
+ @Override
+ public DependencyResult resolveCoreExtensionAndFlatten(
+ Plugin plugin,
+ DependencyFilter dependencyFilter,
+ List<RemoteRepository> repositories,
+ RepositorySystemSession session)
+ throws PluginResolutionException {
return resolveInternal(plugin, null /* pluginArtifact */,
dependencyFilter, repositories, session);
}
+ @Override
public DependencyNode resolve(
Plugin plugin,
Artifact pluginArtifact,
@@ -171,10 +190,22 @@ public DependencyNode resolve(
List<RemoteRepository> repositories,
RepositorySystemSession session)
throws PluginResolutionException {
+ return resolveInternal(plugin, pluginArtifact, dependencyFilter,
repositories, session)
+ .getRoot();
+ }
+
+ @Override
+ public DependencyResult resolvePluginAndFlatten(
+ Plugin plugin,
+ Artifact pluginArtifact,
+ DependencyFilter dependencyFilter,
+ List<RemoteRepository> repositories,
+ RepositorySystemSession session)
+ throws PluginResolutionException {
return resolveInternal(plugin, pluginArtifact, dependencyFilter,
repositories, session);
}
- private DependencyNode resolveInternal(
+ private DependencyResult resolveInternal(
Plugin plugin,
Artifact pluginArtifact,
DependencyFilter dependencyFilter,
@@ -190,8 +221,6 @@ private DependencyNode resolveInternal(
DependencyFilter collectionFilter = new
ScopeDependencyFilter("provided", "test");
DependencyFilter resolutionFilter =
AndDependencyFilter.newInstance(collectionFilter, dependencyFilter);
- DependencyNode node;
-
try {
DependencySelector selector =
AndDependencySelector.newInstance(session.getDependencySelector(), new
WagonExcluder());
@@ -221,14 +250,16 @@ private DependencyNode resolveInternal(
request.setTrace(RequestTrace.newChild(trace, depRequest));
- node = repoSystem.collectDependencies(pluginSession,
request).getRoot();
+ DependencyNode node =
+ repoSystem.collectDependencies(pluginSession,
request).getRoot();
if (logger.isDebugEnabled()) {
node.accept(new GraphLogger());
}
depRequest.setRoot(node);
- repoSystem.resolveDependencies(session, depRequest);
+ return repoSystem.resolveDependencies(session, depRequest);
+
} catch (DependencyCollectionException e) {
throw new PluginResolutionException(
plugin, e.getResult().getExceptions(),
logger.isDebugEnabled() ? e : null);
@@ -241,8 +272,6 @@ private DependencyNode resolveInternal(
.collect(Collectors.toList());
throw new PluginResolutionException(plugin, exceptions,
logger.isDebugEnabled() ? e : null);
}
-
- return node;
}
// Keep this class in sync with
org.apache.maven.project.DefaultProjectDependenciesResolver.GraphLogger
diff --git
a/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginDependenciesResolver.java
b/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginDependenciesResolver.java
index 0f865df277..957365a293 100644
---
a/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginDependenciesResolver.java
+++
b/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginDependenciesResolver.java
@@ -27,6 +27,7 @@
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.DependencyResult;
/**
* Assists in resolving the dependencies of a plugin.
<strong>Warning:</strong> This is an internal utility interface
@@ -61,7 +62,9 @@ Artifact resolve(Plugin plugin, List<RemoteRepository>
repositories, RepositoryS
* @param session The repository session to use for resolving the plugin
artifacts, must not be {@code null}.
* @return The dependency tree denoting the resolved plugin class path,
never {@code null}.
* @throws PluginResolutionException If any dependency could not be
resolved.
+ * @deprecated This method should be avoided, as it requires manual
flattening; use {@link #resolvePluginAndFlatten(Plugin, Artifact,
DependencyFilter, List, RepositorySystemSession)} instead to let Resolver
handle it.
*/
+ @Deprecated
DependencyNode resolve(
Plugin plugin,
Artifact pluginArtifact,
@@ -69,4 +72,42 @@ DependencyNode resolve(
List<RemoteRepository> repositories,
RepositorySystemSession session)
throws PluginResolutionException;
+
+ /**
+ * Resolves the runtime dependencies of the specified core extension (as
{@link Plugin} as GAV carrier).
+ *
+ * @param plugin The plugin for which to resolve the dependencies, must
not be {@code null}.
+ * @param dependencyFilter A filter to exclude artifacts from resolution
(but not collection), may be {@code null}.
+ * @param repositories The plugin repositories to use for resolving the
plugin artifacts, must not be {@code null}.
+ * @param session The repository session to use for resolving the plugin
artifacts, must not be {@code null}.
+ * @return The dependency resolution result having the resolved extension
class path but also the tree, never {@code null}.
+ * @throws PluginResolutionException If any dependency could not be
resolved.
+ * @since 3.10.0
+ */
+ DependencyResult resolveCoreExtensionAndFlatten(
+ Plugin plugin,
+ DependencyFilter dependencyFilter,
+ List<RemoteRepository> repositories,
+ RepositorySystemSession session)
+ throws PluginResolutionException;
+
+ /**
+ * Resolves the runtime dependencies of the specified plugin.
+ *
+ * @param plugin The plugin for which to resolve the dependencies, must
not be {@code null}.
+ * @param pluginArtifact The plugin's main artifact, may be {@code null}.
+ * @param dependencyFilter A filter to exclude artifacts from resolution
(but not collection), may be {@code null}.
+ * @param repositories The plugin repositories to use for resolving the
plugin artifacts, must not be {@code null}.
+ * @param session The repository session to use for resolving the plugin
artifacts, must not be {@code null}.
+ * @return The dependency resolution result having the resolved plugin
class path but also the tree, never {@code null}.
+ * @throws PluginResolutionException If any dependency could not be
resolved.
+ * @since 3.10.0
+ */
+ DependencyResult resolvePluginAndFlatten(
+ Plugin plugin,
+ Artifact pluginArtifact,
+ DependencyFilter dependencyFilter,
+ List<RemoteRepository> repositories,
+ RepositorySystemSession session)
+ throws PluginResolutionException;
}
diff --git
a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
index c11e6ce893..53e20302d8 100644
---
a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
+++
b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
@@ -26,6 +26,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import org.apache.maven.RepositoryUtils;
import org.apache.maven.cli.internal.extension.model.CoreExtension;
@@ -35,7 +36,7 @@
import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.PluginResolutionException;
-import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
+import org.apache.maven.plugin.internal.PluginDependenciesResolver;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.ClassWorld;
@@ -48,10 +49,10 @@
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.graph.DependencyFilter;
-import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.ArtifactResult;
+import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
-import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator;
/**
* BootstrapCoreExtensionManager
@@ -64,7 +65,7 @@ public class BootstrapCoreExtensionManager {
private final Logger log;
- private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
+ private final PluginDependenciesResolver pluginDependenciesResolver;
private final DefaultRepositorySystemSessionFactory
repositorySystemSessionFactory;
@@ -77,7 +78,7 @@ public class BootstrapCoreExtensionManager {
@Inject
public BootstrapCoreExtensionManager(
Logger log,
- DefaultPluginDependenciesResolver pluginDependenciesResolver,
+ PluginDependenciesResolver pluginDependenciesResolver,
DefaultRepositorySystemSessionFactory
repositorySystemSessionFactory,
CoreExports coreExports,
PlexusContainer container) {
@@ -174,13 +175,12 @@ private List<Artifact> resolveExtension(
plugin.setArtifactId(interpolator.interpolate(extension.getArtifactId()));
plugin.setVersion(interpolator.interpolate(extension.getVersion()));
- DependencyNode root =
pluginDependenciesResolver.resolveCoreExtension(
+ DependencyResult result =
pluginDependenciesResolver.resolveCoreExtensionAndFlatten(
plugin, dependencyFilter, repositories, repoSession);
- PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
- root.accept(nlg);
- List<Artifact> artifacts = nlg.getArtifacts(false);
-
- return artifacts;
+ return result.getArtifactResults().stream()
+ .filter(ArtifactResult::isResolved)
+ .map(ArtifactResult::getArtifact)
+ .collect(Collectors.toList());
} catch (PluginResolutionException | InterpolationException e) {
throw new ExtensionResolutionException(extension, e);
}