April 20, 2015

Packaging up a Java application on OSX with recent versions of Java

So, I've started hacking on a very, very old project of mine that is a Swing-based Java application. I got it running again on OSX but things have changed a lot since I last was doing much coding on it. It used to be that Apple vended Java for OSX, but now Oracle does, and the way that you package up a Java application as an OSX application has changed.

Oracle has some documentation on how to package up an application, but I have to admit that it took me a lot longer than it should have to get this to work. First, Oracle distributes an Ant task for packaging the JAR. I don't use Ant for my project. Actually, I don't remember how I was packaging up the application before. I think I just hand-crafted some directories and dropped an Info.plist file in there that worked.

I was a bit intimidated by that, but it does look like someone has done things by hand. This also looked pretty complicated.

So I ended up installing ant. I had previously installed homebrew on my machine, so that was as simple as "brew install ant". Then I needed to put together a build.xml. I know a bit about that, but not much. I use eclipse for this project, but haven't done anything smart with how it is set up. It just uses the default java builder. I think I even have it set up to put the compiled code in the existing directory structure with the Java files. Not really great. Anyway, I made a simple build.xml that pulls in the libraries I need and some other resources. When I tried to run the resulting application though, I get a failure:

LSOpenURLsWithRole() failed with error -10810

That was not helpful. Running from the command line didn't help, just output that error. Running via java -jar did help though: it couldn't find some classes it needed. Oh, right, I need to set the classpath in the Manifest file. So if you get that error, check to see if your classpath is set correctly. Remember that when you run something via -jar, the -classpath option is completely ignored, and it takes the classpath from the JAR's manifest file. Here is what my final build.xml looked like:

<project name="GMAO" default="bundle-GMAO" basedir=".">        
    <taskdef name="bundleapp"
             classname="com.oracle.appbundler.AppBundlerTask"   
             classpath="../GMAO_libs/appbundler-1.0.jar" />
    <!-- See the lib reference here, this is why you need to use the lib directory! -->

	<path id="build.classpath">
	  <fileset dir="${basedir}">
	     <include name="lib/*.jar"/>
	  </fileset>
	</path>

	<pathconvert property="manifest.classpath" pathsep=" ">
	  <path refid="build.classpath"/>
	  <mapper>
	    <chainedmapper>
	       <flattenmapper/>
	       <globmapper from="*.jar" to="*.jar"/>
	    </chainedmapper>
	  </mapper>
	</pathconvert>
	
	<target name="create-jar" description="Create GMAO Jar">
		<jar destfile="GMAOGUI.jar" basedir="." includes="**/**.class,../common/**/**.class,images/**,docs/**,*html,*xml,*xsl">
			<manifest>
				<attribute name="Main-Class" value="com.FuguTabetai.GMAO.GMAOGUI"/>
				<attribute name="Class-Path" value="${manifest.classpath}"/>
			</manifest>
		</jar>
	</target>
	
    <target name="bundle-GMAO" depends="create-jar">
        <delete dir="appBundle" failonerror="false"/>
        <mkdir dir="appBundle"/>
    	<echo message="JAVA_HOME is set to = ${java.home}" />
        <bundleapp outputdirectory="appBundle"
            name="GMAO"
            displayname="GMAO"
            identifier="com.FuguTabetai.GMAO.GMAOGUI"
            mainclassname="com.FuguTabetai.GMAO.GMAOGUI"
        	icon="images/GMAOGUI.icns">
        	<runtime dir="${java.home}/.."/>
        	<option value="-Dswing.volatileImageBufferEnabled=false"/>
            <!-- The following is important and should point to your build -->
            <classpath file="GMAOGUI.jar" />
            <!-- You can have multiple instance of classpath if you 3rd party or
                 dependent jars in different locations -->
        	<classpath file="lib/TableLayout.jar" />
        	<classpath file="lib/commons-logging-1.2.jar" />
        	<classpath file="lib/helpgui-1.1.jar" />
        	<classpath file="lib/jcommon-0.7.0.jar" />
        	<classpath file="lib/jfreechart-0.9.3.jar" />
			<classpath file="lib/jnlp.jar" />
    		<classpath file="lib/skinlf.jar" />
    		<classpath file="lib/swingfx.jar" />
    		<classpath file="lib/xnap-commons-0.9.5.jar" />
        	<classpath file="lib/xpp3_min-1.1.3.4.0.jar" />
        	<classpath file="lib/xstream-1.2.jar" />
        	<classpath file="lib/gmao_common.jar" />
        </bundleapp>
    </target>
</project>
The Appbundler documentation was useful in adding some additional properties. I know that the build.xml could be better, and I'll probably improve it, but I wanted to note it here because I know in a few years I will want to figure out why I did this.


Comments

Provide your email address when commenting and Gravatar will provide general portable avatars, and if you haven't signed up with them, a cute procedural avatar with their implementation of Shamus Young's Wavatars.

Re: Packaging up a Java application on OSX with recent versions of Java
Of course, not too long after figuring this out there was a discussion on the java-dev@lists.apple.com mailing list about how to package up an application. It looks like there is another way that seems more supported than the appbundler approach. Here is a great summary message from David DeHaven:

Now I have more time for a better answer... :)

I mention it because it's actively developed and supported by Oracle and specifically builds application bundles for MAS. We have online documentation on using it [1] as well as a man page [2]

You'll want to use the latest possible JDK to create app bundles as MAS distribution is a moving target and we have to keep chasing it around, older releases may not work.

The maintainers are on openjfx-dev [3] and are generally responsive unless on vacation or traveling.

-DrD-

[1] https://docs.oracle.com/javase/8/docs/technotes/guides/deploy/self-contained-packaging.html
[2] https://docs.oracle.com/javase/8/docs/technotes/tools/unix/javapackager.html
[3] http://mail.openjdk.java.net/mailman/listinfo/openjfx-dev
Posted 3 weeks, 2 days ago by FuguTabetai • • wwwReply

Add Comment

( to reply to a comment, click the reply link next to the comment )

 
Comment Title
 
Your Name:
 
Email Address:
Make Public?
 
Website:
Make Public?
 
verification image
Image verification:
 
Comment:

Allowed XHTML tags : a, b, i, strong, code, acrynom, blockquote, abbr. Linebreaks will be converted automatically.