1

I have a build.xml where I put together some fat runnable jars with targets similar to:

<target name="create_myapp_jar">
  <jar destfile="./production/myapp.jar" filesetmanifest="mergewithoutmain">
    <manifest>
      <attribute name="Main-Class" value="com.something.entrypoints.MyApp"/>
      <attribute name="Class-Path" value="."/>
    </manifest>
    <fileset dir="./classes"/>
    <zipfileset excludes="META-INF/*.SF" src="./lib/commons-cli-1.2.jar"/>
    <zipfileset excludes="META-INF/*.SF" src="./lib/commons-codec-1.10-sources.jar"/>
    <zipfileset excludes="META-INF/*.SF" src="./lib/commons-codec-1.10.jar"/>
    <zipfileset excludes="META-INF/*.SF" src="./lib/commons-io-2.4.jar"/>
    <zipfileset excludes="META-INF/*.SF" src="./lib/commons-lang-2.6.jar"/>
    <zipfileset excludes="META-INF/*.SF" src="./lib/commons-pool2-2.2.jar"/>

    lots and lots of more JARs here....
</target>

The code was generated by Eclipse (Export runnable Jar) and with minor changes by me.

The list of Jars that are included is quite long actually. I build several of these fat-jars, and I was wondering how I could avoid listing the <zipfileset> statements for each target?

How can I smack them all together and then reference them from each fat-jar build target? All in the purpose of not letting my build.xml swell to hundreds and hundreds of lines. Also the pain of adding a new JAR to each of the targets would go away if I could have one definition somewhere.

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
Peter Andersson
  • 1,947
  • 3
  • 28
  • 44

2 Answers2

1

A zipgroupfileset can be used to accomplish this:

<target name="create_myapp_jar">
    <jar destfile="./production/myapp.jar" filesetmanifest="mergewithoutmain">
        <manifest>
          <attribute name="Main-Class" value="com.something.entrypoints.MyApp"/>
          <attribute name="Class-Path" value="."/>
        </manifest>
        <fileset dir="./classes"/>
        <zipgroupfileset dir="lib/" includes="*.jar" excludes="META-INF/*.SF" />
    </jar>
</target>

If you need to save the Jar fileset for later reuse, you can do:

<fileset dir="lib" id="lib_jars">
    <include name="*.jar"/>
</fileset>
<jar destfile="./production/myapp.jar" filesetmanifest="mergewithoutmain">
    <manifest>
      <attribute name="Main-Class" value="com.something.entrypoints.MyApp"/>
      <attribute name="Class-Path" value="."/>
    </manifest>
    <fileset dir="./classes"/>
    <zipgroupfileset refid="lib_jars" />
</jar>

EDIT:

It seems that the excludes only excludes files in the dir directory, not entries from the Jar files themselves, as explained in Ant: Exclude files from merged jar file. There is an answer there that provides an easy workaround.

Community
  • 1
  • 1
M A
  • 71,713
  • 13
  • 134
  • 174
  • Thanks! That solves my immediate problem, however this only works if the jars are located in the same directory (which is the most common situation of course). If I would want it, is there anyway I could "group" a list of jars, give them a name and then reference the name instead? – Peter Andersson Apr 01 '16 at 10:16
  • When running, I got the "Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes", does the exclude really work? – Peter Andersson Apr 01 '16 at 10:18
  • @PeterAndersson You're right. The `excludes` does not work as expected here for `zipgroupfileset`. I updated the answer. – M A Apr 01 '16 at 10:27
1

as far as I understand, your zipfileset entries list is always the same for each built jars ? Maybe you should consider making a macro that contains the zipfileset entries and use variables to adjust the macro for the context of each target:

<macrodef name="make-jar">
    <attribute name="destfile"/>
    <attribute name="mainclass"/>
    <attribute name="classpath"/>
    <attribute name="obj.dir"/>
    <sequential>
        <jar destfile="@{destfile}" filesetmanifest="mergewithoutmain">
            <manifest>
                <attribute name="Main-Class" value="@{mainclass}"/>
                <attribute name="Class-Path" value="@{classpath}"/>
            </manifest>
            <fileset dir="@{obj.dir}"/>
            <zipfileset excludes="META-INF/*.SF" src="./lib/commons-cli-1.2.jar"/>
            <zipfileset excludes="META-INF/*.SF" src="./lib/commons-codec-1.10-sources.jar"/>
            <zipfileset excludes="META-INF/*.SF" src="./lib/commons-codec-1.10.jar"/>
            <zipfileset excludes="META-INF/*.SF" src="./lib/commons-io-2.4.jar"/>
            <zipfileset excludes="META-INF/*.SF" src="./lib/commons-lang-2.6.jar"/>
            <zipfileset excludes="META-INF/*.SF" src="./lib/commons-pool2-2.2.jar"/>

            lots and lots of more JARs here....  
        </jar>
    </sequential>
</macrodef>

<target name="create_myapp_jar">
    <make-jar destfile="./production/myapp.jar" mainclass="com.something.entrypoints.MyApp" classpath="." obj.dir="./classes"/>
</target>
P.A. Cros
  • 501
  • 3
  • 6
  • This worked beautifully, and I happen to have a thing for macros too.... a shame I can't mark both answers as "Correct". Have to think about which one is the best. – Peter Andersson Apr 01 '16 at 10:30