【问题标题】:Maven - how can I add an arbitrary classpath entry to a jar?Maven - 如何将任意类路径条目添加到 jar?
【发布时间】:2010-12-03 08:42:50
【问题描述】:

我有一种不寻常的情况,我需要将任意类路径条目(指向 jar 文件)添加到可执行 jar 的清单中。 (这适用于 Swing 桌面应用程序。)

maven-jar-plugin 使用 maven 依赖项为 jar 清单生成“Class-Path”条目,似乎没有任何方法可以添加任意条目。

我还研究了使用“-classpath”参数将任意类路径条目硬编码到启动应用程序的批处理文件中,但我不知道如何让 Maven 将类路径过滤到批处理文件中.

【问题讨论】:

  • 出于兴趣,为什么要添加类路径条目而不是指定依赖项并让Maven计算类路径?
  • 这是一种复杂的部署情况 - 简而言之,我有一个 jar,它位于部署目标中一个众所周知的位置,我想为其添加一个绝对路径。 maven 知道该依赖项,但不会部署它。在另一个类似的情况下,我想将具有不同名称的相同依赖项添加到类路径中。这是您在公司环境中工作时遇到的那些疯狂的一次性事情之一:)
  • 我想玩依赖范围不是一个选项(我想“提供”)。是的,我同意,这将是一个令人讨厌的工作。
  • 我确实弄乱了“提供”和“依赖”范围,但它们的工作方式并不像您预期​​的那样。

标签: maven-2 build jar classpath


【解决方案1】:

我发现这个问题有一个简单的解决方案。您可以将<Class-Path> 元素添加到<manifestEntries> 元素,并将<addClassPath>true</addClassPath> 设置为<manifest> 元素。所以<Class-Path> 元素的值会自动添加到类路径中。示例:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
        <addClasspath>true</addClasspath>
        <mainClass>your.main.Class</mainClass>
      </manifest>
      <manifestEntries>
        <Class-Path>../conf/</Class-Path>
      </manifestEntries>
    </archive>
  </configuration>
</plugin>

【讨论】:

  • 注意:这种方法与 JAR 索引不兼容!请参阅stackoverflow.com/a/10437177/14731 了解更多信息。
  • @Laf 谢谢!它对我有用。但我不得不排除 addClasspath,因为它将所有东西(lib、jars 等)添加到我的清单中,而我只需要一个文件夹(config/)。不过,谢谢!
【解决方案2】:

更新:以下是如何将类路径过滤到自定义清单中。

maven-dependency-plugin 的build-classpath 目标可以配置为将类路径输出到属性格式的文件中(即classpath=[classpath])。然后配置过滤器元素以使用生成的类路径文件,并配置要过滤的资源目录。

例如:

<build>
  <plugins>
    <plugin>
      <artifactId>maven-dependency-plugin</artifactId>
      <version>2.1</version>
      <executions>
        <execution>
          <phase>generate-resources</phase>
          <goals>
            <goal>build-classpath</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <outputFilterFile>true</outputFilterFile>
        <outputFile>${project.build.directory}/classpath.properties</outputFile>
      </configuration>
    </plugin>
    <plugin>
      <artifactId>maven-jar-plugin</artifactId>
      <configuration>
        <archive>
          <manifestFile>
            ${project.build.outputDirectory}/META-INF/MANIFEST.MF
          </manifestFile>
        </archive>
      </configuration>
    </plugin>
  </plugins>
  <filters>
    <filter>${project.build.directory}/classpath.properties</filter>
  </filters>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
    </resource>
  </resources>
</build>

然后在 src/main/resources/META-INF/Manifest.MF 中指定以下内容:

Bundle-Version: 4.0.0
...
Classpath: ${classpath};[specify additional entries here]

注意:使用标准窗口路径分隔符 (\) 进行此处理时存在错误,生成路径被去除分隔符(注意它在 Linux 上工作正常)。您可以通过在 build-classpath 目标的配置中指定 &lt;fileSeparator&gt;\\\\&lt;/fileSeparator&gt; 来为 Windows 正确生成类路径。


您可以在jar-plugin 的配置中自定义清单。为此,您需要在 pom 中添加类似的内容。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  ...
  <configuration>
    <archive>
      <index>true</index>
      <manifest>
        <addClasspath>true</addClasspath>
      </manifest>
      <manifestEntries>
        <mode>development</mode>
        <url>${pom.url}</url>
        <key>value</key>
      </manifestEntries>
    </archive>
  </configuration>
  ...
</plugin>

完整的archiver specification 提供了很多选项。有关配置类路径的选项,请参阅 examples page

如果这些都不适合您,您可以define your own Manifest,设置包含所需条目的属性,并使用filter 用这些属性填充清单

【讨论】:

  • 我知道如何使用过滤,但我不知道如何将类路径过滤到文件中。类路径是否有内置属性?
  • 我包含了入门指南过滤部分的链接,您只需配置包含清单的资源目录即可启用过滤。该页面包含执行此操作的示例
  • 谢谢,但是将类路径插入过滤后的清单文件的神奇 maven 属性是什么?
  • 谢谢,这是我第一次尝试生成过滤器文件,打开了一些有趣的可能性......
  • 是的,你可以通过过滤做各种有用的事情。
【解决方案3】:

尝试像在这个错误中那样做,即使用 manifestEntries/Class-Path 元素合并条目

https://issues.apache.org/jira/browse/MJAR-41

【讨论】:

    【解决方案4】:

    我能够得到 Rich Seller 方法的稍微修改的版本,避免了 cmets 中提到的 Error assembling JAR: Unable to read manifest file (line too long) 问题。

    我想通过 .jar 文件的清单类路径中引用的 dependency-maven-plugin 复制所有依赖项。我无法使用 Maven Jar 插件的 &lt;addClasspath&gt;true&lt;/addClasspath&gt; 选项,因为它在我的 Jar 类路径中放了太多东西(我只是复制了一些依赖项)。

    这是我如何让它工作的。

    首先我使用 Maven 依赖插件进行复制,同时构建一个类路径变量。使用&lt;outputProperty&gt; 我把它放在一个属性而不是一个文件中:

      <plugin>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>3.2.0</version>
        <executions>
          <execution>
            <phase>generate-resources</phase>
            <goals>
              <goal>copy-dependencies</goal>
              <goal>build-classpath</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/lib</outputDirectory>              
    
              <!-- These properties are for build-classpath. It creates a classpath for the copied
                   dependencies and puts it in the ${distro.classpath} property. The jar Class-Path
                   uses spaces as separators. Unfortunately <pathSeparator> configuration property
                   does not work with a space as value, so the pathSeparator is set to a character
                   here and this is then replaced later using the regex-property plugin. -->
              <prefix>lib</prefix>
              <outputProperty>distro.classpath</outputProperty>
              <pathSeparator>:</pathSeparator>
            </configuration>
          </execution>
        </executions>
      </plugin>
    

    Jar Manifest Class-Path 的语法使用 空格 作为分隔符。虽然依赖插件有一个&lt;pathSeparator&gt; 属性,但不幸的是,如果它是一个空格,它会忽略该值。所以我只是将它硬编码为某个值,然后使用 build-helper-maven-plugin 将其替换为我需要的空间:

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <version>3.2.0</version>
        <executions>
          <execution>
            <phase>process-resources</phase>
            <goals>
              <goal>regex-property</goal>
            </goals>
            <configuration>
              <!-- Here the value of property for the jar the Class-Path is replaced to have a space
                   as separator. Unfortunately <replacement> does not work if a single space if specified
                   so this uses the surrounding .jar and lib to provide some content. -->
              <name>distro.classpath.replaced</name>
              <value>${distro.classpath}</value>
              <regex>[.]jar[:]lib</regex>
              <replacement>.jar lib</replacement>
            </configuration>
          </execution>
        </executions>
      </plugin>
    

    在这里,&lt;replacement&gt; 值如果只是一个空格也不起作用,所以我用它周围存在的文本将它包围起来。

    最后我可以使用 Maven Jar Plugin 来获取被替换为空格的属性作为分隔符。因为我在 maven 定义中传递了类路径的值(而不是从过滤的文件中提取),所以 Manifest 文件的行长约束会自动处理,不会出现“行太长”的问题:

      <plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <version>3.2.0</version>
        <configuration>
          <archive>
            <manifest>
              <mainClass>org.acme.Main</mainClass>
            </manifest>
            <manifestEntries>
              <!-- Include the computed classpath with all copied dependencies in the jar here -->
              <Class-Path>${distro.classpath.replaced}</Class-Path>
            </manifestEntries>
          </archive>
        </configuration>
      </plugin>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-24
      • 2021-12-12
      • 2015-09-27
      • 2013-11-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多