Some time ago, I wrote an article about distributing Java command-line applications and how difficult it is to locate the proper java binary to run your application with. But let’s have a quick refresher on the problem before going further.

The Problem

When distributing a Java application via package managers, your application should rely on one of the Java Runtime Environments (a.k.a. JRE) provided by the package manager. Ensuring the correct JRE will be installed as a dependency of your application is the job of the package manager.

However, once installed, locating where is the JRE your application needs can be a daunting task. The JRE in the user’s $PATH may not match the required version, and the package manager might not provide consistent installation paths for the JREs nor a way to select one of them according to some criteria like the minimum or maximum Java version.

This got worse with Java’s frequent release cycle where new versions are published every six months. Each new version brings performance improvements, security enhancements, and feature additions, as well as deprecations and removals. It becomes vital to express which Java versions the application is compatible with.

This situation poses challenges for application developers, package maintainers, and end-users.

  • Developers need a convenient way to ensure their program runs with the correct JRE.

  • Package maintainers are reluctant to provide JRE selection mechanisms (not talking about system-wide mechanisms like /etc/alternatives here) as it is Java-specific and not their primary responsibility. On top of that, every single package manager would need such a mechanism.

  • End-users want a seamless experience without having to worry about which Java version is in their $PATH when they call your application.

findjava to the rescue

findjava is a powerful tool designed to alleviate these challenges and simplify the process of finding the most suitable JRE (but not only) to run your Java applications. It is licensed under the Apache-2.0 license.

It offers the following benefits:

JRE discovery

findjava scans a list of directories, files, and environment variables to discover installed JREs on the system. Those are configurable and typically would be tailored for each package manager.

JRE metadata extraction

Each discovered JRE is analyzed, and relevant metadata is extracted, providing valuable information about the JRE characteristics.

  • What Java specification version does it support?

  • Where is its java.home directory?

  • Is it providing additional tools like javac, native-image, …​?

JRE metadata are cached and invalidated when changes are detected (e.g., JRE updates, deletions, additions), ensuring efficient and up-to-date JRE information.

JRE filtering

findjava allows you to apply specific constraints when selecting the JRE, such as:

  • Minimum/maximum Java specification version implemented by this JRE

  • Desired programs part of this Java installation (e.g., java, javac, native-image)

  • The vendor of this JRE

Flexible output modes

The output mode of findjava is configurable. It can provide the path to the java.home directory of the selected JRE or directly the desired binary path.

System and application level configuration

JRE discovery and filtering can be configured at both the system and application levels.

  • System-level configuration allows package managers to control JRE selection. For example, only JREs implementing Java specifications 11 to 17 should be proposed.

  • Application-level configuration enables exceptions for specific use cases. For example, an application requires a JRE 16 or above.

findjava will try to satisfy the system-level preferences. If it is not possible due to some more restrictive constraints for the given application, then it will step out of the system-level restrictions.

For example, if a system has JREs 8, 11, and 20 installed and the system is configured to prefer a JRE in the 11 to 17 range., the following will happen:

  • findjava ⇒ 11 as it is in the preferred range.

  • findjava --min-java-version 11 ⇒ 11 as it is in the preferred range.

  • findjava --min-java-version 16 ⇒ 20 as available JREs in the preferred range are not satisfying the specific constraints of that JRE.

  • findjava --max-java-version 10 ⇒ 8 as available JREs in the preferred range are not satisfying the specific constraints of that JRE.

This mechanism allows package maintainers to provide a system-wide behavior to prefer their battle-tested JREs while allowing individual applications to still express additional constraints.

Going further

For more information, take a look at the findjava usage documentation.

Integration with package managers

findjava is currently available in external (i.e. non-official) package repositories:

Find out how to install it via the installation instructions

Call for help: Integration in official package managers

But for findjava to be useful for you to use in your application, it needs to be widely available and therefore integrated into official package managers for Linux, macOS, and at some point Windows.

I already started the process for Debian (#1039109), but I would need some Debian expert to move things forward.

If you are experienced in package manager integration or want to contribute in any capacity, your help is invaluable.

Contributing

Contributions of any kind to findjava are welcome! Feel free to open issues, submit pull requests, or join in the discussions on the GitHub repository.

Let’s work together to enhance the development, distribution, and user experience of Java applications!