Skip to content

Instantly share code, notes, and snippets.

@peterkir
Forked from hogmoru/MultipleJDKsOnMacOS.md
Created November 16, 2017 08:19
Show Gist options
  • Save peterkir/6dd690b99fa3ec0274cd7f6b750563f7 to your computer and use it in GitHub Desktop.
Save peterkir/6dd690b99fa3ec0274cd7f6b750563f7 to your computer and use it in GitHub Desktop.

Technical details for https://stackoverflow.com/a/44169445/6730571

Details of investigation:

On a base system, /usr/bin/java is a symlink that points to /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java, which is an Apple wrapper tool that locates and executes the actual java.

(Do not touch anything in those 2 system directories. It should actually be impossible due to "System Integrity Protection" anyway.)

If you don't have Java installed, attempting to execute java will open a dialog that invites you to install it.

If you install a JDK from Oracle or OpenJDK pkg download, it goes to /Library/Java/JavaVirtualMachines (1), and java will find it.

When you have several of them, you can use /usr/libexec/java_home as explained in other answers to help set $JAVA_HOME for current shell.

If $JAVA_HOME is set, and points to a valid JDK, Apple's java wrapper will use it.

But how do we chose the default version, the one that executes without setting $JAVA_HOME?

The old "Java Preferences pane" used to allow exactly that, but it does not exist anymore since 10.8.2.

By default, it seems the wrapper checks all JREs under /Library/Java/JavaVirtualMachines (2) and runs the one with highest version (3).

I don't want that, if the latest is too "cutting edge" (e.g. JDK9 at the moment breaks groovyConsole & other tools).

So, for example, to exclude JDK9 from consideration by system java wrapper, rename /Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Info.plist to Info.plist.disabled.

(Editing the file also works, if you know how to convert to xml with plutil, the relevant key is JVMVersion: when I changed it from 9 to -9 or anything that is lower than 1.8.0_131 it was considered "lower" by the wrapper).

As far as I can tell it does not affect anything else. Yes, if I point $JAVA_HOME to that JDK9 it does still work.

There might be an undocumented way to configure this (old versions used to read $HOME/Library/Preferences/java_home.plist but that does not seem to be the case anymore).

(To be continued... ?)


Annex

(1) And also overwrites /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/. Apparently this is the one that the new Preferences pane will launch -- this is the only exception I found to my solution: that thingy will still use JDK9 (latest I installed), but no other Java application does.


(2) To find this I used opensnoop and followed what happened when executing java -version. That gave clues about which files to check, and upon investigating I found that I was not alone :) Lots of clues, but sadly no exploitable conclusion on that page. I think the guy was using a pre-ElCapitan macOS.

Also used "verbose" mode for java launcher:

$ JAVA_LAUNCHER_VERBOSE=true java -version
2017-05-24 23:15:14.064 java[15602:731042] [JVM Detection] AddJVMsFromLibraryPath: Scanning: file:///Users/asmithee/Library/
2017-05-24 23:15:14.065 java[15602:731042] [JVM Detection] AddJVMsFromLibraryPath: Scanning: file:///Users/asmithee/Developer/
2017-05-24 23:15:14.065 java[15602:731042] [JVM Detection] AddJVMsFromLibraryPath: Scanning: file:///Library/
2017-05-24 23:15:14.066 java[15602:731042] [JVM Detection] AddJVMsFromSampledFile: Checking for a JVM at: libjli.dylib -- file:///Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/MacOS/
2017-05-24 23:15:14.066 java[15602:731042] [JVM Detection] Match: Could not find constraint for JVMMaximumSystemVersion
2017-05-24 23:15:14.066 java[15602:731042] [JVM Detection] Match: Could not find constraint for JVMMaximumFrameworkVersion
2017-05-24 23:15:14.066 java[15602:731042] [JVM Detection] AddJVMsFromSampledFile: JVM has capabilities: (
    CommandLine
)
2017-05-24 23:15:14.067 java[15602:731042] [JVM Detection] AddJVMsFromSampledFile: Checking for a JVM at: libjli.dylib -- file:///Library/Java/JavaVirtualMachines/jdk1.8.0_74.jdk/Contents/MacOS/
2017-05-24 23:15:14.067 java[15602:731042] [JVM Detection] Match: Could not find constraint for JVMMaximumSystemVersion
2017-05-24 23:15:14.069 java[15602:731042] [JVM Detection] Match: Could not find constraint for JVMMaximumFrameworkVersion
2017-05-24 23:15:14.070 java[15602:731042] [JVM Detection] AddJVMsFromSampledFile: JVM has capabilities: (
    CommandLine
)
2017-05-24 23:15:14.070 java[15602:731042] [JVM Detection] AddJVMsFromLibraryPath: Scanning: file:///Developer/
2017-05-24 23:15:14.070 java[15602:731042] [JVM Detection] AddJVMsFromLibraryPath: Scanning: file:///System/Library/
2017-05-24 23:15:14.070 java[15602:731042] [JVM Detection] AddJVMsFromLibraryPath: Scanning: file:///Developer/
available JVMs:
    1.8.0_131, x86_64:	"Java SE 8"	/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home
    1.8.0_74, x86_64:	"Java SE 8"	/Library/Java/JavaVirtualMachines/jdk1.8.0_74.jdk/Contents/Home

obtained version: "1.8.0_131"
set preferred architecture to: "x86_64"
about to exec: "/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home"
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment