Maven - how can I add an arbitrary classpath entry to a jar?

87,889

Solution 1

I found that there is an easy solution for this problem. You can add a <Class-Path> element to <manifestEntries> element, and set <addClassPath>true</addClassPath> to <manifest> element. So value of <Class-Path> element is added to class-path automatically. Example:

<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>

Solution 2

Update: Here's how to filter a classpath into a custom manifest.

The maven-dependency-plugin's build-classpath goal can be configured to output the classpath to a file in the properties format (i.e. classpath=[classpath]). You then configure the filters element to use the generated classpath file, and configure the resources directory to be filtered.

For example:

<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>

Then specify the following in src/main/resources/META-INF/Manifest.MF:

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

Note: there is a bug with this processing using the standard window path separator (\), the generate path is stripped of separators (note it works fine on Linux). You can get the classpath to be generated correctly for Windows by specifying <fileSeparator>\\\\</fileSeparator> in the build-classpath goal's configuration.


You can customise the manifest in the jar-plugin's configuration. To do so you'd add something like this to your 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>

The full archiver specification provides quite a few options. See the examples page for options on configuring the classpath.

If none of these work for you, you can define your own Manifest, set up properties containing the required entries and use a filter to populate the manifest with those properties

Solution 3

Try to do it like they do in this bug, i.e. merge entries using manifestEntries/Class-Path element

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

Share:
87,889
Ken Liu
Author by

Ken Liu

Director of Engineering at Cockroach Labs. Github: kenliu Twitter: @kenliu

Updated on July 08, 2022

Comments

  • Ken Liu
    Ken Liu almost 2 years

    I have an unusual situation where I need to add an arbitrary classpath entry (that points to a jar file) into the manifest of an executable jar. (This is for a Swing desktop application.)

    The maven-jar-plugin generates the "Class-Path" entry for the jar manifest using the maven dependencies, and there doesn't appear to be any way of adding arbitrary entries.

    I also looked at hard-coding the arbitrary classpath entry into the batch file that starts the application, using the "-classpath" parameter, but I can't figure out how to get Maven to filter the classpath into a batch file.

  • Ken Liu
    Ken Liu over 14 years
    I know how to use filtering, but I couldn't figure out how to filter the classpath into a file. Is there a built-in property for the classpath?
  • Rich Seller
    Rich Seller over 14 years
    I included a link to the filtering section of the getting started guide, you just need to configure the resources directory that contains the manifest to enable filtering. The page includes an example to do this
  • Ken Liu
    Ken Liu over 14 years
    Thanks, but what is the magic maven property that inserts the classpath into the filtered manifest file?
  • Rich Seller
    Rich Seller over 14 years
    Thanks, it's the first time I've tried generating a filter file, opens some interesting possibilities...
  • Ken Liu
    Ken Liu over 14 years
    Yeah, you can do all sorts of useful stuff with filtering.
  • Gili
    Gili about 12 years
    BEWARE: This approach is incompatible with JAR indexing! See stackoverflow.com/a/10437177/14731 for more information.
  • Gili
    Gili about 12 years
    -1: This approach is incompatible with JAR indexing. See stackoverflow.com/a/10437177/14731
  • Aksh
    Aksh over 8 years
    @Laf Thanks! It worked for me. But I had to exclude addClasspath, coz it was adding everything(lib, jars etc.) to my manifest, and I only needed one folder(config/). Still, thanks!
  • daniel.kahlenberg
    daniel.kahlenberg over 8 years
    The only bad tiny thing with this solution is that I'm getting Error assembling JAR: Unable to read manifest file (line too long) because the expanded ${classpath} value in the manifest.mf doesnt have the needed 72 characters line width, logical because there are many artifacts. Did someone have a similar experience? I'm asking because a fix would be welcome as I would like to use Rich Sellers approach: I need to filter one certain artifact off the classpath before the jar file is generated.