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
Hi,

I hope you'll do an updated release of gmao. I used it for a few projects in the past (8-10 years ago, I suppose) and I haven't found any software with as good a workflow since, even for purely local stuff. Unfortunately I ran into some quirks with later versions of java (might've been linux specific), so I had to stop using it. I miss it a lot and it would be awesome if a new version were released.

Nice writeup by the way.

Posted 1 week, 5 days ago by Anonymous • • • Reply

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.