|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "Unified Jar" |
| 4 | +date: 2015-12-20 09:23:07 |
| 5 | +categories: java jar |
| 6 | +--- |
| 7 | + |
| 8 | +Sometimes I have a little program built in some JVM language. Usually it's a |
| 9 | +simple command line utility, maybe something that tests database connectivity |
| 10 | +via a JDBC connection, a simple JMS utility or a utility analogous to ping but |
| 11 | +for UDP. |
| 12 | + |
| 13 | +The point is, I want to make it easy to set it up and move it from machine to |
| 14 | +machine. I just want to run it from the command line and have it work. |
| 15 | + |
| 16 | +But, it's got several code files, maybe a resource, and I used something for a |
| 17 | +network library, and a command line parsing library... |
| 18 | + |
| 19 | +What I would like is a consolidated jar, one jar that has what is needed, it is |
| 20 | +configured so it can be run with `java -jar Util.jar`, and it will work. |
| 21 | + |
| 22 | +Obviously, the build system should be responsible for producing the new |
| 23 | +consolidated artifact. |
| 24 | + |
| 25 | +For the simplest version, where there are only code files, no jars, it's pretty |
| 26 | +straight forward: |
| 27 | + |
| 28 | +{% highlight xml %} |
| 29 | +<target name="dist" depends="compile" |
| 30 | + description="generate the distribution" > |
| 31 | + <!-- Create the distribution directory --> |
| 32 | + <mkdir dir="${dist}"/> |
| 33 | + |
| 34 | + <jar jarfile="${dist}/Util.jar" basedir="${build}"> |
| 35 | + <manifest> |
| 36 | + <attribute name="Main-Class" value="Main"/> |
| 37 | + </manifest> |
| 38 | + </jar> |
| 39 | +</target> |
| 40 | +{% endhighlight %} |
| 41 | + |
| 42 | +Next, say there I used some libraries, something for parsing command line parameters. |
| 43 | + |
| 44 | +There are two basic approaches to this. One is to create a jar containing jars. |
| 45 | +A custom class loader that knows how to read jars from inside jars is required |
| 46 | +to make this work. There are a couple available tools that do this. Eclipse can |
| 47 | +do this through the GUI or [One Jar](http://one-jar.sourceforge.net/). |
| 48 | + |
| 49 | +This repo covers (but does not necessarily advocate) a second approach. |
| 50 | +Unjarring the libraries and creating a new jar with all the classes from the |
| 51 | +compile and the libraries in a single jar. |
| 52 | + |
| 53 | +Adding this line: |
| 54 | + |
| 55 | +{% highlight xml %} |
| 56 | +<zipfileset src="lib/commons-cli-1.3.1.jar" includes="**/*.class"/> |
| 57 | +{% endhighlight %} |
| 58 | + |
| 59 | +will unzip the library jar, extract the .class files and include them the new |
| 60 | +jar that is being created. In context it looks like this: |
| 61 | + |
| 62 | +{% highlight xml %} |
| 63 | +<target name="dist" depends="compile"> |
| 64 | + <mkdir dir="${dist}"/> |
| 65 | + |
| 66 | + <jar jarfile="${dist}/util.jar" basedir="${classes}"> |
| 67 | + <manifest> |
| 68 | + <attribute name="Main-Class" value="Main"/> |
| 69 | + </manifest> |
| 70 | + <zipfileset src="lib/commons-cli-1.3.1.jar" includes="**/*.class"/> |
| 71 | + </jar> |
| 72 | +</target> |
| 73 | +{% endhighlight %} |
| 74 | + |
| 75 | +Now there is a single jar that contains all the dependencies necessary to run |
| 76 | +the program. |
| 77 | + |
| 78 | +There is an additional evolution possible. On Unix style systems it is possible |
| 79 | +to create a single consolidated file that can be set executable. |
| 80 | + |
| 81 | +By taking a simple bash script: |
| 82 | + |
| 83 | +{% highlight bash %} |
| 84 | +#! /bin/bash |
| 85 | + |
| 86 | +exec /usr/bin/java -jar $0 "$@" |
| 87 | +{% endhighlight %} |
| 88 | + |
| 89 | +and munging that on the beginning of a jar file, the result is a file that will |
| 90 | +execute on its own, as long as there is a /usr/bin/java executable installed. |
| 91 | + |
| 92 | +By adding these lines to the Ant task, a concatenated file with the script and |
| 93 | +jar will be created. |
| 94 | + |
| 95 | +{% highlight xml %} |
| 96 | +<concat destfile="${build}/util" binary="yes"> |
| 97 | + <filelist dir="src/main/bash" files="header.sh"/> |
| 98 | + <filelist dir="${dist}" files="util.jar"/> |
| 99 | +</concat> |
| 100 | +<chmod file="${build}/util" perm="ugo+x"/> |
| 101 | +{% endhighlight %} |
| 102 | + |
| 103 | +A sample project is available |
| 104 | +[here](https://github.com/jacobsimpson/consolidated_jar/tree/ant-build). |
| 105 | + |
0 commit comments