可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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>