Home > Enterprise >  System-agnostic way to set JAVA_HOME of specific JDK version
System-agnostic way to set JAVA_HOME of specific JDK version

Time:08-01

Working with different projects, each one having different JDK version requirements (mainly 1.8 and 17), with people contributing from different operating systems; it has been decided to use the JAVA_HOME environment variable within our gradle scripts to get the JDK path.

It works well, though one needs to export JAVA_HOME to a different value, that differs for each individual contributor, each time one switches to another project.

I searched here at Stack sites, the SdkMan project and this blog post https://opensource.com/article/22/3/find-java-home about this topic.

The proposed solutions introduces much complexity to determine system type, locate available JDKs.

I ended-up writing my own implementation to find the JAVA_HOME of a specific JDK version, although it only supports RedHat and Debian based Linux distributions.

Is there a standard method to determine the JAVA_HOME, for a specific JDK version, in a fully system-agnostic way; be it Linux, BSD/MacOS, Windows?

Here is the shell script I wrote, only for Debian/RedHat based systems.

java_home:

#!/bin/sh
# Usage:
# java_home [JDK_VERSION]

get_home() {
  # get java_home from javac path
  printf %s\\n "${1%/bin/javac}"
}

query_javac() {
  {
    command "$__ALTERNATIVES" --query javac || return 1
  } | awk -v t="$1" \
    'BEGIN{p="^" toupper( substr( t, 1, 1 ) ) substr( t, 2 ) ":"}$0~p{print $2}'
}

# find the alternatives command for this system
for cmd in update-alternatives alternatives false; do
  __ALTERNATIVES=$(command -v "$cmd") && break
done

# If no version provided, return the home of the Best java version
java_home=$(
  if [ $# -eq 0 ]; then
    get_home "$(query_javac best)"
  else
    # Iterate the Alternative java versions
    query_javac alternative |
      while read -r javac; do
        # Read the version string returned by the javac command
        raw_javac_version=$(command "$javac" -version 2>&1)
        case $raw_javac_version in
          javac\ $1*)
            # Print the home of this javac version and exit
            get_home "$javac"
            exit
            ;;
        esac
      done
  fi
)

if [ -n "$java_home" ]; then
  printf %s\\n "$java_home"
else
  exit 1
fi

Example usage:

$ java_home 1.8
/usr/lib/jvm/java-8-openjdk-amd64

I am seeking a lighter, more standard, and more agnostic method of determining the Java home of specific JDK version.

CodePudding user response:

Is there a standard method to determine the JAVA_HOME, for a specific JDK version, in a fully system-agnostic way; be it Linux, BSD/MacOS, Windows?

As @Olivier noted, on Windows you can install a JDK anywhere. The same is true on Linux, and probably on MacOS too.

So given that the JDK could be installed anywhere, it will be impractical to try to find it. A truly system agnostic solution is impossible.

For example, your current approach will fail if javac is not on the command searchpath (i.e. $PATH), or if the user has installed a JRE rather than a JDK.


Is this really a problem?

Only if you call it a problem!

The pragmatic solution is:

  • Use a platform specific approach to finding the JDK; for example:

    • On Windows, use the registry to find the JDK
    • On Linux, use the alternatives mechanism and/or the default installation locations used by the distro's package manager or the OpenJDK RPMs.
    • On MacOS look in /Library/Java/JavaVirtualMachines. Or use the java_home tool.
  • If your best efforts don't find the JDK, throw the problem back to the person installing the application that needs a JDK or JRE:

    • Recommend a preferred way to install Java
    • Tell the user how to set up the environment variables by hand.

Or you could just make installing sdkman a prerequisite for your projects. (Except that sdkman is not in (for example) the Ubuntu or RedHat package repositories, and it probably won't play nice with the package manager's update mechanism.)


Note: deciding to call it a problem won't actually get you a solution. As I said, there is no system agnostic solution that will work in all circumstances. This is just a "wicked problem".

  • Related