Start here

How to create a runnable Jar? The classpath Problem…

May 5th  2009 — Kevin Ng’eno

Today I was asked to deliver a tool working with a Swing interface. The tricky part comes when the guy tell me he doesn’t have Ant. Otherwise I would have given him an Ant file running a jar like this one :

<project name="Test" basedir="." default="run"> 

  <path id="build.class.path">
    <fileset dir="lib">
      <include name="*.jar" />
    </fileset>
  </path>

  <target name="run" depends="jar">
    <java fork="true" classname="${main-class}">
      <classpath>
        <path location="${jar.dir}/${ant.project.name}.jar" />
        <path refid="build.class.path" />
      </classpath>
    </java>
  </target>

</project>

The easy solution is to make a batch file that calls the jar file with the classpath. But it’s going to run only on windows platform. So if you want to include Unix platform, you should also make a shell script to run the jar.

But there is also the cleaner solution (my point of view) : put the class path into the jar META-INF/MANIFEST.MF file. The only problem with that solution is that you have to insert all the jar in this MANIFEST one by one (no directories) all separeted by a white space. Here is a realy long MANIFEST including Axis2 libraries :

Manifest-Version: …
Ant-Version: …
Created-By: …
Main-Class: …
Class-Path: axis2/XmlSchema-1.4.2.jar axis2/activation-1.1.jar axis2/annogen-0.1.0.jar axis2/axiom-api-1.2.7.jar axis2/axiom-dom-1.2.7.jar axis2/axiom-impl-1.2.7.jar axis2/axis2-adb-1.4.1.jar axis2/axis2-adb-codegen-1.4.1.jar axis2/axis2-ant-plugin-1.4.1.jar axis2/axis2-clustering-1.4.1.jar axis2/axis2-codegen-1.4.1.jar axis2/axis2-corba-1.4.1.jar axis2/axis2-fastinfoset-1.4.1.jar axis2/axis2-java2wsdl-1.4.1.jaraxis2/axis2-jaxbri-1.4.1.jar axis2/axis2-jaxws-1.4.1.jar axis2/axis2-jaxws-api-1.4.1.jar axis2/axis2-jibx-1.4.1.jar axis2/axis2-json-1.4.1.jar axis2/axis2-jws-api-1.4.1.jar axis2/axis2-kernel-1.4.1.jar axis2/axis2-metadata-1.4.1.jar axis2/axis2-mtompolicy-1.4.1.jar axis2/axis2-saaj-1.4.1.jar axis2/axis2-saaj-api-1.4.1.jar axis2/axis2-spring-1.4.1.jar axis2/axis2-xmlbeans-1.4.1.jar axis2/backport-util-concurrent-3.1.jar axis2/commons-codec-1.3.jar axis2/commons-fileupload-1.2.jar axis2/commons-httpclient-3.1.jar axis2/commons-io-1.4.jar axis2/commons-logging-1.1.1.jar axis2/geronimo-annotation_1.0_spec-1.1.jar axis2/geronimo-stax-api_1.0_spec-1.0.1.jar axis2/httpcore-4.0-beta1.jar axis2/httpcore-nio-4.0-beta1.jar axis2/jalopy-1.5rc3.jar axis2/jaxb-api-2.1.jar axis2/jaxb-impl-2.1.6.jar axis2/jaxb-xjc-2.1.6.jar axis2/jaxen-1.1.1.jar axis2/jettison-1.0-RC2.jar axis2/jibx-bind-1.1.5.jar axis2/jibx-run-1.1.5.jar axis2/log4j-1.2.15.jar axis2/mail-1.4.jar axis2/mex-1.4.1.jar axis2/neethi-2.0.4.jar axis2/soapmonitor-1.4.1.jar axis2/woden-api-1.0M8.jar axis2/woden-impl-dom-1.0M8.jar axis2/wsdl4j-1.6.2.jar axis2/wstx-asl-3.2.4.jar axis2/xalan-2.7.0.jar axis2/xercesImpl-2.8.1.jar axis2/xml-apis-1.3.04.jar axis2/xml-resolver-1.2.jar axis2/xmlbeans-2.3.0.jar

Since it could be annoying to insert all this jars, there is an other solution :  with the version 7 of Ant, you can use a task named manifestclasspath. Who’s purpose is to converts a path into a property whose value is appropriate for a Manifest’s Class-Path attribute.

<project name="Test" basedir="." default="run">
  <path id="class.path">
    <fileset dir="${jar.dir}/axis2">
    <include name="*.jar" />
  </fileset></path>

  <manifestclasspath property="jar.classpath" jarfile="${jar.dir}/${ant.project.name}.jar">
     <classpath refid="class.path" />
  </manifestclasspath>

  <target name="jar" depends="clean,compile">
    <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
      <fileset dir="${src.dir}">
        <exclude name="**/*.java" />
      </fileset>
      <manifest>
        <attribute name="Main-Class" value="${main-class}" />
        <attribute name="Class-Path" value="${jar.classpath}" />
      </manifest>
    </jar>
  </target>
</project>

Now you can just double clik on the jar and it should work.

The only things to keep in mind :

  • Install Java (carefull with the versions)
  • Put the libraries in the same folder as the jar
  • Keep the libraries in the same folder as the jar (see the relative classpath)