I am testing my current application with Mac OS X which has Java 7 from Oracle installed. Instead using Java 7 from Oracle, it's using Java 6 from Apple. The default system output of java -version
is showing 7
.
I tried most of the things mentioned in different sites, but I was unable to fix this issue.
JAVA_HOME
is also properly set.
I am using the Mac only for testing purposes. I really need some guidance on this.
When I run it with Eclipse by selecting JRE 7, it runs properly. Thus there is nothing wrong with the application. I am missing something on Mac OS X.
My Java system environment looks like this:
OS X version
10.8
/usr/libexec/java_home -V
Matching Java Virtual Machines (3):
1.7.0_12, x86_64: "Java SE 7" /Library/Java/JavaVirtualMachines/jdk1.7.0_12.jdk
1.6.0_37-b06-434, x86_64: "Java SE 6" /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
1.6.0_37-b06-434, i386: "Java SE 6" /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
/Library/Java/JavaVirtualMachines/jdk1.7.0_12.jdk/Contents/Home
/usr/libexec/java_home
/Library/Java/JavaVirtualMachines/jdk1.7.0_12.jdk/Contents/Home
echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/jdk1.7.0_12.jdk/Contents/Home/
JAVA_ARCH
is not set
/Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java -version
java version "1.7.0_12-ea"
ls /Library/Java/JavaVirtualMachines
jdk1.7.0_12.jdk
/System/Library/Frameworks/JavaVM.framework/Commands/java -version
java version "1.6.0_37"
I guess my current JDK is pointing to something wrong.
Your Mac OS X application bundle has been created with an app bundler which is not compatible with Oracle's Java 7 package. The bundler you were using could be, for example, Jar Bundler
provide by Apple which only works for Apple's Java 6 System Packages.
Apple has given up support for Java as an integrated System Packages from Java 7 and later. As a consequence you have to go for the Oracle Java 7 Third Party package and their application package bundle solution. This allows you to create and deploy Oracle Java 7 based application bundles on Mac OS X 10.7.3 and onwards.
The underlying technical issue you are facing is Apple's native Objective-C
based JavaAppLauncher
binary and the format it uses in Info.plist
is only working with Apple's Java 6 System Packages and the JavaAppLauncher
Info.plist
combination coming from Oracle is only working for Oracle's Java 7 Packages.
As you are using a JavaAppLauncher
supporting Apple's Java 6 System Packages, it will always pick up the Apple Java 6 System Package installed on your Mac.
There is a video, where Scott Kovatch, the lead engineer for the Mac OS X port of the Java platform at Oracle is talking on DEVOXX about how app bundling for Oracle Java 7 is working in great detail.
To create app bundles based for Mac OS X 10.7.3 and onwards based on
and above, you have to use Oracle's app bundler
lib/appbundler-1.0.jar
containing the Ant Task com.oracle.appbundler.AppBundlerTask
With Oracle's app bundler you have now the choice to run your packaged app with the default Oracle Java 7 Package installed on your Mac here:
/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/
or the Oracle Java 7 JRE you inline in your packaged application
MyJavaMacOSXApp.app/Contents/PlugIns/
Note: There are pros and cons for both approaches, but you need the last one with your own JRE if you want to go to the Apple App Store with your bundled app.
appbundler-1.0.jar
and move it to <project>/lib/appbundler-1.0.jar
Add the following to your <project>/build.xml
<property environment="env" />
<taskdef
name="bundleapp"
classname="com.oracle.appbundler.AppBundlerTask"
classpath="lib/appbundler-1.0.jar" />
<target name="bundle">
<bundleapp
outputdirectory="dist"
name="MyJavaMacOSXApp"
displayname="My Java Mac OS X App"
identifier="com.example.MyJavaMacOSXApp"
shortversion="1.0"
applicationCategory="public.app-category.developer-tools"
mainclassname="com.example.MyJavaMacOSXApp">
<runtime dir="${env.JAVA_HOME}" />
<classpath file="dist/MyJavaMacOSXApp.jar" />
</bundleapp>
</target>
Note: You need to replace MyJavaMacOSXApp
with your application data. You can find here some additional AppBundlerTask
options, as this example shows only how how it works in its simplest form.
After you run the bundle
target with ant bundle
you will find MyJavaMacOSXApp.app
in the <project>/dist
directory.
<runtime dir="${env.JAVA_HOME}" />
element?Inlining Oracle Java 7 Package (JRE)
The Ant target above copies the Oracle Java 7 Package (JRE) from your
JAVA_HOME
into
MyJavaMacOSXApp.app/Contents/PlugIns
So the application package is totally self contained and does not need an Oracle Java 7 Package (JRE) installed on the target system at all. Like you can see in the following screen shot of such a deployed MyJavaMacOSXApp.app
:
Wiring default Oracle Java 7 Package (JRE)
If you want to use the default Oracle Java 7 Package (JRE) installed on the application bundle target Mac under
/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/
you have to remove the
<runtime dir="${env.JAVA_HOME}" />
element fromt the bundle
task. Like you can see in the following screen shot of such a deployed MyJavaMacOSXApp.app
:
Source of MyJavaMacOSXApp.java
package com.example;
import java.awt.*;
import javax.swing.*;
public class MyJavaMacOSXApp extends JPanel {
public MyJavaMacOSXApp() {
JLabel versionLabel = new JLabel("java.version=" + System.getProperty("java.version"));
JLabel homeLabel = new JLabel("java.home=" + System.getProperty("java.home"));
setLayout(new BorderLayout());
add(versionLabel, BorderLayout.PAGE_START);
add(homeLabel, BorderLayout.PAGE_END);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("MyJavaMacOSXApp");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyJavaMacOSXApp newContentPane = new MyJavaMacOSXApp();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
Just add as many <classpath file="dist/additional.jar" />
entries as you need.
Note: The order of elements in the bundle task isn't preserved at runtime of your bundled app. The java.class.path
gets built up at runtime by the native JavaAppLauncher
as it reads in the *.jar
s from MyJavaMacOSXApp.app/Contents/Java
directory.
Just for completeness, this is how Info.plist
looks like:
<?xml version="1.0" ?>
<!DOCTYPE plist PUBLIC "-//Apple//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>JavaAppLauncher</string>
<key>CFBundleIconFile</key>
<string>GenericApp.icns</string>
<key>CFBundleIdentifier</key>
<string>com.example.MyJavaMacOSXApp</string>
<key>CFBundleDisplayName</key>
<string>My Java Mac OS X App</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MyJavaMacOSXApp</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSHumanReadableCopyright</key>
<string></string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>JVMRuntime</key>
<string>jdk1.7.0_17.jdk</string>
<key>JVMMainClassName</key>
<string>com.example.MyJavaMacOSXApp</string>
<key>JVMOptions</key>
<array>
</array>
<key>JVMArguments</key>
<array>
</array>
</dict>
</plist>
Important documents this answer is based on:
There is also a well maintained fork of appbundler itself, with many more features and bugfixes.