Home Explore Blog Models CI



nixpkgs

5th chunk of `doc/languages-frameworks/maven.section.md`
a7c5f53dc580128b9db778ec2ddac15f5ede31a6e703aecd0000000100000fcf
  outputHash = lib.fakeHash;
}
```

The build will fail, and tell you the expected `outputHash` to place. When you've set the hash, the build will return with a `/nix/store` entry whose contents are the full Maven repository.

::: {.warning}
Some additional files are deleted that would cause the output hash to change potentially on subsequent runs.
:::

```bash
❯ tree $(nix-build --no-out-link double-invocation-repository.nix) | head
/nix/store/8kicxzp98j68xyi9gl6jda67hp3c54fq-maven-repository
├── backport-util-concurrent
│   └── backport-util-concurrent
│       └── 3.1
│           ├── backport-util-concurrent-3.1.pom
│           └── backport-util-concurrent-3.1.pom.sha1
├── classworlds
│   └── classworlds
│       ├── 1.1
│       │   ├── classworlds-1.1.jar
```

If your package uses _SNAPSHOT_ dependencies or _version ranges_; there is a strong likelihood that over time, your output hash will change since the resolved dependencies may change. Hence this method is less recommended than using `buildMaven`.

### Building a JAR {#building-a-jar}

Regardless of which strategy is chosen above, the step to build the derivation is the same.

```nix
{
  stdenv,
  maven,
  callPackage,
}:
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";
  buildInputs = [ maven ];

  buildPhase = ''
    runHook preBuild

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

    runHook postBuild
  '';

  installPhase = ''
    runHook preInstall

    install -Dm644 target/${finalAttrs.pname}-${finalAttrs.version}.jar $out/share/java

    runHook postInstall
  '';
})
```

::: {.tip}
We place the library in `$out/share/java` since JDK package has a _stdenv setup hook_ that adds any JARs in the `share/java` directories of the build inputs to the CLASSPATH environment.
:::

```bash
❯ tree $(nix-build --no-out-link build-jar.nix)
/nix/store/7jw3xdfagkc2vw8wrsdv68qpsnrxgvky-maven-demo-1.0
└── share
    └── java
        └── maven-demo-1.0.jar

2 directories, 1 file
```

### Runnable JAR {#runnable-jar}

The previous example builds a `jar` file but that's not a file one can run.

You need to use it with `java -jar $out/share/java/output.jar` and make sure to provide the required dependencies on the classpath.

The following explains how to use `makeWrapper` in order to make the derivation produce an executable that will run the JAR file you created.

We will use the same repository we built above (either _double invocation_ or _buildMaven_) to setup a CLASSPATH for our JAR.

The following two methods are more suited to Nix then building an [UberJar](https://imagej.net/Uber-JAR) which may be the more traditional approach.

#### CLASSPATH {#classpath}

This method is ideal if you are providing a derivation for _nixpkgs_ and don't want to patch the project's `pom.xml`.

We will read the Maven repository and flatten it to a single list. This list will then be concatenated with the _CLASSPATH_ separator to create the full classpath.

We make sure to provide this classpath to the `makeWrapper`.

```nix
{
  stdenv,
  maven,
  callPackage,
  makeWrapper,
  jre,
}:
let
  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

Title: Building and Running Maven JARs in Nix
Summary
This chunk concludes the discussion on the 'Double Invocation' method for Maven repositories, reiterating its instability due to changing output hashes with `SNAPSHOT` dependencies or version ranges. It then details the process of building a Maven JAR within Nix using `stdenv.mkDerivation`, emphasizing the need for a pre-built Maven repository (from either `buildMaven` or 'Double Invocation'). The built JAR is placed in `$out/share/java` to leverage `JDK` package setup hooks. Finally, it addresses how to create a 'Runnable JAR', explaining that a standard JAR file isn't directly executable. It introduces using `makeWrapper` to create an executable derivation, preferring this over an 'UberJar' approach. The `CLASSPATH` method is presented, involving flattening the Maven repository and setting the `CLASSPATH` for the `java -jar` command via `makeWrapper`.