【问题标题】:Download artifact from Maven repository in Java program在 Java 程序中从 Maven 存储库下载工件
【发布时间】:2018-07-10 07:14:16
【问题描述】:

我需要编写从给定 Maven 存储库下载给定工件 (GAV) 的 Java 代码。过去我使用的是 Nexus 2 的 REST 接口(这很简单),但我希望使用独立于存储库(Nexus 2、Nexus 3、Artifactory)的东西。

Fetching Maven artifacts programmatically 中提出了类似的问题,但主要答案来自 2014 年,并建议使用自 2014 年以来未更新的库。

【问题讨论】:

  • 您是否尝试过描述中强调的问题的解决方案?
  • @Manmohan_singh 不,我不想使用未经测试的旧库。

标签: java maven nexus artifactory


【解决方案1】:

使用 Aether(版本 1.1.0)可以做以下事情:

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.eclipse.aether.DefaultRepositorySystemSession;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
import org.eclipse.aether.impl.DefaultServiceLocator;
import org.eclipse.aether.repository.LocalRepository;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.resolution.ArtifactRequest;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
import org.eclipse.aether.spi.connector.transport.TransporterFactory;
import org.eclipse.aether.transport.file.FileTransporterFactory;
import org.eclipse.aether.transport.http.HttpTransporterFactory;


public class ArtifactDownload
{

  private static RepositorySystem newRepositorySystem()
  {
    DefaultServiceLocator locator = MavenRepositorySystemUtils
        .newServiceLocator();
    locator.addService(RepositoryConnectorFactory.class,
        BasicRepositoryConnectorFactory.class);
    locator.addService(TransporterFactory.class, FileTransporterFactory.class);
    locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
    return locator.getService(RepositorySystem.class);

  }

  private static RepositorySystemSession newSession(RepositorySystem system,
      File localRepository)
  {
    DefaultRepositorySystemSession session = MavenRepositorySystemUtils
        .newSession();
    LocalRepository localRepo = new LocalRepository(localRepository.toString());
    session.setLocalRepositoryManager(system.newLocalRepositoryManager(session,
        localRepo));
    return session;
  }


  public static File getArtifactByAether(String groupId, String artifactId,
      String version, String classifier, String packaging, File localRepository)
      throws IOException
  {
    RepositorySystem repositorySystem = newRepositorySystem();
    RepositorySystemSession session = newSession(repositorySystem,
        localRepository);

    Artifact artifact = new DefaultArtifact(groupId, artifactId, classifier,
        packaging, version);
    ArtifactRequest artifactRequest = new ArtifactRequest();
    artifactRequest.setArtifact(artifact);

    List<RemoteRepository> repositories = new ArrayList<>();

    RemoteRepository remoteRepository = new RemoteRepository.Builder("public",
        "default", "http://somerepo").build();

    repositories.add(remoteRepository);

    artifactRequest.setRepositories(repositories);
    File result;

    try
    {
      ArtifactResult artifactResult = repositorySystem.resolveArtifact(session,
          artifactRequest);
      artifact = artifactResult.getArtifact();
      if (artifact != null)
      {
        result = artifact.getFile();
      }
      else
      {
        result = null;
      }
    }
    catch (ArtifactResolutionException e)
    {
      throw new IOException("Artefakt " + groupId + ":" + artifactId + ":"
          + version + " konnte nicht heruntergeladen werden.");
    }

    return result;

  }
}

使用以下工件

    <dependency>
      <groupId>org.eclipse.aether</groupId>
      <artifactId>aether-api</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.aether</groupId>
      <artifactId>aether-spi</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.aether</groupId>
      <artifactId>aether-impl</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.aether</groupId>
      <artifactId>aether-connector-basic</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.aether</groupId>
      <artifactId>aether-transport-file</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.eclipse.aether</groupId>
      <artifactId>aether-transport-http</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-aether-provider</artifactId>
      <version>${mavenVersion}</version>
    </dependency>

<aetherVersion>1.1.0</aetherVersion>
<mavenVersion>3.3.3</mavenVersion>

【讨论】:

  • 有关于这个以太的文档吗?这篇文章是我发现的唯一一个类似于文档的东西?
  • 我知道它有点过时了,但你试过用通配符吗?我正在努力下载相同 GAV 下的所有工件,只有不同的分类器,但得到 ArtifactResolutionException。我正在使用 https://repo1.maven.org/maven2 并将其作为工件实例 Artifact artifact = new DefaultArtifact( "args4j:args4j:jar:*:2.33" ); 传递,这将针对 repo1.maven.org/maven2/args4j/args4j/2.33
  • 我认为通配符不起作用。相反,您可能需要使用一些 Aether 函数来解析给定坐标的工件列表。或者您可以使用 REST 来计算列表。
【解决方案2】:

我最近发现自己需要从 Maven 存储库下载文件。我在https://github.com/shrinkwrap/resolver 库之后偶然发现(https://www.hascode.com/2017/09/downloading-maven-artifacts-from-a-pom-file-programmatically-with-eclipse-aether/#comment-5602),它比 Eclipse Aether 项目更容易使用。

String artifactoryUrl = "https://your-repo:port/repository";
String[] requiredTypes = new String[] { "zip", "xml" };

for (String requiredType : requiredTypes) {
    MavenResolvedArtifact[] result = Maven.configureResolver()
            .withMavenCentralRepo(false)
            .withRemoteRepo("default", artifactoryUrl, "default")
            .useLegacyLocalRepo(true) // You can also set to ignore origin of artifacts present in local repository via useLegacyLocalRepo(true) method.
            .resolve(
                    group + ":" +
                    id + ":" +
                    requiredType + ":" +
                    version
            )
            .withTransitivity()
            .asResolvedArtifact();

    for (MavenResolvedArtifact mavenResolvedArtifact : result) {
        System.out.println(mavenResolvedArtifact);
        System.out.println(mavenResolvedArtifact.asFile().getAbsolutePath());
    }
 }

【讨论】:

    【解决方案3】:

    您正在描述maven-dependency-plugin (get goal)的功能

    因此,在 maven 插件的上下文中,Java 代码完全符合您的要求。

    我愿意

    • github获取get插件的源代码
    • 删除所有maven插件的东西(@Component依赖注入,参数)
    • 在需要的地方集成它的要点(并添加对所需内部 maven 库的依赖项)

    【讨论】:

      【解决方案4】:

      您可以使用 aether API 下载 maven 工件,该 API 将下载给定 POM.xml 文件中的 jars

      import java.io.File;
      import java.lang.reflect.Method;
      import java.net.URL;
      import java.net.URLClassLoader;
      import java.nio.file.Paths;
      import java.util.Arrays;
      import java.util.List;
      import org.apache.maven.model.Dependency;
      import org.apache.maven.model.Model;
      import org.apache.maven.model.building.DefaultModelBuilderFactory;
      import org.apache.maven.model.building.DefaultModelBuildingRequest;
      import org.apache.maven.model.building.ModelBuilder;
      import org.apache.maven.model.building.ModelBuildingResult;
      import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
      import org.eclipse.aether.DefaultRepositorySystemSession;
      import org.eclipse.aether.RepositorySystem;
      import org.eclipse.aether.RepositorySystemSession;
      import org.eclipse.aether.artifact.Artifact;
      import org.eclipse.aether.artifact.DefaultArtifact;
      import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory;
      import org.eclipse.aether.impl.DefaultServiceLocator;
      import org.eclipse.aether.repository.LocalRepository;
      import org.eclipse.aether.repository.Proxy;
      import org.eclipse.aether.repository.RemoteRepository;
      import org.eclipse.aether.repository.RemoteRepository.Builder;
      import org.eclipse.aether.resolution.ArtifactRequest;
      import org.eclipse.aether.resolution.ArtifactResolutionException;
      import org.eclipse.aether.resolution.ArtifactResult;
      import org.eclipse.aether.spi.connector.RepositoryConnectorFactory;
      import org.eclipse.aether.spi.connector.transport.TransporterFactory;
      import org.eclipse.aether.transport.file.FileTransporterFactory;
      import org.eclipse.aether.transport.http.HttpTransporterFactory;
      import org.eclipse.aether.util.repository.DefaultProxySelector;
      
      public class DownloadingArtifactsByPomExample {
      
      public static final String TARGET_LOCAL_REPOSITORY = "target/local-repository";
      
      public static void main(String[] args) throws Exception {
          File projectPomFile = new 
      File("C:\\Users\\user\\Desktop\\TEST_Aether\\test\\pom.xml");
      //Paths.get("","pom.xml").toAbsolutePath().toFile();
      
          System.out.printf("loading this sample project's Maven descriptor from %s\n", 
      projectPomFile);
          System.out.printf("local Maven repository set to %s\n",
                  Paths.get("", TARGET_LOCAL_REPOSITORY).toAbsolutePath());
      
          RepositorySystem repositorySystem = getRepositorySystem();
          RepositorySystemSession repositorySystemSession = 
      getRepositorySystemSession(repositorySystem);
      
          final DefaultModelBuildingRequest modelBuildingRequest = new 
      DefaultModelBuildingRequest()
                  .setPomFile(projectPomFile);
      
          ModelBuilder modelBuilder = new DefaultModelBuilderFactory().newInstance();
          ModelBuildingResult modelBuildingResult = 
      modelBuilder.build(modelBuildingRequest);
      
          Model model = modelBuildingResult.getEffectiveModel();
          System.out.printf("Maven model resolved: %s, parsing its dependencies..\n", 
      model);
          for (Dependency d : model.getDependencies()) {
              System.out.printf("processing dependency: %s\n", d);
              Artifact artifact = new DefaultArtifact(d.getGroupId(), d.getArtifactId(), 
      d.getType(), d.getVersion());
              ArtifactRequest artifactRequest = new ArtifactRequest();
              artifactRequest.setArtifact(artifact);
              artifactRequest.setRepositories(getRepositories(repositorySystem, 
      repositorySystemSession));
      
              try {
                  ArtifactResult artifactResult = 
      repositorySystem.resolveArtifact(repositorySystemSession,
                          artifactRequest);
                  artifact = artifactResult.getArtifact();
                  // to load the artifact in current classloader
                  ClassLoader classLoader = new URLClassLoader(new URL[] { 
      artifact.getFile().toURI().toURL() });
                  URL u = artifact.getFile().toURI().toURL();
                  URLClassLoader urlClassLoader = (URLClassLoader) 
      ClassLoader.getSystemClassLoader();
                  Class urlClass = URLClassLoader.class;
                  Method method = urlClass.getDeclaredMethod("addURL", new Class[] { 
      URL.class });
                  method.setAccessible(true);
                  method.invoke(urlClassLoader, new Object[] { u });
                  System.out.printf("artifact %s resolved to %s\n", artifact, 
      artifact.getFile());
              } catch (ArtifactResolutionException e) {
                  System.err.printf("error resolving artifact: %s\n", e.getMessage());
              }
      
          }
      
      }
      
      public static RepositorySystem getRepositorySystem() {
          DefaultServiceLocator serviceLocator = 
      MavenRepositorySystemUtils.newServiceLocator();
          serviceLocator.addService(RepositoryConnectorFactory.class, 
      BasicRepositoryConnectorFactory.class);
          serviceLocator.addService(TransporterFactory.class, 
      FileTransporterFactory.class);
          serviceLocator.addService(TransporterFactory.class, 
      HttpTransporterFactory.class);
      
          serviceLocator.setErrorHandler(new DefaultServiceLocator.ErrorHandler() {
              @Override
              public void serviceCreationFailed(Class<?> type, Class<?> impl, Throwable 
      exception) {
                  System.err.printf("error creating service: %s\n", 
      exception.getMessage());
                  exception.printStackTrace();
              }
          });
      
          return serviceLocator.getService(RepositorySystem.class);
      }
      
      public static DefaultRepositorySystemSession 
      getRepositorySystemSession(RepositorySystem system) {
          DefaultRepositorySystemSession repositorySystemSession = 
      MavenRepositorySystemUtils.newSession();
      
          LocalRepository localRepository = new LocalRepository(TARGET_LOCAL_REPOSITORY);
          repositorySystemSession
      
      .setLocalRepositoryManager(system.newLocalRepositoryManager(repositorySystemSession, 
      localRepository));
      
          repositorySystemSession.setRepositoryListener(new 
      ConsoleRepositoryEventListener());
          repositorySystemSession.setProxySelector(new DefaultProxySelector()
                  .add(new Proxy(Proxy.TYPE_HTTPS, "proxy.tcs.com", 8080), 
      Arrays.asList("localhost", "127.0.0.1")));
          return repositorySystemSession;
      }
      
      public static List<RemoteRepository> getRepositories(RepositorySystem system, 
      RepositorySystemSession session) {
          return Arrays.asList(getCentralMavenRepository());
      }
      
      private static RemoteRepository getCentralMavenRepository() {
          // In "http://central.maven.org we can provide local m2 repository location to
          // load the jars into local repo
          // like file://C:user/m2/repository
          RemoteRepository.Builder builder = new Builder("central", "default", " 
         http://central.maven.org/maven2/");
          // for proxy
          builder.setProxy(new Proxy("type", "host", 8080));// port 8080
          RemoteRepository central = builder.build();
          return central;
      }
      
      }
      

      import org.eclipse.aether.AbstractRepositoryListener;
      import org.eclipse.aether.RepositoryEvent;
      
      public class ConsoleRepositoryEventListener extends AbstractRepositoryListener {
      
      @Override
      public void artifactInstalled(RepositoryEvent event) {
          System.out.printf("artifact %s installed to file %s\n, event.getArtifact()", 
      event.getFile());
      }
      
      @Override
      public void artifactInstalling(RepositoryEvent event) {
          System.out.printf("installing artifact %s to file %s\n, event.getArtifact()", 
      event.getFile());
      }
      
      @Override
      public void artifactResolved(RepositoryEvent event) {
          System.out.printf("artifact %s resolved from repository %s\n", event.getArtifact(), event.getRepository());
      }
      
      @Override
      public void artifactDownloading(RepositoryEvent event) {
          System.out.printf("downloading artifact %s from repository %s\n", event.getArtifact(), event.getRepository());
      }
      
      @Override
      public void artifactDownloaded(RepositoryEvent event) {
          System.out.printf("downloaded artifact %s from repository %s\n", event.getArtifact(), event.getRepository());
      }
      
      @Override
      public void artifactResolving(RepositoryEvent event) {
          System.out.printf("resolving artifact %s\n", event.getArtifact());
      }
      
      }
      

      <properties>
          <aetherVersion>1.1.0</aetherVersion>
          <mavenVersion>3.2.1</mavenVersion>
      </properties>
      <dependencies>
          <dependency>
              <groupId>org.eclipse.aether</groupId>
              <artifactId>aether-api</artifactId>
              <version>${aetherVersion}</version>
          </dependency>
          <dependency>
              <groupId>org.eclipse.aether</groupId>
              <artifactId>aether-spi</artifactId>
              <version>${aetherVersion}</version>
          </dependency>
          <dependency>
              <groupId>org.eclipse.aether</groupId>
              <artifactId>aether-util</artifactId>
              <version>${aetherVersion}</version>
          </dependency>
          <dependency>
              <groupId>org.eclipse.aether</groupId>
              <artifactId>aether-impl</artifactId>
              <version>${aetherVersion}</version>
          </dependency>
          <dependency>
              <groupId>org.eclipse.aether</groupId>
              <artifactId>aether-connector-basic</artifactId>
              <version>${aetherVersion}</version>
          </dependency>
          <dependency>
              <groupId>org.eclipse.aether</groupId>
              <artifactId>aether-transport-file</artifactId>
              <version>${aetherVersion}</version>
          </dependency>
          <dependency>
              <groupId>org.eclipse.aether</groupId>
              <artifactId>aether-transport-http</artifactId>
              <version>${aetherVersion}</version>
          </dependency>
          <dependency>
              <groupId>org.apache.maven</groupId>
              <artifactId>maven-aether-provider</artifactId>
              <version>${mavenVersion}</version>
          </dependency>
      </dependencies>
      

      【讨论】:

      • 你能解释一下你的答案和我的不同吗?
      • 我试图加强你的回答 JF Meier,第一个区别是我曾经将 pom.xml 位置作为输入来获取所有 jar,你给出了 artifact id、group id 和 all 和第二个区别我添加了如何设置下载代理,并举例说明如何使用本地 repo 作为 maven 中心
      • 如果您在我的答案中添加一些 cmets 并解释弱点,读者可能会受益更多。
      猜你喜欢
      • 2014-04-13
      • 2019-08-12
      • 2015-11-29
      • 1970-01-01
      • 2016-05-22
      • 2012-09-30
      • 1970-01-01
      • 2012-02-26
      • 1970-01-01
      相关资源
      最近更新 更多