Home Explore Blog Models CI



nixpkgs

7th chunk of `doc/languages-frameworks/maven.section.md`
93ebf2bb020060475c8c237fcdf467bebe7bbc1b383ed8db0000000100000e3e
          --add-flags "-classpath $out/share/java/maven-demo-${finalAttrs.version}.jar:''${classpath#:}" \
          --add-flags "Main"

    runHook postInstall
  '';
})
```

#### MANIFEST file via Maven Plugin {#manifest-file-via-maven-plugin}

This method is ideal if you are the project owner and want to change your `pom.xml` to set the CLASSPATH within it.

Augment the `pom.xml` to create a JAR with the following manifest:

```xml
<build>
  <plugins>
    <plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
            <archive>
                <manifest>
                    <addClasspath>true</addClasspath>
                    <classpathPrefix>../../repository/</classpathPrefix>
                    <classpathLayoutType>repository</classpathLayoutType>
                    <mainClass>Main</mainClass>
                </manifest>
                <manifestEntries>
                    <Class-Path>.</Class-Path>
                </manifestEntries>
            </archive>
        </configuration>
    </plugin>
  </plugins>
</build>
```

The above plugin instructs the JAR to look for the necessary dependencies in the `lib/` relative folder. The layout of the folder is also in the _maven repository_ style.

```bash
❯ unzip -q -c $(nix-build --no-out-link runnable-jar.nix)/share/java/maven-demo-1.0.jar META-INF/MANIFEST.MF

Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: nixbld
Class-Path: . ../../repository/com/vdurmont/emoji-java/5.1.1/emoji-jav
 a-5.1.1.jar ../../repository/org/json/json/20170516/json-20170516.jar
Created-By: Apache Maven 3.6.3
Build-Jdk: 1.8.0_265
Main-Class: Main
```

We will modify the derivation above to add a symlink to our repository so that it's accessible to our JAR during the `installPhase`.

```nix
{
  stdenv,
  maven,
  callPackage,
  makeWrapper,
  jre,
}:
let
  # pick a repository derivation, here we will use buildMaven
  repository = callPackage ./build-maven-repository.nix { };
in
stdenv.mkDerivation (finalAttrs: {
  pname = "maven-demo";
  version = "1.0";

  src = builtins.fetchTarball "https://github.com/fzakaria/nixos-maven-example/archive/main.tar.gz";
  nativeBuildInputs = [ makeWrapper ];
  buildInputs = [ maven ];

  buildPhase = ''
    runHook preBuild

    echo "Using repository ${repository}"
    mvn --offline -Dmaven.repo.local=${repository} package;

    runHook postBuild
  '';

  installPhase = ''
    runHook preInstall

    mkdir -p $out/bin

    # create a symbolic link for the repository directory
    ln -s ${repository} $out/repository

    install -Dm644 target/maven-demo-${finalAttrs.version}.jar $out/share/java
    # create a wrapper that will automatically set the classpath
    # this should be the paths from the dependency derivation
    makeWrapper ${jre}/bin/java $out/bin/maven-demo \
          --add-flags "-jar $out/share/java/maven-demo-${finalAttrs.version}.jar"

    runHook postInstall
  '';
})
```
::: {.note}
Our script produces a dependency on `jre` rather than `jdk` to restrict the runtime closure necessary to run the application.
:::

This will give you an executable shell-script that launches your JAR with all the dependencies available.

```bash
❯ tree $(nix-build --no-out-link runnable-jar.nix)
/nix/store/8d4c3ibw8ynsn01ibhyqmc1zhzz75s26-maven-demo-1.0
├── bin
│   └── maven-demo
├── repository -> /nix/store/g87va52nkc8jzbmi1aqdcf2f109r4dvn-maven-repository
└── share
    └── java
        └── maven-demo-1.0.jar

❯ $(nix-build --no-out-link --option tarball-ttl 1 runnable-jar.nix)/bin/maven-demo
NixOS 😀 is super cool 😃!
```

Title: Nix Derivation for Maven JARs with Manifest Classpath
Summary
This section elaborates on using a Maven plugin to define the CLASSPATH within a JAR's manifest file, contrasting it with the earlier CLASSPATH method. It demonstrates how configuring the `maven-jar-plugin` in `pom.xml` embeds dependency paths (relative to a `repository/` directory) directly into `META-INF/MANIFEST.MF`. A Nix derivation is then provided, illustrating how to set up the build process: it compiles the Maven project and, during the `installPhase`, creates a symbolic link from `$out/repository` to the actual Maven repository derivation. This ensures the JAR can locate its dependencies as specified in its manifest. The resulting executable shell script (generated by `makeWrapper`) launches the JAR using a `jre` dependency for a minimized runtime closure, successfully demonstrating a working application with external dependencies.