The war plugin in 1.7 now places WEB-INF ahead of META-INF, causing issues with OSGi containers

There was a change made to War.groovy in 1.7. In 1.6, the constructor had the following: webInf = copyAction.rootSpec.addChild().into(‘WEB-INF’)

In 1.7 this was changed to: webInf = copyAction.rootSpec.addFirst().into(‘WEB-INF’)

This now places the WEB-INF folder ahead of META-INF in the bundle. This breaks OSGi containers, which expect the META-INF and MANIFEST.MF to be the first 2 entries in the bundle.

Are you sure? This sounds like a crazy assumption.

Java’s jar tool has always placed the manifest first, and most if not all frameworks expect this. OSGi bundles and war files are both extensions of jar files. Was there a reason the WEB-INF was placed first? I know of no requirement for this by any standard, framework, or container, so it should do no harm reverting this change.

BTW the java.util.jar.JarInputStream and JarOutputStream classes also expect this.

I don’t know why the change was made, but it’s likely there was some reason. That said, if it’s wrong, it needs to be fixed.

I noticed that this was not fixed in 1.8 RC1. Are there any plans to address this?

Please consider this bug from the oracle java bug database.

JDK-5046178 : JarInputStream doesn’t return Manifest object

The bug is not going to be fixed, so gradles behavior WILL cause trouble. I was already hit by it.

Why do you think that this issue isn’t going to be fixed? Also, the issue only seems to apply to indexed Jar files. Are you creating such an index yourself? Unless I’m missing something, Gradle has no built-in support for creating a Jar index.

I think he was just wondering, if it’s going to be fixed.

But why do you think that this is just an issue with indexed jars? JarInputStream fails to read the manifest file from a war that was created with gradle. It doesn’t matter if it is indexed or not. And who knows in which java tools or apps JarInputStream is used…

BTW: I hate it to argue for this issue. Why on earth is this fact not part of the jar spec? If it is a requirement for a jar that the manifest is the first file of a jar it should be in the spec.

But still, I think gradle should try to simulate the official jar tool as good as possible. And the jar tool enforces that the manifest file is the first file.

But why do you think that this is just an issue with indexed jars?

I misinterpreted the issue description. Turns out that creating an indexed Jar is sufficient but not necessary for this problem to occur.

Yes, any war file created by Gradle 1.7 (and later at this point) will not produce jars consistent with the jar tool in the JDK. Did you ever discover why the change was made in 1.7? It was a very small change that is easily reverted, but with large consequences. If you are producing war files not consistent with the jar tool, it seems like there should be a good reason for it.

It has never been a goal to produce a Jar file consistent with the Jar tool, whatever that means exactly. I haven’t checked what changed in 1.7, but we should certainly have a look. Raised as GRADLE-2886.

What it means exactly is to put the META-INF as the first entry in the jar file, like the JDK’s jar command line tool.

The jar file format (which includes jars, ears, wars) produced by JDK’s jar command line tool should be considered the de facto standard, IMO, as the JDK’s standard library (JarInputStream, JarOutputStream) depend on this format, i.e. META-INF comes first.

Again, it’s not clear what this means. If it means to make ‘META-INF’ the first entry, we can certainly do that. Of course the real solution is to get JDK-5046178 fixed.

OK I will clarify that. A jar file is based on the zip file format. Zip files are organized into a sequence of files. The first or second file in this sequence should be the META-INF/MANIFEST.MF in order for the jar file to be compatible with the JDK standard library utilities.

From JDK’s JarInputStream.java:

// This implementation assumes the META-INF/MANIFEST.MF entry

// should be either the first or the second entry (when preceded

// by the dir META-INF/). It skips the META-INF/ and then

// “consumes” the MANIFEST.MF to initialize the Manifest object.

JarEntry e = (JarEntry)super.getNextEntry();

if (e != null && e.getName().equalsIgnoreCase(“META-INF/”))

e = (JarEntry)super.getNextEntry();

first = checkManifest(e);

The only change that needs to be made is in War.groovy, when adding the WEB-INF, instead of calling rootSpec.addFirst(), call rootSpec.addChild(), which is what was done in Gradle 1.6 and earlier. I have a patched version of 1.7 that does this and there are no apparent issues.

We will fix it, but its a matter of finding the time. Are you interested in helping out with a fix?

Of course! I’ll submit a patch and attach it to the issue.

Great, thanks. Can you submit a pull request instead of a patch?

I went ahead and submitted the pull request. I’m not very experienced with GitHub so let me know if there is a problem.