Issue
I am currently working on a project that has a built-in library loader for maven dependencies.
This is my current code:
public class ResolverTest {
private static final File LOCAL_REPO_DIR = new File("localRepo");
public static void main(String[] args) throws MalformedURLException, DependencyResolutionException {
downloadLibraries(
Arrays.asList(
"https://repo1.maven.org/maven2/",
"https://repository.apache.org/content/repositories/snapshots/"
),
List.of("commons-io:commons-io:2.12.0-SNAPSHOT")
);
}
public static List<URL> downloadLibraries(List<String> repositories, List<String> libraries) throws DependencyResolutionException, MalformedURLException {
// setup connection
var locator = MavenRepositorySystemUtils.newServiceLocator();
locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
var repoSystem = locator.getService(RepositorySystem.class);
var session = MavenRepositorySystemUtils.newSession();
session.setChecksumPolicy(RepositoryPolicy.CHECKSUM_POLICY_FAIL);
session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_NEVER);
session.setLocalRepositoryManager(repoSystem.newLocalRepositoryManager(session, new LocalRepository(LOCAL_REPO_DIR)));
session.setTransferListener(new LoggingTransferListener());
session.setReadOnly();
List<RemoteRepository> remoteRepos = new ArrayList<>();
var repoIdx = 0;
for (var repoUrl : repositories) {
remoteRepos.add(new RemoteRepository.Builder(String.valueOf(repoIdx), "default", repoUrl).build());
repoIdx++;
}
remoteRepos = repoSystem.newResolutionRepositories(session, remoteRepos);
// download libraries
var request = new DependencyRequest(
new CollectRequest(
(Dependency) null,
libraries.stream().map(library ->
new Dependency(new DefaultArtifact(library), null)
).toList(),
remoteRepos
),
null
);
var results = repoSystem.resolveDependencies(session, request).getArtifactResults();
var urls = new ArrayList<URL>();
for (var result : results) {
urls.add(result.getArtifact().getFile().toURI().toURL());
}
return urls;
}
private static class LoggingTransferListener extends AbstractTransferListener {
@Override
public void transferInitiated(TransferEvent event) {
System.out.println("Init transfer " + event.getResource().getRepositoryUrl() + event.getResource().getResourceName());
}
}
}
implementation("org.apache.maven:maven-resolver-provider:3.8.6")
implementation("org.apache.maven.resolver:maven-resolver-connector-basic:1.7.3")
implementation("org.apache.maven.resolver:maven-resolver-transport-http:1.8.2")
The issue I'm experiencing is that every time the program is restarted and the library loader is called again, the resolver tries to download the maven-metadata.xml
file of the dependency from all repositories that didn't have it in the previous attempt.
This only seems to happen with snapshot dependencies.
In the example above I'm also using RepositoryPolicy.UPDATE_POLICY_NEVER
. If it is set to RepositoryPolicy.UPDATE_POLICY_ALWAYS
, the resolver pulls the metadata from all repositories (like it should).
So why is it still pulling from the other repos, even if UPDATE_POLICY_NEVER
is set?
Setting the session to offline mode (session.setOffline(true);
) also doesn't work: The maven resolver throws a DependencyResolutionException: org.eclipse.aether.resolution.DependencyResolutionException: Cannot access central (https://repo.maven.apache.org/maven2) in offline mode and the artifact (path to artifact) has not been downloaded from it before.
(The dependency is in my local repo, but wasn't downloaded from central)
Solution
Well...
// this one prevents maven from downloading metadata.xml
// if I understand properly it tries to find maven-metadata-0.xml
// in local repository and in case of failure tries remote repositories
session.setResolutionErrorPolicy(new SimpleResolutionErrorPolicy(true, false));
// this one prevents maven from creating _remote.repositories files
// in local repository, yours: in my local repo, but wasn't downloaded from central
session.setLocalRepositoryManager(repoSystem.newLocalRepositoryManager(session, new LocalRepository(LOCAL_REPO_DIR, "simple")));
Answered By - Andrey B. Panfilov
Answer Checked By - Pedro (JavaFixing Volunteer)