Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I change Mac OS's default Java VM returned from /usr/libexec/java_home

I think JAVA_HOME is the best you can do. The command-line tools like java and javac will respect that environment variable, you can use /usr/libexec/java_home -v '1.7*' to give you a suitable value to put into JAVA_HOME in order to make command line tools use Java 7.

export JAVA_HOME="`/usr/libexec/java_home -v '1.7*'`"

But standard double-clickable application bundles don't use JDKs installed under /Library/Java at all. Old-style .app bundles using Apple's JavaApplicationStub will use Apple Java 6 from /System/Library/Frameworks, and new-style ones built with AppBundler without a bundled JRE will use the "public" JRE in /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home - that's hard-coded in the stub code and can't be changed, and you can't have two different public JREs installed at the same time.


Edit: I've had a look at VisualVM specifically, assuming you're using the "application bundle" version from the download page, and this particular app is not an AppBundler application, instead its main executable is a shell script that calls a number of other shell scripts and reads various configuration files. It defaults to picking the newest JDK from /Library/Java as long as that is 7u10 or later, or uses Java 6 if your Java 7 installation is update 9 or earlier. But unravelling the logic in the shell scripts it looks to me like you can specify a particular JDK using a configuration file.

Create a text file ~/Library/Application Support/VisualVM/1.3.6/etc/visualvm.conf (replace 1.3.6 with whatever version of VisualVM you're using) containing the line

visualvm_jdkhome="`/usr/libexec/java_home -v '1.7*'`"

and this will force it to choose Java 7 instead of 8.


I've been there too and searched everywhere how /usr/libexec/java_home works but I couldn't find any information on how it determines the available Java Virtual Machines it lists.

I've experimented a bit and I think it simply executes a ls /Library/Java/JavaVirtualMachines and then inspects the ./<version>/Contents/Info.plist of all runtimes it finds there.

It then sorts them descending by the key JVMVersion contained in the Info.plist and by default it uses the first entry as its default JVM.

I think the only thing we might do is to change the plist: sudo vi /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Info.plist and then modify the JVMVersion from 1.8.0 to something else that makes it sort it to the bottom instead of the top, like !1.8.0.

Something like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    ...
    <dict>
            ...
            <key>JVMVersion</key>
            <string>!1.8.0</string>   <!-- changed from '1.8.0' to '!1.8.0' -->`

and then it magically disappears from the top of the list:

/usr/libexec/java_home -verbose
Matching Java Virtual Machines (3):
    1.7.0_45, x86_64:   "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home
    1.7.0_09, x86_64:   "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_09.jdk/Contents/Home
    !1.8.0, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home

Now you will need to logout/login and then:

java -version
java version "1.7.0_45"

:-)

Of course I have no idea if something else breaks now or if the 1.8.0-ea version of java still works correctly.

You probably should not do any of this but instead simply deinstall 1.8.0.

However so far this has worked for me.


It's actually pretty easy. Let's say we have this in our JavaVirtualMachines folder:

  • jdk1.7.0_51.jdk
  • jdk1.8.0.jdk

Imagine that 1.8 is our default, then we just add a new folder (for example 'old') and move the default jdk folder to that new folder. Do java -version again et voila, 1.7!


I actually looked at this a little in the disassembler, since source isn't available.

/usr/bin/java and /usr/libexec/java_home both make use of JavaLaunching.framework. The JAVA_HOME environment variable is indeed checked first by /usr/bin/java and friends (but not /usr/libexec/java_home.) The framework uses the JAVA_VERSION and JAVA_ARCH envirionment variables to filter the available JVMs. So, by default:

$ /usr/libexec/java_home -V
Matching Java Virtual Machines (2):
    11.0.5, x86_64: "Amazon Corretto 11"    /Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home
    1.8.0_232, x86_64:  "Amazon Corretto 8" /Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home

/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home

But setting, say, JAVA_VERSION can override the default:

$ JAVA_VERSION=1.8 /usr/libexec/java_home
/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home

You can also set JAVA_LAUNCHER_VERBOSE=1 to see some additional debug logging as far as search paths, found JVMs, etc., with both /usr/bin/java and /usr/libexec/java_home.

In the past, JavaLaunching.framework actually used the preferences system (under the com.apple.java.JavaPreferences domain) to set the preferred JVM order, allowing the default JVM to be set with PlistBuddy - but as best as I can tell, that code has been removed in recent versions of macOS. Environment variables seem to be the only way (aside from editing the Info.plist in the JDK bundles themselves.)

Setting default environment variables can of course be done through your .profile or via launchd, if you need them be set at a session level.


It's pretty simple, if you don't mind rolling up your sleeves... /Library/Java/Home is the default for JAVA_HOME, and it's just a link that points to one of:

  • /System/Library/Java/JavaVirtualMachines/1.?.?.jdk/Contents/Home
  • /Library/Java/JavaVirtualMachines/jdk1.?.?_??.jdk/Contents/Home

So I wanted to change my default JVM/JDK version without changing the contents of JAVA_HOME... /Library/Java/Home is the standard location for the current JVM/JDK and that's what I wanted to preserve... it seems to me to be the easiest way to change things with the least side effects.

It's actually really simple. In order to change which version of java you see with java -version, all you have to do is some version of this:

cd /Library/Java
sudo rm Home
sudo ln -s /Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home ./Home

I haven't taken the time but a very simple shell script that makes use of /usr/libexec/java_home and ln to repoint the above symlink should be stupid easy to create...

Once you've changed where /Library/Java/Home is pointed... you get the correct result:

cerebro:~ magneto$ java -version
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27) Java HotSpot(TM)
64-Bit Server VM (build 25.60-b23, mixed mode)