【问题标题】:Java get version of maven dependency at runtimeJava在运行时获取maven依赖的版本
【发布时间】:2020-03-16 07:47:12
【问题描述】:

是否可以在运行时检索特定 maven 依赖项的版本?

例如对于 pom.xml:

<dependency>
    <groupId>foo.bar</groupId>
    <artifactId>foobar</artifactId>
    <version>1.0</version>
</dependency>

我想检索具有工件 ID foobar 的特定依赖项的版本 1.0

【问题讨论】:

  • 我想这就是你要找的东西:*.com/a/10295470/4597596
  • @A.S.H 感谢您的提示,但我认为问题不在于从 pom 中阅读
  • @GaneshchaitanyaI 我不想指定依赖项,而是在运行时读取依赖项版本
  • “在运行时”是指您有一些依赖于 foo.bar.foobar 依赖项的应用程序,并且在该应用程序中您希望能够打印出 Maven foo. bar.foobar 依赖项在构建时有吗?

标签: java maven


【解决方案1】:

你在看你自己创建的罐子吗?还是第三方库?我已经为前者发布了一个轻量级的解决方案。因此,如果您在运行时查找的 jar 包在您自己手中,请继续尝试;-)。它可能比从 jar 文件中读取 XML 或属性要优雅一些。

想法

  1. 使用 Java 服务加载器 方法可以在以后添加尽可能多的组件/工件,它们可以在运行时贡献自己的版本。创建一个非常轻量级的库,只需几行代码即可读取、查找、过滤和排序类路径上的所有工件版本。
  2. 创建一个ma​​ven源代码生成器插件,在编译时为每个模块生成服务实现,在每个jar中打包一个非常简单的服务。

解决办法

解决方案的第一部分是artifact-version-service 库,现在可以在githubMavenCentral 上找到它。它涵盖了服务定义和一些在运行时获取工件版本的方法。

第二部分是artifact-version-maven-plugin,也可以在githubMavenCentral 上找到。它用于让生成器轻松实现每个工件的服务定义。

示例

获取所有带有坐标的模块

不再需要读取jar manifest,只需一个简单的方法调用:

// iterate list of artifact dependencies
for (Artifact artifact : ArtifactVersionCollector.collectArtifacts()) {
    // print simple artifact string example
    System.out.println("artifact = " + artifact);
}

返回一组排序的工件。要修改排序顺序,请提供自定义比较器:

new ArtifactVersionCollector(Comparator.comparing(Artifact::getVersion)).collect();

这样返回的工件列表按版本号排序。

查找特定的工件

ArtifactVersionCollector.findArtifact("foo.bar", "foobar");

获取特定工件的版本详细信息。

查找具有匹配 groupId(s) 的工件

查找所有 groupId foo.bar 的工件(完全匹配):

ArtifactVersionCollector.findArtifactsByGroupId("foo.bar", true);

查找 groupId foo.bar 开头的所有工件:

ArtifactVersionCollector.findArtifactsByGroupId("foo.bar", false);

按版本号排序结果:

new ArtifactVersionCollector(Comparator.comparing(Artifact::getVersion)).artifactsByGroupId("foo.", false);

对工件列表实施自定义操作

通过提供 lambda,第一个示例可以这样实现:

ArtifactVersionCollector.iterateArtifacts(a -> {
    System.out.println(a);
    return false;
});

安装

将这两个标签添加到所有 pom.xml 文件中,或者添加到某处的公司主 pom 中:

<build>
  <plugins>
    <plugin>
      <groupId>de.westemeyer</groupId>
      <artifactId>artifact-version-maven-plugin</artifactId>
      <version>1.1.0</version>
      <executions>
        <execution>
          <goals>
            <goal>generate-service</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

<dependencies>
  <dependency>
    <groupId>de.westemeyer</groupId>
    <artifactId>artifact-version-service</artifactId>
    <version>1.1.0</version>
  </dependency>
</dependencies>

【讨论】:

    【解决方案2】:

    这里最有问题的部分是通过名称查找 JAR。不幸的是,在 Java 中没有 100% 可靠的方法。要按名称获取 JAR,您需要扫描可能并不总是存在的正在运行的应用程序的类路径(例如,因为使用了自定义类加载器或使用了模块路径而不是类路径)。

    但是让我们假设您没有使用任何花哨的功能,例如自定义类加载器,并且您的类路径包含所有 Maven 依赖项。你现在需要做什么?我将尝试描述一个粗略的算法:

    • 从您的类路径中检索所有 JAR 文件的路径。
    • 扫描每个 JAR 文件并找到文件pom.properties。它位于 META-INF/maven/{groupId}/{artifactId}。
    • pom.properties 中查找version 属性的值。

    同样,这个解决方案并不完全可靠。您必须决定:您真的需要版本信息吗?出于什么目的?

    【讨论】:

      【解决方案3】:

      pom.xml

      <?xml version="1.0" encoding="UTF-8"?>
      
      <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
          <modelVersion>4.0.0</modelVersion>
      
          <groupId>org.example</groupId>
          <artifactId>WDProject</artifactId>
          <version>1.0-SNAPSHOT</version>
      
          <name>WDProject</name>
          <url>http://www.nosite.com</url>
      
          <properties>
              <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
              <maven.compiler.source>1.7</maven.compiler.source>
              <maven.compiler.target>1.7</maven.compiler.target>
      
              <selenium.version>3.141.59</selenium.version>
              <webdrivermanager.version>3.7.1</webdrivermanager.version>
      
          </properties>
      
          <dependencies>
              <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.11</version>
                  <scope>test</scope>
              </dependency>
      
              <!-- https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager -->
              <dependency>
                  <groupId>io.github.bonigarcia</groupId>
                  <artifactId>webdrivermanager</artifactId>
                  <version>${webdrivermanager.version}</version>
              </dependency>
      
              <dependency>
                  <groupId>org.seleniumhq.selenium</groupId>
                  <artifactId>selenium-api</artifactId>
                  <version>${selenium.version}</version>
              </dependency>
              <dependency>
                  <groupId>org.seleniumhq.selenium</groupId>
                  <artifactId>selenium-server</artifactId>
                  <version>${selenium.version}</version>
              </dependency>
              <dependency>
                  <groupId>org.seleniumhq.selenium</groupId>
                  <artifactId>selenium-remote-driver</artifactId>
                  <version>${selenium.version}</version>
              </dependency>
              <dependency>
                  <groupId>org.seleniumhq.selenium</groupId>
                  <artifactId>selenium-java</artifactId>
                  <version>${selenium.version}</version>
                  <scope>test</scope>
              </dependency>
              <dependency>
                  <groupId>net.lingala.zip4j</groupId>
                  <artifactId>zip4j</artifactId>
                  <version>2.2.4</version>
              </dependency>
              <dependency>
                  <groupId>org.apache.maven</groupId>
                  <artifactId>maven-model</artifactId>
                  <version>3.3.9</version>
              </dependency>
          </dependencies>
      
          <build>
              <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
                  <plugins>
                      <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
                      <plugin>
                          <artifactId>maven-clean-plugin</artifactId>
                          <version>3.1.0</version>
                      </plugin>
                      <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
                      <plugin>
                          <artifactId>maven-resources-plugin</artifactId>
                          <version>3.0.2</version>
                      </plugin>
                      <plugin>
                          <artifactId>maven-compiler-plugin</artifactId>
                          <version>3.8.0</version>
                      </plugin>
                      <plugin>
                          <artifactId>maven-surefire-plugin</artifactId>
                          <version>2.22.1</version>
                      </plugin>
                      <plugin>
                          <artifactId>maven-jar-plugin</artifactId>
                          <version>3.0.2</version>
                      </plugin>
                      <plugin>
                          <artifactId>maven-install-plugin</artifactId>
                          <version>2.5.2</version>
                      </plugin>
                      <plugin>
                          <artifactId>maven-deploy-plugin</artifactId>
                          <version>2.8.2</version>
                      </plugin>
                      <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
                      <plugin>
                          <artifactId>maven-site-plugin</artifactId>
                          <version>3.7.1</version>
                      </plugin>
                      <plugin>
                          <artifactId>maven-project-info-reports-plugin</artifactId>
                          <version>3.0.0</version>
                      </plugin>
                  </plugins>
              </pluginManagement>
          </build>
      </project>
      
      

      虽然您想要搜索特定的依赖项,但下面的代码会检索 pom 文件中可用的依赖项的所有详细信息。 您只需要创建一个包装器方法来检索特定依赖项的详细信息。

      
      import org.apache.maven.model.Model;
      import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
      import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
      
      import java.io.FileReader;
      import java.io.IOException;
      
      
      class SampleMavenDependencyReader {
      
          public static void main(String[] args) throws IOException, XmlPullParserException {
              MavenXpp3Reader reader = new MavenXpp3Reader();
              Model model = reader.read(new FileReader("/Users/nonadmin/bins/projects/IdeaProjects/WDProject/pom.xml"));
      
              for (int i = 0; i < model.getDependencies().size(); i++) {
                  System.out.println(model.getDependencies().get(i));
              }
          }
      }
      
      

      输出

      Dependency {groupId=junit, artifactId=junit, version=4.11, type=jar}
      Dependency {groupId=io.github.bonigarcia, artifactId=webdrivermanager, version=${webdrivermanager.version}, type=jar}
      Dependency {groupId=org.seleniumhq.selenium, artifactId=selenium-api, version=${selenium.version}, type=jar}
      Dependency {groupId=org.seleniumhq.selenium, artifactId=selenium-server, version=${selenium.version}, type=jar}
      Dependency {groupId=org.seleniumhq.selenium, artifactId=selenium-remote-driver, version=${selenium.version}, type=jar}
      Dependency {groupId=org.seleniumhq.selenium, artifactId=selenium-java, version=${selenium.version}, type=jar}
      Dependency {groupId=net.lingala.zip4j, artifactId=zip4j, version=2.2.4, type=jar}
      Dependency {groupId=org.apache.maven, artifactId=maven-model, version=3.3.9, type=jar}~~~
      
      

      【讨论】:

      • 我不是在寻找自己项目的版本号,而是在我的项目中使用的特定依赖项的版本号。
      • 我已经更新了答案,请您看一遍并验证,如果您觉得它有用,请点赞。
      最近更新 更多