System-wide Installation of Gradle and JDK

Hi all,

these days I mostly write code for the JVM using the gradle build system.
When I setup my laptop with NixOS I just wanted to install the JDK and gradle system-wide, e.g. in /etc/nixos/configuration.nix. Tbh, I just found this easier than fiddling around with nix-shell (which I want to learn a bit later once I get to speed with NixOS).
Installing gradle and the JDK is fairly easy, however, a dependency of the project needs JDK 11 or higher - so I added gradle and jdk14 to my systemPackages only to find out that gradle uses a different version of Java, which in this case is Java 8 - and now loading the dependencies classes on runtime fails. After googling for a while I’m almost certain that I need to use the Overlay mechanism.

My question now is how I can solve the problem with gradle precisely - I think I need an overlay for gradle and override it’s build inputs. Sadly, I don’t know enough about Overlays at the moment to write this overlay on my own.

Can anyone provide a hint for me?
I’m thankful for every advice :slight_smile:

Thanks for reading this!

Overlays are useful if you want to change something in pkgs but they are not strictly necessary for this use case – you can just override gradle in place.

Looking at

https://github.com/NixOS/nixpkgs/blob/27da11972d3fd9353f81e94a6549e8a0da40f45d/pkgs/top-level/all-packages.nix#L12201-L12208

that would probably be something like

environment.systemPackages = [
  ((pkgs.gradleGen.override {
    java = jdk15;
  }).gradle_latest)
];

I do not see jdk14 in all-packages.nix, though.

Thank you very much for your post!
It isn’t only the correct solution for my specific problem, as it also shows that I confuse overrides with overlays and now I know what to learn next :slight_smile:

Thanks you much, this works well.

Alternative solution installing multiple JDK(s)

As LinuxInstallationSupplier searches also "/opt/java", the following extension of NixOS configuration can be used:

  1. create custom package jdkEnv with sub-directories pointing to JDK(s),
  2. set environment.pathsToLink to make this path available in /run/current-system/sw/jdks,
  3. link it to /opt/java,
  4. install latest JDK globally as default, otherwise ./gradlew might fail to run.
{ config, pkgs, ... }:

let
  jdkEnv = pkgs.runCommand "jdk-env" {
    buildInputs = with pkgs; [
      pkgs.openjdk17
      pkgs.openjdk21
      pkgs.temurin-bin-17
      pkgs.temurin-bin-21
    ];
 } ''
    mkdir -p $out/jdks
    ln -s ${pkgs.openjdk17}/lib/openjdk   $out/jdks/openjdk17
    ln -s ${pkgs.openjdk21}/lib/openjdk   $out/jdks/openjdk21
    ln -s ${pkgs.temurin-bin-17}          $out/jdks/temurin17
    ln -s ${pkgs.temurin-bin-21}          $out/jdks/temurin21
  '';
in {
  environment.pathsToLink = [ "/jdks" ];

  environment.systemPackages = [
    # to get /run/current-system/sw/jdks/ populated
    jdkEnv

    # to default java binaries to highest version (instead of 8 or something)
    pkgs.temurin-bin
  ];

  system.activationScripts.jdkSymlinks.text = ''
    mkdir -p /opt
    chmod 755 /opt

    ln -sfT /run/current-system/sw/jdks /opt/java
  '';
}