This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a commit to branch maven-resolver-1.9.x
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
The following commit(s) were added to refs/heads/maven-resolver-1.9.x by this
push:
new 8a7f4a314 [1.9.x] Bug: GH-1703 Locally cached artifacts defy RRF
(#1708)
8a7f4a314 is described below
commit 8a7f4a314c5ebcf757d81c2bbeb9940c1524fb24
Author: Tamas Cservenak <[email protected]>
AuthorDate: Thu Dec 11 16:00:09 2025 +0100
[1.9.x] Bug: GH-1703 Locally cached artifacts defy RRF (#1708)
Within ArtifactResolver there was a subtle bug,
caused by unintentional lazy evaluation of
logical OR. In case filter is present, it is
ONLY and only LRM availability that drives the logic.
---
.../internal/impl/DefaultArtifactResolver.java | 19 +++-
.../internal/impl/DefaultArtifactResolverTest.java | 115 ++++++++++++++++++++-
2 files changed, 130 insertions(+), 4 deletions(-)
diff --git
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java
index 044302461..12e86cb92 100644
---
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java
+++
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultArtifactResolver.java
@@ -362,9 +362,10 @@ public class DefaultArtifactResolver implements
ArtifactResolver, Service {
new LocalArtifactRequest(
artifact, filteredRemoteRepositories,
request.getRequestContext()));
result.setLocalArtifactResult(local);
- boolean found = (filter != null && local.isAvailable()) ||
isLocallyInstalled(local, versionResult);
- // with filtering it is availability that drives logic
- // without filtering it is simply presence of file that
drives the logic
+ boolean found = (filter != null && local.isAvailable())
+ || (filter == null && isLocallyInstalled(local,
versionResult));
+ // with filtering: availability drives the logic
+ // without filtering: simply presence of file drives the
logic
// "interop" logic with simple LRM leads to RRF breakage:
hence is ignored when filtering in effect
if (found) {
if (local.getRepository() != null) {
@@ -480,6 +481,18 @@ public class DefaultArtifactResolver implements
ArtifactResolver, Service {
}
}
+ /**
+ * This is the method that checks local artifact result if no RRF being
used. Unlike with RRF, where only
+ * {@link LocalArtifactResult#isAvailable()} is checked, here we perform
multiple checks:
+ * <ul>
+ * <li>if {@link LocalArtifactResult#isAvailable()} is {@code true},
return {@code true}</li>
+ * <li>if {@link LocalArtifactResult#getRepository()} is instance of
{@link LocalRepository}, return {@code true}</li>
+ * <li>if {@link LocalArtifactResult#getRepository()} is {@code null}
and request had zero remote repositories set, return {@code true}</li>
+ * </ul>
+ * Note: the third check is interfering with RRF, as RRF may make list of
remote repositories empty, that was
+ * originally non-empty, by eliminating remote repositories to consider.
+ * Hence, we may use this method ONLY if RRF is inactive.
+ */
private boolean isLocallyInstalled(LocalArtifactResult lar, VersionResult
vr) {
if (lar.isAvailable()) {
return true;
diff --git
a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java
b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java
index 024d6bf0e..1159a6fa3 100644
---
a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java
+++
b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java
@@ -34,6 +34,7 @@ import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.ArtifactProperties;
import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.impl.RemoteRepositoryFilterManager;
import org.eclipse.aether.impl.UpdateCheckManager;
import org.eclipse.aether.impl.VersionResolver;
import
org.eclipse.aether.internal.impl.filter.DefaultRemoteRepositoryFilterManager;
@@ -63,6 +64,7 @@ import
org.eclipse.aether.resolution.VersionResolutionException;
import org.eclipse.aether.resolution.VersionResult;
import org.eclipse.aether.spi.connector.ArtifactDownload;
import org.eclipse.aether.spi.connector.MetadataDownload;
+import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilter;
import org.eclipse.aether.spi.connector.filter.RemoteRepositoryFilterSource;
import org.eclipse.aether.transfer.ArtifactNotFoundException;
import org.eclipse.aether.transfer.ArtifactTransferException;
@@ -96,7 +98,7 @@ public class DefaultArtifactResolverTest {
private HashMap<String, RemoteRepositoryFilterSource>
remoteRepositoryFilterSources;
- private DefaultRemoteRepositoryFilterManager remoteRepositoryFilterManager;
+ private RemoteRepositoryFilterManager remoteRepositoryFilterManager;
@Before
public void setup() {
@@ -886,4 +888,115 @@ public class DefaultArtifactResolverTest {
resolved = resolved.setFile(null);
assertEquals(artifact, resolved);
}
+
+ @Test
+ public void testCachedButFilteredOut() {
+ remoteRepositoryFilterManager = new RemoteRepositoryFilterManager() {
+ @Override
+ public RemoteRepositoryFilter
getRemoteRepositoryFilter(RepositorySystemSession session) {
+ return new RemoteRepositoryFilter() {
+ @Override
+ public Result acceptArtifact(RemoteRepository
remoteRepository, Artifact artifact) {
+ return new Result() {
+ @Override
+ public boolean isAccepted() {
+ return false;
+ }
+
+ @Override
+ public String reasoning() {
+ return "REFUSED";
+ }
+ };
+ }
+
+ @Override
+ public Result acceptMetadata(RemoteRepository
remoteRepository, Metadata metadata) {
+ return new Result() {
+ @Override
+ public boolean isAccepted() {
+ return true;
+ }
+
+ @Override
+ public String reasoning() {
+ return "OK";
+ }
+ };
+ }
+ };
+ }
+ };
+ session.setLocalRepositoryManager(new LocalRepositoryManager() {
+ public LocalRepository getRepository() {
+ return null;
+ }
+
+ public String getPathForRemoteMetadata(Metadata metadata,
RemoteRepository repository, String context) {
+ return null;
+ }
+
+ public String getPathForRemoteArtifact(Artifact artifact,
RemoteRepository repository, String context) {
+ return null;
+ }
+
+ public String getPathForLocalMetadata(Metadata metadata) {
+ return null;
+ }
+
+ public String getPathForLocalArtifact(Artifact artifact) {
+ return null;
+ }
+
+ public LocalArtifactResult find(RepositorySystemSession session,
LocalArtifactRequest request) {
+ LocalArtifactResult result = new LocalArtifactResult(request);
+ result.setAvailable(false);
+ try {
+ result.setFile(TestFileUtils.createTempFile(""));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ public void add(RepositorySystemSession session,
LocalArtifactRegistration request) {}
+
+ public LocalMetadataResult find(RepositorySystemSession session,
LocalMetadataRequest request) {
+ LocalMetadataResult result = new LocalMetadataResult(request);
+ try {
+ result.setFile(TestFileUtils.createTempFile(""));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ public void add(RepositorySystemSession session,
LocalMetadataRegistration request) {}
+ });
+
+ // rebuild resolver with our filter
+ resolver = new DefaultArtifactResolver();
+ resolver.setFileProcessor(new TestFileProcessor());
+ resolver.setRepositoryEventDispatcher(new
StubRepositoryEventDispatcher());
+ resolver.setVersionResolver(new StubVersionResolver());
+ resolver.setUpdateCheckManager(new StaticUpdateCheckManager(false));
+ resolver.setRepositoryConnectorProvider(repositoryConnectorProvider);
+ resolver.setRemoteRepositoryManager(new StubRemoteRepositoryManager());
+ resolver.setSyncContextFactory(new StubSyncContextFactory());
+ resolver.setOfflineController(new DefaultOfflineController());
+ resolver.setArtifactResolverPostProcessors(Collections.emptyMap());
+
resolver.setRemoteRepositoryFilterManager(remoteRepositoryFilterManager);
+
+ ArtifactRequest request = new ArtifactRequest(artifact, null, "");
+ request.addRepository(new RemoteRepository.Builder("id", "default",
"file:///").build());
+
+ // resolver should throw
+ try {
+ resolver.resolveArtifact(session, request);
+ fail("Should throw ArtifactResolutionException");
+ } catch (ArtifactResolutionException ex) {
+ // message should contain present=true, available=false, filter
message
+ assertTrue(ex.getMessage().contains("gid:aid:ext:ver (present, but
unavailable): REFUSED"));
+ }
+ }
}