I'm donating the <genjar> task to the project. 
Yes, it's another jar task that:

o given a set of 'root' classes will determine all dependant
  classes and include them in the jar (subject to filtration rules)

o include 'resource' files (non-class files) into the jar and allows
  'repackaging', i.e. forcing the file's path to whatever you like

o optionally generates manifest entries for every file included 
  in the jar

o allows setting manifest attributes (both main and per-entry) 
  from the project file.

The source is attached as well as the doc page:
-  unjar to its own directory
-  build with ant
    'ant usage' displays all relevant targets
-  documentation is in ./docs
-  examples are in dist-build.xml and test/build.xml
-  check dist-build.xml for example usage of an 
   optional task

Caveat: Java2 is required and only 1.3 is tested

Send bug reports or enhancement requests directly 
to me.  Contact info is in the docs.

jwk
------------------------------------------------------------------
What if the Hokey Pokey is really what it's all about?

Title: GenJar

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.

Parameters

Attribute Description Required
jarfile The name of the jar file to create. Yes

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
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 simple jar containing all classes necessary to run the two specified applications (Main and Test).

Should <class> have an attribute which specifies things like RMI? Where the names of the classes can be inferred from the root name?
<class name="com.foo.RemoteProcedure" type="rmi" />
Does this apply to BeanInfo, etc? If this is done, it should be table driven so that users can add their own types and patterns.

<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
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" />
</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" />
</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>
</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 file="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.

Does there need to be a way of including an entire library into the jar? That is, specify a jar and just copy that jar's content into the target jar (ala jlink). The resource tag already gives a way to include entire directories.

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

    genjar-src.jar

    Reply via email to