Ant: Exclude files from merged jar file

2019-02-01 00:47发布

问题:

For a java project I'd like to merge all third-party jars it depends on into the main jar created by Apache Ant, which I already managed to do.

The problem is that some of these jar-files have signature-files in their META-INF-directories, so when I try to run my jar-file, I get the error message "Invalid signature file digest for Manifest main attributes". After I delete the signature-files manually the error is gone.

I tried to filter the signature files out in my ant-file with an excludes-attribute or an exclude-tag, but nothing seems to have any effect.

This is the ant-task:

<target name="jar" description="Creates the jar file">
  <mkdir dir="${jar}"/>
  <jar destfile="${jar}/${ant.project.name}.jar" level="9" filesetmanifest="mergewithoutmain">
    <zipgroupfileset dir="${lib}" includes="*.jar"/>
    <zipfileset dir="${class}"/>
    <manifest>
      <attribute name="Main-Class" value="${mainclass}"/>
    </manifest>
  </jar>
</target>

How can I filter files from the resulting jar in this ant-task? Thanks for your help!

回答1:

To the best of my knowledge there's no way to filter when using <zipgroupfileset>: the include/excludes used there apply to the zips to be merged, not the content within them.

If you have a well-known set of JARs to merge you could use individual <zipset> entries for each one; this approach allows using include/exclude to filter the contents of the source archive.

An alternative approach is to simply unzip everything into a temporary location, remove/modify the unwanted bits, then zip everything back up.



回答2:

carej is right. I've been trying to do this, merging other jars into my application jar excluding some files, and there is no way to use <zipgroupfileset> for it.

My solution is a variant of the unzip/clean-up/jar method: I first merge all the external library jars into one with <zipgroupfileset>, then merge it into mine with <zipfileset> which does allow filtering. In my case it works noticeably faster and is cleaner than unzipping the files to disk:

<jar jarfile="${dist}/lib/external-libs.jar">
  <zipgroupfileset dir="lib/">
    <include name="**/*.jar"/>
  </zipgroupfileset>
</jar>
<sleep seconds="1"/>
<jar jarfile="${dist}/lib/historadar-${DSTAMP}.jar" manifest="Manifest.txt">
  <fileset dir="${build}" includes="**/*.*"/>
  <zipfileset src="${dist}/lib/external-libs.jar">
    <exclude name="*"/>
  </zipfileset>
</jar>

The first <jar> puts all the jars it finds in lib/ into external-libs.jar, then I make it wait for one second to avoid getting warnings about the files having modification dates in the future, then I merge my class files from the build/ directory with the content of external-libs.jar excluding the files in its root, which in this case were README files and examples.

Then I have my own README file that lists all information needed about those libraries I include in my application, such as license, website, etc.



回答3:

You can use the exclude parameter in zipfileset tag to remove content from merged external JAR files, as this:

<jar jarfile="${dist}/lib/external-libs.jar">
  <zipgroupfileset dir="lib/" excludes="META-INF/**/*">
    <include name="**/*.jar"/>
  </zipgroupfileset>
</jar>

The resulting JAR file will be unsigned.



回答4:

Alberto's answer works fine but takes time to unzip&rezip the archive. I implemented a new Ant task to use built-in filtering functions, that results in much faster execution:

public class FilterZipTask extends Task {

  private Zip zipTask;

  private List<FileSet> groupfilesets = new ArrayList<FileSet>();

  private String excludes;

  public void setExcludesInZips(String excludes) {
    this.excludes = excludes;
  }

  public void addZipGroupFileset(FileSet set) {
    groupfilesets.add(set);
  }

  public void addZip(Zip zipTask) {
    this.zipTask = zipTask;
  }

  @Override
  public void execute() throws BuildException {
    for (FileSet fileset : groupfilesets) {
      Iterator<FileResource> iterator = fileset.iterator();
      while (iterator.hasNext()) {
        ZipFileSet zfs = new ZipFileSet();
        FileResource resource = iterator.next();
        zfs.setSrc(resource.getFile());
        zfs.setExcludes(excludes);
        zipTask.addZipfileset(zfs);
      }
    }
    zipTask.execute();
  }
}

And use it in build file as follows:

<taskdef name="filterzip" classname="FilterZipTask"/>
<filterzip excludesInZips="META-INF/*.*">
  <zipgroupfileset dir="${deps.dir}" includes="*.jar" />
  <zip destfile="${destjar}" />
</filterzip>


回答5:

I was also facing same problem. Googled a lot and found something that worked for me. Un-jar you jar file delete . META-INF/.SF , META-INF/.DSA files. Jar it again and run it should not show the error message.

Cause of error is explained here: http://qe-cafe.blogspot.in/2010/06/invalid-signature-file-digest-for.html



回答6:

Have been struggling with the same issue for a few hours, so ended up writing a new task by extending the existing one:

import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

import org.apache.tools.ant.taskdefs.Jar;
import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.ZipFileSet;

public class CustomizedJarTask extends Jar {

    protected Set<String> filters;

    @Override
    public void add(ResourceCollection resources) {
        if (filters != null && resources instanceof ZipFileSet) {
            ZipFileSet set = ZipFileSet.class.cast(resources);
            for (String filter : filters)
                set.createExclude().setName(filter);
        }
        super.add(resources);
    }

    public void setFilters(String patterns) {
        StringTokenizer tokenizer = new StringTokenizer(patterns, ", ", false);
        while (tokenizer.hasMoreTokens()) {
            if (filters == null)
                filters = new HashSet<>();
            filters.add(tokenizer.nextToken());
        }
    }

}

With the above, all I need in the build file is:

<taskdef name="customized-jar" classname="CustomizedJarTask" classpath="${basedir}/bin/" />
<customized-jar jarfile="${directory.build}/external-libs.jar" duplicate="fail" filters="META-INF/**">
    <zipgroupfileset dir="${directory.libs}">
        <include name="**/*.jar" />
    </zipgroupfileset>
</customized-jar>


标签: ant jar