ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java – Maven:以编程方式获取所有依赖项

2019-06-11 11:47:07  阅读:1183  来源: 互联网

标签:java maven aether


如何以编程方式获取Maven模块在Maven执行环境之外的所有依赖项?

到目前为止,我有:

通过maven-core:

Path pomPath = ...;
MavenXpp3Reader reader = new MavenXpp3Reader();
try (InputStream is = Files.newInputStream(pomPath)) {
    Model model = reader.read(is);
    this.mavenProject = new MavenProject(model);
}

并通过jcabi-aether:

File localRepo = Paths.get(System.getProperty("user.home"), ".m2").toFile();
new Classpath(mavenProject, localRepo, "runtime")

到目前为止这一般是正确的吗?

现在的问题是我得到一个NullPointerException:

Caused by: java.lang.NullPointerException
    at com.jcabi.aether.Aether.mrepos(Aether.java:197)
    at com.jcabi.aether.Aether.<init>(Aether.java:140)
    at com.jcabi.aether.Classpath.<init>(Classpath.java:125)

因为mavenProject.getRemoteProjectRepositories()返回null.

如何初始化MavenProject以包含已配置的远程repos,同时考虑settings.xml文件(镜像,代理,存储库等)?

解决方法:

在Maven插件之外,对工件进行操作的方式是通过Aether.该团队有一个示例项目,用于获取名为ResolveTransitiveDependencies的给定工件的传递依赖性.一旦设置了Aether依赖项(like shown here),您就可以:

public static void main(final String[] args) throws Exception {
    DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
    RepositorySystem system = newRepositorySystem(locator);
    RepositorySystemSession session = newSession(system);

    RemoteRepository central = new RemoteRepository.Builder("central", "default", "http://repo1.maven.org/maven2/").build();

    Artifact artifact = new DefaultArtifact("group.id:artifact.id:version");

    CollectRequest collectRequest = new CollectRequest(new Dependency(artifact, JavaScopes.COMPILE), Arrays.asList(central));
    DependencyFilter filter = DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE);
    DependencyRequest request = new DependencyRequest(collectRequest, filter);
    DependencyResult result = system.resolveDependencies(session, request);

    for (ArtifactResult artifactResult : result.getArtifactResults()) {
        System.out.println(artifactResult.getArtifact().getFile());
    }
}

private static RepositorySystem newRepositorySystem(DefaultServiceLocator locator) {
    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) {
    DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
    LocalRepository localRepo = new LocalRepository("target/local-repo");
    session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));
    return session;
}

它将下载工件并将它们放入“target / local-repo”.

请注意,您可以使用系统会话上的DefaultProxySelector和DefaultMirrorSelector配置代理和镜像.有可能读取Maven设置文件并使用它来填充会话,但事情变得非常难看……

如果你想要与Maven本身紧密耦合,因为你有权访问要处理的POM并想要考虑设置,那么以编程方式直接调用Maven要简单得多.在这种情况下,您对给定POM文件的每个依赖项的路径感兴趣,包括传递依赖项.为此,dependency:list的目标,以及将outputAbsoluteArtifactFilename设置为真,将给出(差不多)完全相同的目标.

要以编程方式调用Maven,可以使用Invoker API.将依赖项添加到项目中:

<dependency>
  <groupId>org.apache.maven.shared</groupId>
  <artifactId>maven-invoker</artifactId>
  <version>2.2</version>
</dependency>

你可以有:

InvocationRequest request = new DefaultInvocationRequest();
request.setPomFile(new File(pomPath));
request.setGoals(Arrays.asList("dependency:list"));
Properties properties = new Properties();
properties.setProperty("outputFile", "dependencies.txt"); // redirect output to a file
properties.setProperty("outputAbsoluteArtifactFilename", "true"); // with paths
properties.setProperty("includeScope", "runtime"); // only runtime (scope compile + runtime)
// if only interested in scope runtime, you may replace with excludeScope = compile
request.setProperties(properties);

Invoker invoker = new DefaultInvoker();
// the Maven home can be omitted if the "maven.home" system property is set
invoker.setMavenHome(new File("/path/to/maven/home"));
invoker.setOutputHandler(null); // not interested in Maven output itself
InvocationResult result = invoker.execute(request);
if (result.getExitCode() != 0) {
    throw new IllegalStateException("Build failed.");
}

Pattern pattern = Pattern.compile("(?:compile|runtime):(.*)");
try (BufferedReader reader = Files.newBufferedReader(Paths.get("dependencies.txt"))) {
    while (!"The following files have been resolved:".equals(reader.readLine()));
    String line;
    while ((line = reader.readLine()) != null && !line.isEmpty()) {
        Matcher matcher = pattern.matcher(line);
        if (matcher.find()) {
            // group 1 contains the path to the file
            System.out.println(matcher.group(1));
        }
    }
}

这将创建一个调用请求,其中包含:要调用的目标和系统属性,就像在命令行上启动mvn dependency:list -Dprop = value一样.要使用的设置的路径将默认为“${user.home} /settings.xml”的标准位置,但也可以使用request.setUserSettingsFile(…)指定设置的路径, request.setGlobalSettingsFile(…).调用者需要设置Maven主页(即安装目录),但仅限于未设置“maven.home”系统属性.

调用依赖项的结果:列表被重定向到一个文件,稍后进行后处理.该目标的输出包括格式中的依赖项列表(如果没有,则分类器可能不存在):

group.id:artifact.id:type[:classifier]:version:scope:pathname

没有办法只输出已解析工件文件的路径,并且分类器可能不存在这一事实使解析变得复杂(我们无法拆分:有限制,因为路径可能包含: …).首先,已解析的工件位于输出文件中的“以下文件已解析:”行下面,然后,由于所需范围仅为编译或运行时,我们可以使用简单的正则表达式获取工件文件的路径获取编译后的所有内容:或运行时:然后,该路径可以直接用作新文件.

如果后期处理过程中的箍看起来太脆弱,我猜你可以创建自己的插件,只输出已解析的工件文件名.

标签:java,maven,aether
来源: https://codeday.me/bug/20190611/1218491.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有