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 JVMVersion
is 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>