GenJar Manual

by

GenJar

Synopsis

Jars a set of classes and resources.

The <genjar> task is designed to make Jar creation as easy as possible. You give it the root classes (i.e. entry points) of your application and it will determine all other class files that need to be included in the jar.

It does this by recursively examining each class file, extracting a list of all classes referenced, eventually arriving at the complete set of classes required to execute the application. These classes are then placed into the target jar file.

Impetus

Why does Ant need another jar task? If a developer uses a lot of libraries (their own and/or third party), including these libraries into an application jar can be a real problem. Does one include the entire library? Just that portion actually used? (And just what libraries did get used?)

GenJar was designed to render these questions moot: the JVM knows how to link classes together to execute an application - why can't it be used to bundle all the required pieces into a Jar?

No Jar is really complete without a Manifest. To this end, GenJar will generate complete manifest files, listing every file contained in the Jar, along with size and creation dates (useful for problem diagnosis). Manifest attributes may be specified in a 'template' file or directly within the Ant build file. (See this example.)

<genjar>

The <genjar> element is the task level element. It has several child parameters that may be specified: <class>, <classfilter>, <resource> and <manifest>. Along with the standard Ant <classpath> element.

To make GenJar 'known' to Ant a taskdef must be used. A properties file is provided to simplify this task.

<taskdef resource="genjar.properties">
If GenJar.jar is in $ANT_HOME/lib
<taskdef resource="genjar.properties" classpath="path/to/GenJar.jar">
If GenJar.jar is in a different location

Parameters

Attribute Description  
jarfile The name of the jar file to create. At least 1 of jarfile or destdir.
destdir The name of the directory to copy the dependencies to.

If the name starts with a File.pathSeparator or the second character is a : then the path is assumed to be absolute. Otherwise the project baseDir attribute is prepended to the name to create the full path to the new jar file.

Parameters specified as nested elements

<class>

Use <class> elements to specify the names of the classes from which <genjar> will begin its class dependency search. Each class is recursively searched for the classes on which it depends. In this way, all classes necessary to execute an application can be automatically included in the jar. (See class filter for a method of preventing certain classes from being placed in the jar.)

This referenced class inclusion works for all classes that are known at compile time. Any classes that are dynamically loaded cannot be located in this fashion and therefore must be explicitly included using a <class> element.

Note: Class names listed in the <class> element are not subject to filtering performed by the class filter.

Parameters

Attribute Description Required
name The fully qualified name of the class include in the jar. (Use the standard Java 'dotted' notation.) Yes (Unless a fileset is supplied)
bean If set to 'yes', this class' manifest entry will be marked as being a JavaBean (Java-Bean: true). No

Examples:

  <genjar jarfile="test.jar">
    <class name="com.killer.app.Main"/>
    <class name="com.killer.app.Test"/>
  </genjar>
      

This example builds a jar containing all classes necessary to run the two specified applications (Main and Test).

  <genjar jarfile="test.jar">
    <class>
      <fileset dir="${classes.dir}>
        <include name="com/company/*.class">
      </fileset>    
    </class>
  </genjar>
      

This example builds a jar containing all classes necessary to run all the classes in the com.company package.

<resource>

Use <resource> elements to specify non-class files to be included in the jar.

Attribute Description Required
file Specifies a single file to include in the jar Yes
filename The name (including the path in the jar) of a single file from a jar, to include in the jar under construction. Unjar the archive in a directory to include more then one file and to change the path. No
package A package name that's to replace the default package name of all resources specified in this <resource> element. No

A <resource> element may take a standard Ant fileset. In this case, the path given to the jarred files is taken from the <include> parameter. If a package is specified on the resource, then all files included in the fileset will have their paths changed to the package specified.

Examples:

<genjar jarfile="test.jar">
  <resource file="images/icon.png" />
  <classpath>
        <pathelement path="path/to/images" />
    </classpath>
</genjar>

This example results in the file icon.png being included in the jar with a path of /images.

<genjar jarfile="test.jar">
  <resource file="images/icon.png" package="com/foo/ka" />
  <classpath>
        <pathelement path="path/to/images" />
  </classpath>
</genjar>

This results in the file icon.png being included in the jar with a path of /com/foo/ka, effectively placing into the com.foo.ka package.

<genjar jarfile="test.jar">
  <resource>
    <fileset dir="${build.docs}">
        <include name="api/**/*.*" />
    </fileset>
  </resource>
  <classpath>
        <pathelement path="${build.doc}"/>
  </classpath>
</genjar>

This example results in all the files in and below the ${build.docs}/api directory being included into the jar. The path used in the jar begins at api.

<genjar jarfile="test.jar">
  <resource filename="org/apache/xerces/readers/xcatalog.dtd" />
  <classpath>
    <pathelement location="lib/xerces.jar"/>
  </classpath>
</genjar>

This example will copy the xcatalog.dtd file from the Xerces jar (in the classpath) into the target jar.

package attribute can't be used to access a file from a jar file, using filename. Unjar the content in a tmp folder to use change the path of the files in the destination jar.

<library>

The <library> specifies either a directory tree or a jar file to be included into the generated jar. In either case, the entire content of the referenced library is included in the jar.

In the case of a directory, all files contained within (and below) the named directory will be inserted into the jar with a path name beginning at the named directory. For example, if you specify a library like this <library dir="docs"/> then all files and subdirectories within the docs will be inserted into the jar with their paths beginning at docs.

If you postfix the directory's path with the /* pattern, then the named directory will be stripped from the file paths before insertion into the jar. For example, <library dir="docs/*"/> will insert all the files in and below the docs into the generated jar, but their paths will begin immediately below docs.

When the specified library is a jar, all entries in the jar are copied into the generated jar with the exception of the library jar's manifest file. Along with the library jar's files, any entry attributes are also imported into the generated jar.

Parameters

Attribute Description Required
dir A directory containing the library files. All files within this directory tree will be added to the jar, the path used in the jar will start at this name. One of dir or jar
jar A jar to include in the target jar. ALL files in this jar will be copied to the target jar except the manifest file. One of dir or jar

Examples:

<library jar="${lib}/xerces.jar"/>

This example will copy the entire xerces.jar into the generated jar.

<library dir="${lib}/classes" />

This example will pull all files located in and below the ${lib}/classes directory into the jar. Their jar names will include the path named by the ${lib}/classes.

<library dir="${docs}/*"/>

This example will insert all files (and directories) below the ${docs} directory into the generated jar. But the path named by ${docs} will be stripped form those files before insertion.

Assume the following structure and files:

./docs
./docs/index.html
./docs/images
./docs/images/fig1.jpg
./docs/images/fig2.jpg

If you use the library tag this way <library dir="docs"/> then the jar will contain:

docs/index.html
docs/images/fig1.jpg
docs/images/fig2.jpg

If you were to specify the library this way: <library dir="docs/*"/> then the jar will contain:

index.html
images/fig1.jpg
images/fig2.jpg
Note that the main attributes (Main-Class, Class-Path) from a library jar are NOT imported into the generated jar. Any package information embedded within the jar is also lost.

<classfilter>

Use the <classfilter> element to specify which classes are not to be included in the jar, and as necessary, which classes are to be explicitly included. Any number of <include> and <exclude> elements may be used inside the <classfilter>.

(Note that the traditional Ant includes/includesfile/excludes/excludesfile attributes are not used as they deal with files and GenJar deals with classes.)

The class filtering mechanism operates on patterns. These patterns are class name prefixes, i.e. partial package or class names. If a class' fully qualified name starts with an include/exlcude pattern, then it's considered a match. For example: the class name com.foo.Test matches the pattern com.foo. because the class name starts with the pattern.

When determining if a class should be in the jar, <genjar> first checks the list of include patterns. If the candidate class' name matches an include pattern then the class is included in the jar (explicit inclusion). If the class' name does not match an include pattern but matches an exclude pattern, the class is not included in the jar (explicit exclusion). If the class' name does not match any patterns, then it's included in the jar by default (implicit inclusion).

This algorithm allows the user to select very narrow slices of large package spaces. For example, one can include just the Ant types package into a jar by excluding the entire apache package space and then including specifically the Ant types package:

<classfilter>
  <exclude name="org.apache." />  <!-- exclude the entire apache package space -->
  <include name="org.apache.tools.ant.types." /> <!-- but include Ant types -->
</classfilter>

This example demonstrates the fact that include patterns override exclude patterns.

There is a default list of exclude patterns that's compiled into the class filter:

  • java.
  • javax.
  • sun.
  • sunw.
  • com.sun.
  • org.omg.
  • A site wide list of exclusions may be specified in the resource file site-exclusions. This file is expected to located in the same location (directory/package) as the GenJar class. the site-exclusions file is expected to contain one exclude pattern per line with blank lines being ignored. You may embed comments by prefixing the comment line with '#'.

    <include> and <exclude> Parameters

    Attribute Description Required
    name Include/Exclude pattern Yes

    Examples:

    <genjar jarfile="test.jar">
      <class name="com.killer.app.Main"/>
      <classfilter>
        <exclude name="org.apache."/>
        <exclude name="com.ibm."/>
      </classfilter>
    </genjar>

    This specifies a jar that will contain all classes referenced by com.killer.app.Main except those in any package starting with org.apache or com.ibm.

    <genjar jarfile="test.jar">
      <class name="com.killer.app.Main"/>
      <classfilter>
        <include name="org.apache.ant"/>
        <exclude name="org.apache."/>
        <exclude name="com.ibm."/>
      </classfilter>
    </genjar>

    This specifies a jar that will contain all classes referenced by com.killer.app.Main except those in any package starting with org.apache or com.ibm. All referenced classes from org.apache.ant will be included as an explicit inclusion overrides an exclusion.

    <classpath>

    The <classpath> element is used to specify search paths to genjar's jar builder. See the Ant documentation for a full discussion on <classpath>.

    Examples:

    <genjar jarfile="test.jar">
      <class name="com.killer.app.Main"/>
      <classfilter>
        <exclude name="org.apache."/>
        <exclude name="com.ibm."/>
      </classfilter>
      <classpath>
        <pathelement location="build/classes"/>
      </classpath>
    </genjar>

    <manifest>

    The <manifest> element controls how the jar manifest is initially constructed and what main attributes are placed into the manifest. (For more information on Jar Manifests, see this.)

    The <manifest> element allows the developer to specify a template manifest file that will form the base for the manifest placed into the jar. Additionally, main and per-entry attributes may be specified. And control over the default per-entry attributes may be asserted.

    To specify a template manifest file, use the template attribute on the <manifest> element. All attributes (main and per-entry) will be included in the manifest written to the jar. Note that any duplicate attributes generated by GenJar will overwrite those in the template manifest. Example:

    <manifest template="default.mft">
    ....
    </manifest>

    Normally GenJar will generate a set of per-entry attributes for every file included in the jar. These attributes include the full path to the original resource, the last modified date of that resource and the size of that resource. This information is included in the manifest to aid in tracking down problems like: "Do I have the right version of that library file?" and "Where did that class file come from? Is it the old one?" These automatic per-entry attributes may be disabled by specifying generateEntryAttributes='no' in the <manifest> element. At least two attributes are generated for each entry placed in the jar:

    Content-Location
    This attribute is set to the absolute path to the source file or archive (jar/zip).
    Last-Modified
    This attribute is set to the last modification time of the source file (file/jar/zip) or the modification time from the source jar (if the source is in fact a jar).
    others
    If the jar entry is taken from a jar, then the source's entry-attributes are imported into the new jar.

    <manifest> Parameters

    Attribute Description Required
    template path to template file No
    generateEntryAttributesprohibits generation of per-entry attributes (see text)No

    Manifest attributes are specified by using the child <attribute> elements.

    <attribute> Parameters

    Attribute Description Required
    name the attribute's name Yes
    valuethe attribute's valueYes
    entrythe entry name to which this attribute belongs
    If not supplied (or equal to 'main'), then the attribute is a Main-Entry.
    No

    Example:

    <manifest>
      <attribute name="Specification-Title"    value="Killer App" />
      <attribute name="Specification-Version"  value="2.0" />
      <attribute name="Specification-Vendor"   value="Foo Bar Inc." />
      <attribute name="Implementation-Title"   value="KA"  />
      <attribute name="Implementation-Version" value="1.3.7" />
      <attribute entry="com/foobar/ka/main.class"
                 name="Icon-Large"
                 value="large-icon.png" />
    <manifest>

    Complete Example

    <genjar jarfile="${build.dist.jar}">
      <class name="com.riggshill.catalog.Servlet" />
    
      <classfilter>
        <!-- don't load any of the apache stuff (XML et.al.)-->
        <exclude name="org.apache." />
        <!-- but we borrow some routines from an Ant task.... -->
        <include name="org.apache.tools.ant.taskdefs.optional." />
      </classfilter>
    
      <classpath>
        <pathelement location="${build.dest}" />
      </classpath>
    
      <!-- include & repackage some icons (for the visual Ant builder) -->
      <resource name="images/icon-large.png" package="com.riggshill.catalog." />
      <resource name="images/icon-small.png" package="com.riggshill.catalog." />
      <!-- include the docs & source -->
      <resource>
        <fileset dir="${build.dir}">
          <include name="docs/**/*.*" />
          <include name="src/**/*.*" />
        </fileset>
      </resource>
         
    <manifest template="manifest.mf">
        <attribute name="Specification-Title"      value="${Name}" />
        <attribute name="Specification-Version"    value="${version}" />
        <attribute name="Specification-Vendor"     value="RiggsHill Software" />
        <attribute name="Implementation-Title"     value="${Name}" />
        <attribute name="Implementation-Version"   value="${version}" />
        <attribute name="Implementation-Vendor"    value="RiggsHill Software" />
        <attribute name="Implementation-Vendor-Id" value="JWK" />
      </manifest>
    </genjar>
      

    Troubleshooting version 1.0.3 and higher

    The zip archive contains two jar files: NoClassDefFoundError
    java.lang.NoClassDefFoundError: org/apache/bcel/classfile/ClassFormatException
    

    With the 34 Kb genjar.jar, that comes without the classes of org.bcel package, you must have the bcel-6.1.jar in $ANT_HOME/lib.

    ClassFormatException
    org.apache.bcel.classfile.ClassFormatException: Invalid byte tag in constant pool: 18
    

    You have bcel-5.1.jar in your $ANT_HOME/lib. Delete this jar file. Replace it with bcel-6.1.jar or use the 222 Kb genjar.jar that contains the classes of org.bcel package.

    In general

    Genjar does not find a class but I can't see what is missing.

    Run the genjar task with verbose and debug enabled on the command line:

    ant -d genjar_task