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
Dear FuguTabetai.com

Nice to talk to you.
My name is Yuta Sugawara.

How are you doing?
I hope you are doing well.

Currently, I live and work in Tokyo.
First, sorry to message you all of a sudden.

I'm here to ask your permission to use your blog content on our Facebook page.

We made a Facebook page for conveying the allure of Japan to those who don't know about Japan.
At this point, we have about 20,000 fans from all over the world on our Facebook page.
Since we are going turn it into a web service with its own site at the end of March, we need native English bloggers to help get people interested.


URL : https://www.facebook.com/TokyoLocalGuide/?ref=ts&fref=ts

I looked at your blog posts about Japan, which are so organized and easy to read with your fantastic description of each location.
Thus, I thought the concept of your blog matches right up with the concept for our Facebook page.
This is why I'm contacting you, to ask permission to share posts from your blog onto our Facebook page. Of course, we'd provide a link back to your original post each time.

Or even better, if you could write posts for your blog on our web service.
It'd be great if you could collaborate with us on making content for the site as a writer.
In the process, we'd be totally open to hearing input from you, like how the design on a blog page should look.

If you're up for it, I'd really like to have you on our team.
Let’s make a wonderful blog platform together.
When it comes to attracting customers,
I’m willing to go the extra mile.

I look forward to hearing from you.

Thanks

Yuta Sugawara
Posted 6 years, 1 month ago by Yuta Sugawara • @ • • 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.