Today I’ve got a question from one of our developers. He was building a WAR file and then copied it from one location to another. When he tried to run the first file with Winstone everything worked fine. However when we tried to run the second file – he got an exception:
[Winstone 2013/10/17 13:59:12] - Beginning extraction from war file [Winstone 2013/10/17 13:59:12] - Error initializing web application: prefix  java.util.zip.ZipException: invalid bit length repeat at java.util.zip.InflaterInputStream.read(InflaterInputStream.java:164) at java.io.FilterInputStream.read(FilterInputStream.java:107) at winstone.HostConfiguration.getWebRoot(HostConfiguration.java:262) at winstone.HostConfiguration.<init>(HostConfiguration.java:73) at winstone.HostGroup.initHost(HostGroup.java:85) at winstone.HostGroup.<init>(HostGroup.java:45) at winstone.Launcher.<init>(Launcher.java:196) at com.softteco.radioman.winstone.WinstoneServiceProvider.start(WinstoneServiceProvider.java:38) at com.softteco.radioman.Launcher.main(Launcher.java:38)
Okay, something is wrong about ZIP file structure. Running the same two files on my Linux host displayed pretty much the same results. So the problem seemed to be cross-platform. Binary comparison of the files showed that several bytes
andy@andy:~/Temp$ cmp ~/cryptcast.1.war ~/cryptcast.2.war /home/andy/cryptcast.1.war /home/andy/cryptcast.2.war differ: byte 11, line 2
So for some reason some bytes change during copy of the file. This was eye-opening. Finally we were able to formulate an adequate Google query to help us. The first link explained us what to do but didn’t really clarify why this happened. The part of our pom.xml was:
<execution> <id>copy-resources</id> <phase>validate</phase> <goals> <goal>copy-resources</goal> </goals> <configuration> <outputDirectory>./</outputDirectory> <resources> <resource> <directory>../services/target</directory> <!-- The issue vanishes if we remove the next line --> <filtering>true</filtering> <includes> <include>**/*.war</include> </includes> </resource> </resources> </configuration> </execution>
So we removed the last line and things started to work. But why? So I’ve moved a bit deeper into investigations.
mavenResourcesFiltering.filterResources( mavenResourcesExecution );
Interesting, what are they filtering? Moving to another library and we see DefaultMavenResourcesFiltering. Interesting, some magics here:
this.defaultNonFilteredFileExtensions.add( "jpg" ); this.defaultNonFilteredFileExtensions.add( "jpeg" ); this.defaultNonFilteredFileExtensions.add( "gif" ); this.defaultNonFilteredFileExtensions.add( "bmp" ); this.defaultNonFilteredFileExtensions.add( "png" );
So filtering is simply skipped during copy for several types of files. And finally we come to DefaultMavenFileFilter which creates a list of processors and processing files during copy. As a result some symbols were replaced with the others which broke ZIP file structure.
The mystery is uncovered. So what to do? The following things look more reasonable for me:
- Use copy-maven-plugin
- Remove <filterable> or set it to false unless you really need it during copy.
- Exclude unwanted extension in the nonFilteredFileExtensions configuration tag