JAVA_HOME and Mac OS X

by Robert M. Johnson - Sun 22 May 2016
Tags: #Mac

The purpose of this article is to illuminate how Java is installed and accessed on Mac OS X 10.5 versions and later. If you execute which java this will output /usr/bin/java.

This is not where Java resides, it is a symbolic link to /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java

And confusingly enough, this is also not where Java resides. Files contained in /System tend to be Apple specific and not 3rd party. The second clue, as pointed out by Stack Overflow user bdash [1], are files in: /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands are on the order of 10 bytes in size. The real Java executable is bigger than that!

Dynamic Tracing

bdash gives the following command to run: sudo dtrace -n 'syscall::posix_spawn:entry { trace(copyinstr(arg1)); }' -c "/usr/bin/java -version"

This outputs:

dtrace: description 'syscall::posix_spawn:entry' matched 1 probe dtrace: pid 712 has exited CPU ID FUNCTION:NAME 0 629 posix_spawn:entry /Library/Java/JavaVirtualMachines/jdk1.7.0_65.jdk/Contents/Home/bin/java

This suggests the Java program resides in

/Library/Java/JavaVirtualMachines/jdk1.7.0_65.jdk/Contents/Home/bin/java

and is indeed correct. Also, to confirm that I have one JDK version, I observe that my directory /Library/Java/JavaVirtualMachines only contains one directory named jdk1.7.0_65.jdk Multiple JDK versions are allowed and will reside in /Library/Java/JavaVirtualMachines/

The next question is, how are multiple versions managed? And the answer is java_home

Java Home

Since Mac OS X 10.5, Apple has provided a tool called java_home. Its function is to dynamically find the Java version a user specifies in Java Preferences [2]. It returns the home path of the current JDK in use. I run this program with help flag:

/usr/libexec/java_home --help

And discover the --verbose flag. It tells me the full list of JVM architectures I have on my machine. When I run this with this flag on my machine (Macbook OS X 10.10.3) I get the following output:

Matching Java Virtual Machines (1): 1.7.0_65, x86_64: "Java SE 7" /Library/JavaVirtualMachines/jdk1.7.0_65.jdk/Contents/Home

This confirms what I observed earlier in /Library/Java/JavaVirtualMachines, that I only have one JDK version. Just like /usr/bin/java, java_home is a symbolic link to a file that resides in:

/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands

By the way, /usr/libexec is supposed to a folder that contains binaries meant to be run by other programs (i.e., not users) [3].

Java Applet

There's one last Java version sitting around that should be explained as well. Consider:

/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java

It's not a symbolic link nor a binary that redirects to another file. What is it? The path makes it clear: it's used by Safari when it executes a Java applet. On my machine, it has a newer build. It's a JRE and to the best of my knowledge, it only allows one JRE version to be installed.

JAVA_HOME

Now that we better understand how Java is accessed on the Mac, we'd like to set the environmental variable JAVA_HOME. Modify your ~/.bash_profile file:

JAVA_HOME=$(/usr/libexec/java_home) PATH=$PATH:$JAVA_HOME/bin export JAVA_HOME

Using java_home instead of hard-coding a path, will return the path of the Java home directory. We add it to our path variable and finally, export the JAVA_HOME for use as an environmental variable

As a final note, apparently for versions earlier than 10.5, Apple recommends using the fixed path of /Library/Java/Home [2].

Comments