JD-GUI on macOS

Why it fails to start and how to fix it

When trying to start JD-GUI on a recent macOS, you get the following error even if you have a version of Java installed:

I check several times, install Java 8, 12, ... but the error remains. So I decided to dig into this application and try to understand why it is failing. By right-clicking on the icon of the application and choose Show Package Contents, you can see the files inside the package. It contains one folder named Contents. This folder contains Info.plist with metadata about the application:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>CFBundleDevelopmentRegion</key>        <string>English</string>
        <key>CFBundleExecutable</key>               <string>universalJavaApplicationStub.sh</string>
        <key>CFBundleName</key>                     <string>JD-GUI</string>
        <key>CFBundleGetInfoString</key>            <string>JD-GUI version 1.6.6, Copyright 2008, 2019 Emmanuel Dupuy</string>
        <key>CFBundleIconFile</key>                 <string>jd-gui.icns</string>
        <key>CFBundleIdentifier</key>               <string>jd.jd-gui</string>
        <key>CFBundleInfoDictionaryVersion</key>    <string>6.0</string>
        <key>CFBundlePackageType</key>              <string>APPL</string>
        <key>CFBundleLongVersionString</key>        <string>1.6.6, Copyright 2008, 2019 Emmanuel Dupuy</string>
        <key>CFBundleShortVersionString</key>       <string>1.6.6</string>
        <key>CSResourcesFileMapped</key>            <true/>
        <key>LSRequiresCarbon</key>                 <true/>
        <key>NSHumanReadableCopyright</key>         <string>Copyright 2008, 2019 Emmanuel Dupuy</string>
        <key>NSPrincipalClass</key>                 <string>NSApplication</string>
        <key>NSHighResolutionCapable</key>          <true/>
        <key>CFBundleDocumentTypes</key>
        ...

The starting point of the application is given by the key CFBundleExecutable and is thus a script: universalJavaApplicationStub.sh. This script is located inside the MacOS folder and contains:

...

# first check system variable "$JAVA_HOME"
if [ -n "$JAVA_HOME" ] ; then
    JAVACMD="$JAVA_HOME/bin/java"

# check for specified JVMversion in "/usr/libexec/java_home" symlinks
elif [ ! -z ${JVMVersion} ] && [ -x /usr/libexec/java_home ] && /usr/libexec/java_home -F; then

    if /usr/libexec/java_home -F -v ${JVMVersion}; then
        JAVACMD="`/usr/libexec/java_home -F -v ${JVMVersion} 2> /dev/null`/bin/java"
    else
        # display error message with applescript
        osascript -e "tell application \"System Events\" to display dialog \"ERROR launching '${CFBundleName}'\n\nNo suitable Java version found on your system!\nThis program requires Java ${JVMVersion}\nMake sure you install the required Java version.\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1 with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)"
        # exit with error
        exit 3
    fi

...

So it checks the environment variable JAVA_HOME. Yes sure, my JAVA_HOME is not set as I use jenv. I could set it with something like export JAVA_HOME="$(jenv prefix)" in my .zshrc. Another solution is to use the Export plugin with jenv enable-plugin export. But it does not help much as the JAVA_HOME will not be set in the environment when starting the application from the Finder.

So what about the elif in the script? It checks that JVMVersion is set and that /usr/libexec/java_home is callable. Then it calls usr/libexec/java_home -F -v ${JVMVersion} to get the path of Java. The next question is where JVMVersionis coming from? It is initialized this way at the beginning of the script:

# set the default JVM Version to a null string
JVMVersion=""

and then it is set with:

    # read the Java version we want to find
    JVMVersion=`/usr/libexec/PlistBuddy -c "print ${JavaKey}:JVMVersion" "${InfoPlistFile}" 2> /dev/null | xargs`

In other terms, it reads the JVMVersion entry in the Info.plist file. So if we go back to Info.plist, we see:

    ....
        <key>JavaX</key>
        <dict>
            <key>MainClass</key>                    <string>org.jd.gui.OsxApp</string>
            <key>JVMVersion</key>                   <string>1.8+</string>
            <key>ClassPath</key>                    <string>$JAVAROOT/jd-gui-1.6.6-min.jar</string>
            <key>WorkingDirectory</key>             <string>$JAVAROOT</string>
            <key>Properties</key>
            <dict>
                <key>apple.laf.useScreenMenuBar</key>
                <string>true</string>
            </dict>
            <key>VMOptions</key>                    <string>-Xms512m</string>
        </dict>
        ....

and the value of JVMVersion is thus 1.8+. If we try ourself java_home with this value, we get:

/usr/libexec/java_home -F -v "1.8+"
The operation couldn’t be completed. Unable to locate a Java Runtime that supports (null).
Please visit http://www.java.com for information on installing Java.

But if we remove the "+" from "1.8+", we get:

/usr/libexec/java_home -F -v "1.8"
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

The syntax "1.8+" was once valid for java_home but it is no more accepted for quite some time. So how to solve this?

Modify Info.plist and set the version of Java you have installed, without the "+":

            <key>JVMVersion</key>                   <string>1.8</string>