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"));
+        }
+    }
 }

Reply via email to