From 2b726e2c2b83fc980a7ded078f9db22772c3c78c Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 10 Jan 2025 20:00:06 +0100 Subject: [PATCH 1/2] [MNG-8485] Improve VersionRangeResolverResult --- .../java/org/apache/maven/api/Session.java | 17 ++++++++ .../services/VersionRangeResolverResult.java | 39 ++++++++++++++++++- .../maven/internal/impl/AbstractSession.java | 8 ++++ .../impl/resolver/DefaultModelResolver.java | 7 ++-- 4 files changed, 66 insertions(+), 5 deletions(-) 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 681ebb504042..39ae21a0cc15 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 @@ -728,6 +728,23 @@ Map> resolveDependencies( List resolveVersionRange(@Nonnull ArtifactCoordinates artifact, List repositories) throws VersionResolverException; + /** + * Resolves the highest available version of a version range. + * The returned version is only dependent on the configured repositories and their contents. + * The supplied request may also refer to a single concrete version rather than a version range. + * In this case though, the result contains simply the (parsed) input version, regardless of the + * repositories and their contents. + * + * @param artifact the artifact for which to resolve the versions + * @param repositories the repositories to use, or the session repositories if {@code null} + * @return the highest resolved {@code Version}. + * @throws org.apache.maven.api.services.VersionRangeResolverException if the resolution failed + * @see org.apache.maven.api.services.VersionRangeResolver#resolve(Session, ArtifactCoordinates) (String) + */ + @Nonnull + Optional resolveHighestVersion(@Nonnull ArtifactCoordinates artifact, List repositories) + throws VersionResolverException; + /** * Parses the specified version string, for example "1.0". *

diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverResult.java index 3d2f038f1408..e0a5f8348593 100644 --- a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverResult.java +++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionRangeResolverResult.java @@ -27,32 +27,67 @@ import org.apache.maven.api.annotations.Nonnull; /** + * Represents the result of a version range resolution request. This interface provides access to + * information about resolved versions that match a version range constraint, including any exceptions + * that occurred during resolution, the available versions, and their source repositories. + * + *

The versions returned by this interface are guaranteed to be in ascending order.

* * @since 4.0.0 */ @Experimental public interface VersionRangeResolverResult { + /** + * Gets the exceptions that occurred while resolving the version range. + * + * @return The list of exceptions that occurred during resolution, never {@code null} + */ @Nonnull List getExceptions(); + /** + * Gets the versions (in ascending order) that matched the requested range. + * + * @return The list of matching versions, never {@code null}. An empty list indicates + * no versions matched the requested range. + */ @Nonnull List getVersions(); + /** + * Gets the lowest version matching the requested range. + * + * @return An Optional containing the lowest matching version, or empty Optional if no versions + * matched the requested range + */ @Nonnull - default Optional getLowerVersion() { + default Optional getLowestVersion() { return getVersions().isEmpty() ? Optional.empty() : Optional.of(getVersions().get(0)); } + /** + * Gets the highest version matching the requested range. + * + * @return An Optional containing the highest matching version, or empty Optional if no versions + * matched the requested range + */ @Nonnull - default Optional getHigherVersion() { + default Optional getHighestVersion() { return getVersions().isEmpty() ? Optional.empty() : Optional.of(getVersions().get(getVersions().size() - 1)); } + /** + * Gets the repository from which the specified version was resolved. + * + * @param version The version whose source repository should be retrieved, must not be {@code null} + * @return An Optional containing the repository from which the version was resolved, + * or empty Optional if the repository is unknown + */ @Nonnull Optional getRepository(Version version); } diff --git a/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java index d5cefa8327a2..75d32bc04be8 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/AbstractSession.java @@ -863,6 +863,14 @@ public List resolveVersionRange(ArtifactCoordinates artifact, List resolveHighestVersion(ArtifactCoordinates artifact, List repositories) + throws VersionResolverException { + return getService(VersionRangeResolver.class) + .resolve(this, artifact, repositories) + .getHighestVersion(); + } + @Override public Type requireType(String id) { return getService(TypeRegistry.class).require(id); diff --git a/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java b/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java index 9ea3d3f63bdc..197329c56a1b 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java @@ -24,6 +24,7 @@ import java.nio.file.Path; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -135,8 +136,8 @@ public ModelSource resolveModel( artifactId, version); } - List versions = session.resolveVersionRange(coords, repositories); - if (versions.isEmpty()) { + Optional result = session.resolveHighestVersion(coords, repositories); + if (result.isEmpty()) { throw new ModelResolverException( "No versions matched the requested " + (type != null ? type + " " : "") + "version range '" + version + "'", @@ -144,7 +145,7 @@ public ModelSource resolveModel( artifactId, version); } - String newVersion = versions.get(versions.size() - 1).asString(); + String newVersion = result.get().asString(); if (!version.equals(newVersion)) { resolvedVersion.accept(newVersion); } From 904f5e850aff182ba729b1199cf7efa13b6f09da Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 10 Jan 2025 22:15:57 +0100 Subject: [PATCH 2/2] Use orElseThrow --- .../impl/resolver/DefaultModelResolver.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java b/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java index 197329c56a1b..1b807a09250f 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/internal/impl/resolver/DefaultModelResolver.java @@ -24,7 +24,6 @@ import java.nio.file.Path; import java.util.List; import java.util.Objects; -import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -33,7 +32,6 @@ import org.apache.maven.api.DownloadedArtifact; import org.apache.maven.api.RemoteRepository; import org.apache.maven.api.Session; -import org.apache.maven.api.Version; import org.apache.maven.api.annotations.Nonnull; import org.apache.maven.api.annotations.Nullable; import org.apache.maven.api.di.Named; @@ -136,16 +134,14 @@ public ModelSource resolveModel( artifactId, version); } - Optional result = session.resolveHighestVersion(coords, repositories); - if (result.isEmpty()) { - throw new ModelResolverException( - "No versions matched the requested " + (type != null ? type + " " : "") + "version range '" - + version + "'", - groupId, - artifactId, - version); - } - String newVersion = result.get().asString(); + String newVersion = session.resolveHighestVersion(coords, repositories) + .orElseThrow(() -> new ModelResolverException( + "No versions matched the requested " + (type != null ? type + " " : "") + "version range '" + + version + "'", + groupId, + artifactId, + version)) + .asString(); if (!version.equals(newVersion)) { resolvedVersion.accept(newVersion); }