How can I change Mac OS's default Java VM returned from /usr/libexec/java_home
Solution 1
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.
Solution 2
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.
Solution 3
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!
Solution 4
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.
Solution 5
I tested "jenv" and other things like setting "JAVA_HOME" without success. Now I ended up with following solution:
function setJava {
export JAVA_HOME="$(/usr/libexec/java_home -v $1)"
launchctl setenv JAVA_HOME $JAVA_HOME
sudo ln -nsf "$(dirname ${JAVA_HOME})/MacOS" /Library/Java/MacOS
java -version
}
(added to ~/.bashrc or ~/.bash.profile or ~/.zshrc)
And calling like that:
setJava 1.8
java_home will handle the wrong input. So you can't do something wrong. Maven and other stuff will pick up the right version now.
Christopher Schultz
A Human Apache Software Foundation Member Apache Tomcat Committer (Committer, PMC) Apache Velocity Committer
Updated on August 14, 2021Comments
-
Christopher Schultz over 2 years
(Wasn't sure if this should go on SU... migration is certainly an option, but more programmers read questions here, so here goes).
I am running Mac OS X 10.8.4, and I have Apple's JDK 1.6.0_51 installed as well as Oracle's JDK 1.7.0_25. I recently installed Oracle's 1.8 preview JDK for some pre-release software that requires it. Now, when I run /usr/libexec/java_home, I get this:
$ /usr/libexec/java_home -V Matching Java Virtual Machines (4): 1.8.0, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home 1.7.0_25, x86_64: "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home 1.6.0_51-b11-457, x86_64: "Java SE 6" /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home 1.6.0_51-b11-457, i386: "Java SE 6" /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
Great.
However, running:
$ java -version
Returns:
java version "1.8.0-ea"
That means that the default version of Java is currently the pre-release version, which breaks some "normal" packages (in my case, VisualVM).
I can't set
JAVA_HOME
because launching applications ignores environment variables, even when launching from the command line (e.g.$ open /Applications/VisualVM.app
).So, is there a file I can edit where I can set my JVM ordering preferences globally?
(Please don't tell me to launch the Java Preferences Panel because that simply does not work: it does not contain anything useful and only lists one of the 4 JVMs that I have installed.)
Update:
Oracle JVMs live in
/Library/Java/JavaVirtualMachines
. Re-naming the JDK 1.8 directory tojdk1.8.0.jvm.xyz
does not change anything:java_home
still finds it in the right place, and running /usr/bin/java still executes the 1.8 JVM. This is not an issue with synlinks, etc.Answers to Similar Questions
While this answer offers what amounts to a hack that will remove versions of Java from being picked up by java_home, it still does not answer this question of how java_home chooses its default and whether or not users can non-destructively set it.
-
Christopher Schultz almost 11 yearsThis does not appear to be the case on my system. Launching VisualVM before JDK 1.8 was installed worked. After JDK1.8, VisualVM shows the splash screen, then dies. Moving the JDK1.8 directory out of /Library/Java restores its ability to run.
-
Ian Roberts almost 11 years@ChristopherSchultz I've had a look inside the VisualVM bundle and it turns out it's not a normal appbundler application. See my edit for a possible workaround.
-
Christopher Schultz almost 11 yearsSorry, I wrote my previous comment before your edit. I'll check-out getting VisualVM to run using that technique, but it's unlikely to be universally-applicable. I have a bunch of other Java-based software tat I run as well like Eclipse, JasperReports iReport, etc. that are all likely to be affected by this. I think I'd rather just move the JDK1.8 directory somewhere else and use that explicitly with JAVA_HOME for the (few) times that I actually need it.
-
Christopher Schultz over 10 yearsThis question wasn't about un-installation... it was about choosing the "primary" JVM from those one has installed...
-
Christopher Schultz over 10 yearsBad advice: modifying the startup script for a particular application will likely break the application and does not solve the original problem of changing the default JVM for the OS.
-
Celandro over 10 yearsUnfortunately as mentioned by others, jvisualvm does not use standard methods for choosing a jvm. This is the only solution for this app.
-
Ian Roberts over 10 yearsAs I state in my answer you don't need to modify anything inside the application bundle itself, the app can load its configuration from
~/Library/Application Support/VisualVM/1.3.6/etc/visualvm.conf
. -
andrewdotn over 10 yearsYup, you’re right,
JAVA_HOME
is the way to go and in general your best bet is to specify the minor version you need in other cases. Based on disassembly, it turns out you canexport JAVA_VERSION=1.7
to makejava_home
default to showing JKD7 instead of JDK8, but that breaksjava_home -v 1.6
becausejava-home
interprets it as an additional constraint and gives up due to mutually unsatisfiable constraints, then just goes with the default 1.8 even with the--failfast
option. -
antoine over 10 yearsThis worked for me. I have had to use this tweak to keep the Idea Sbt plugin working for me on MacOS. I am mentioning it on my blog agilebuild.blogspot.com/2014/02/…
-
Christopher Schultz about 10 yearsThis will not work when launching VisualVM from Launchpad. Launching from the command-line is never a problem, as you can set the JAVA_HOME environment variable.
-
Christopher Schultz about 10 yearsDoes not answer the question: it will not affect the behavior of
/usr/libexec/java_home
. -
Christopher Schultz almost 10 yearsAnything that relies on environment variables will not work. The point is that applications launched via LaunchPad, etc. won't have that environmental setup. The plist hack above seems like the "best" one in that it actually achieves the desired result. I'm not sure about any downsides, yet. See the answer from @Tony which has the same problem.
-
JGFMK over 9 yearsI can't understand why the System Preferences Java Control Panel doesn't just present a list to select from, rather than have to resort to shell scripts/commands. I suspect this is just for Applets that run in the browser...
-
Weibo Li over 9 yearsThis works but it seems a little tricky and might not look like a standard operation procedure. I wander if there is a better approach.
-
Christopher Schultz over 9 yearsFunny... I thought Apple had removed Java altogether at this point. I don't remember manually removing Apple's Java 1.6 JVM, and it's definitely no longer here. At any rate, this doesn't really fix the original problem which was to specify the preferred JVM given a selection that have been installed.
-
Mo'in Creemers over 9 yearsYou are correct. It doesn't answer the question. It does answer this: If you remove the JVM being used, the 'next' one in the list is used. Maybe that helps.
-
David Resnick over 9 yearsI would still like a solution for this, but for setting the JDK for Intellij to use I added this to my zshenv: export IDEA_JDK=
/usr/libexec/java_home -v 1.7
. I think I'll do the same for JAVA_HOME... -
Jack over 9 years@IanRoberts Hi, I have similar issue in bundling my Java application, I would be grateful if you could have a look at my question as well, thanks stackoverflow.com/questions/28207295/…
-
whyoz over 9 yearsdoes this explain why after running a jdk 8 install, it doesn't show up in the JavaVirtualMachines folder? All I see is "1.6.0.jdk" no matter what version I install.
-
Mo'in Creemers over 9 years@whyoz Just installed jdk-8u31-macosx-x64 on osx 10.10.2 and the VM was installed in the JavaVirtualMachines folder as expected.
-
whyoz over 9 yearsAre you running Parallels by chance? I installed it on the Windows side of Parallels and 8u31 installed as expected..just not on the Mac side..
-
Christopher Schultz over 8 yearsThis isn't how this stuff works:
/Library/Java/Home
is indeed a symlink, but it points to/System/Library/Frameworks/JavaVM.framework/Home
which itself is in a big jumble of symlinks that finally gets you to ... a magical command that determines the right JRE to launch. Note that/usr/libexec/java_home
also links into this magic. So, you can interrupt everything by just replacing symlinks and pointing to a single JRE, but you'll have to update that every time. There is evidently no command likeset_preferred_jvm_version
or something similar. -
Christopher Schultz over 8 yearsThe advantage of this technique, though, is that it does not require you to set
JAVA_HOME
anywhere. I'll play with this technique to see if it will result in Java-based programs launching with the "preferred" Java VM. I suspect it will, but it's pretty fragile. -
Nicolas Henneaux over 6 yearsI manage to use this answer to avoid using Java 9 launching double-click applications (due to an issue in Keystore Store explorer). Thanks!
-
Jeremy Kao almost 6 yearsAn excerpt from Installation of the JDK and the JRE on macOS: After installing Java for macOS 2012-006,
/usr/bin/java
will find the newest JDK installed, and will use that for all of the Java-related command-line tools in/usr/bin
. -
Mike Ryan over 5 yearsWell, you're on to something! Of course, it'd be great to know if there is a way to do this in a way that the designers of the java_home executable intended. You know, like real documentation rather than the incredibly terse output of java_home -help. Sadly, it looks like java_home simply doesn't offer this functionality.
-
Michał Dobi Dobrzański almost 5 yearsUnbelievable, but it worked... Thanks Mac OS Mojave
-
Christopher Schultz over 4 yearsThis is great information, Dan. Using
.profile
isn't useful for my use-case (launching an application from e.g. launchpad) but the tip onlaunchd
is a good one. I'll have to give that a try, since Java's recent versioning madness means that I have several generations of Java installed simultaneously, with varying levels of (personal) trust. -
jrypkahauer over 4 yearsWell these days I just have this in
.bash_profile
:export JAVA_HOME=`/usr/libexec/java_home -v 12`
-
Christopher Schultz over 4 yearsThis doesn't work for double-clicking on an icon, which was kind of the whole point. Solutions which only work from the command-line are ... not solutions.
-
Greg Fenton over 3 yearsThis is great! I am running a slightly convoluted Eclipse setup and have several JDKs installed. So I just created a different BASH script for each Eclipse config I need that simply has the line: "JAVA_VERSION=1.8 /Applications/Eclipse.app/Contents/MacOS/eclipse &"
-
bompf about 2 yearsIt seems like the tool also checks
~/Library/Java/JavaVirtualMachines
for the currently logged in user.