I am having an issue with a jar produced by gradle. Forgive me for the length of this post as I try to lay out all the legwork I’ve put into reproducing the issue so far.
The jar produced by gradle is different in size from the one I create by hand with the jar command. The one produced by Gradle throws exceptions about non-zero directory length when used in my Oracle application whereas the one produced by hand does not through those exceptions.
Gradle produces a jar of 12,939 bytes. It has a very simple one line MANIFEST.MF file. When I use that jar in my application the app server throws many exceptions. This is where it gets interesting. If I extract the manifest and then update the manifest in the jar the app server stops throwing the exceptions.
Here are the steps I’m taking to extract/update the jar.
First, I execute:
jar xvf my.jar META-INF/MANIFEST.MF
Then, I execute:
jar uvfm my.jar META-INF/MANIFEST.MF
This “works”, though it throws a warning because the line in the MANIFEST.MF that I’m updating with already exists in the MANIFEST.MF in the jar. However, the end result is that the jar has also now changed size. And, interestingly, it no longer throws exceptions either.
So, I’m looking for tools to help me compare these jars. They should be (in my humble opinion) the same, but they are not. The questions I’m trying to ask are:
Why are they not the same?
What is different about them?
I am using Gradle 2.3 and 2.4, I’ve not tried to reproduce this with other versions of gradle.
David, thanks for the idea. The only thing that shows up is the different time stamps for MANIFEST.MF. Here is the output. I also used home-brew to install a tool named pkgdiff and compared the two jar files and it reports that there are no changes between the two. I believe it only examines the files themselves, and not necessarily how they are placed into the zip or any zip entries or that kind of thing, but I don’t know that for sure.
Well, you say the two jar files are of different sizes, but you only told us the size of one of them. You also compared the file listing and you say the only difference was the timestamp on one of the elements. You’re saying that otherwise the jar files were identical?
What was the actual error you’re getting from the application container?
Q: Well, you say the two jar files are of different sizes, but you only told us the size of one of them.
A: The bad jar is 12,939 bytes. The good jar is 13,091 bytes. I create the good jar by manually updating its MANIFEST.MF file with this command:
jar uvfm my.jar META-INF/MANIFEST.MF
This command does not change the contents of the MANIFEST.MF file. All the diff tools so far show the contents and size of the MANIFEST.MF file to be the same (albeit with different timestamps). Why does this command change the size of the jar then?
Q:You also compared the file listing and you say the only difference was the timestamp on one of the elements. You’re saying that otherwise the jar files were identical?
A: I used your suggested commands and posted the results to show that the only difference was the timestamp. I also ran pkgdiff on the jars and it reported their contents were unchanged from one jar to the other.
In reviewing your suggestions I see that I ommitted the “-c” in the diff command. Here is the full output:
diff -c bad.lst good.lst
*** bad.lst 2015-06-19 08:13:45.000000000 -0500
--- good.lst 2015-06-19 08:13:37.000000000 -0500
***************
*** 2,8 ****
0 Wed Jun 17 16:17:30 CDT 2015 net/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/
! 68 Wed Jun 17 16:17:30 CDT 2015 META-INF/MANIFEST.MF
3533 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSRequest$_getResponse_closure1.class
5527 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/Constants.class
6905 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSResponse.class
--- 2,8 ----
0 Wed Jun 17 16:17:30 CDT 2015 net/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/
! 68 Wed Jun 17 16:21:40 CDT 2015 META-INF/MANIFEST.MF
3533 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSRequest$_getResponse_closure1.class
5527 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/Constants.class
6905 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSResponse.class
Additional Information
Jar built using Gradle 2.4, --version output looks like this:
$ gradle --version
Gradle 2.4
Build time: 2015-05-05 08:09:24 UTC
Build number: none
Revision: 5c9c3bc20ca1c281ac7972643f1e2d190f2c943c
Groovy: 2.3.10
Ant: Apache Ant™ version 1.9.4 compiled on April 29 2014
JVM: 1.8.0_31 (Oracle Corporation 25.31-b07)
OS: Mac OS X 10.10.3 x86_64
The exception thrown by the application looks like this:
intradoc.io.zip.IdcZipException:
!syZipFormatNonZeroDirectoryLength,org/
at intradoc.io.zip.IdcZipFileFormatter.validateCentralDirectoryEntry(IdcZipFileFormatter.java:453)
at intradoc.io.zip.IdcZipFile.init(IdcZipFile.java:195)
at intradoc.loader.IdcLoaderElementList.makePathElement(IdcLoaderElementList.java:221)
at intradoc.loader.IdcLoaderElementList.addPathElement(IdcLoaderElementList.java:361)
at intradoc.loader.IdcClassLoader.addClassPathElement(IdcClassLoader.java:406)
at intradoc.server.ComponentLoader.loadEnabledComponent(ComponentLoader.java:771)
…
My suspicion is that updating the MANIFEST.MF file causes the central listing (at the end of the zip) to be written in a way that the code expects, possibly just reordering the listing. Could you try extracting a class file and updating it in the same way to see if that breaks the jar again?
Sterling, thanks for your input. I will indeed try your suggest and get back shortly. But first…
Yes, the post you found is exactly the same issue. A few thoughts on that post: The commands Thomas described in the references post are the same ones that Oracle Support is providing on their support site. However, the command they use, “jar uvf”, doesn’t actually update the MANIFEST, it removes it:
$ ls -al
total 32
drwxr-xr-x 3 jstortz staff 102 Jun 19 20:12 ./
drwx------+ 14 jstortz staff 476 Jun 19 20:07 ../
-rw-r--r-- 1 jstortz staff 12939 Jun 19 20:12 rcs_http_lite-1.0.0.bad.jar
$ jar tvf rcs_http_lite-1.0.0.bad.jar
0 Wed Jun 17 16:17:30 CDT 2015 META-INF/
68 Wed Jun 17 16:17:30 CDT 2015 META-INF/MANIFEST.MF
0 Wed Jun 17 16:17:30 CDT 2015 net/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/
5527 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/Constants.class
3533 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSRequest$_getResponse_closure1.class
10655 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSRequest.class
6905 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSResponse.class
$ jar xvf rcs_http_lite-1.0.0.bad.jar META-INF/MANIFEST.MF
inflated: META-INF/MANIFEST.MF
$ ls -al
total 32
drwxr-xr-x 4 jstortz staff 136 Jun 19 20:12 ./
drwx------+ 14 jstortz staff 476 Jun 19 20:07 ../
drwxr-xr-x 3 jstortz staff 102 Jun 19 20:12 META-INF/
-rw-r--r-- 1 jstortz staff 12939 Jun 19 20:12 rcs_http_lite-1.0.0.bad.jar
$ jar uvf rcs_http_lite-1.0.0.bad.jar META-INF/MANIFEST.MF
ignoring entry META-INF/MANIFEST.MF
$ ls -al
total 32
drwxr-xr-x 4 jstortz staff 136 Jun 19 20:12 ./
drwx------+ 14 jstortz staff 476 Jun 19 20:07 ../
drwxr-xr-x 3 jstortz staff 102 Jun 19 20:12 META-INF/
-rw-r--r-- 1 jstortz staff 12892 Jun 19 20:12 rcs_http_lite-1.0.0.bad.jar
$ jar tvf rcs_http_lite-1.0.0.bad.jar
0 Wed Jun 17 16:17:30 CDT 2015 META-INF/
0 Wed Jun 17 16:17:30 CDT 2015 net/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/
5527 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/Constants.class
3533 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSRequest$_getResponse_closure1.class
10655 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSRequest.class
6905 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSResponse.class
I have, as you suggested, extracted a class from the good version of the jar. Below is the output from my work. Notice the size of the jar remains the same. I will test this new jar and post back my situation shortly.
$ ls -al
total 32
drwxr-xr-x 3 jstortz staff 102 Jun 19 20:14 ./
drwx------+ 14 jstortz staff 476 Jun 19 20:07 ../
-rw-r--r-- 1 jstortz staff 13091 Jun 19 20:14 rcs_http_lite-1.0.0.good.jar
$ jar tvf rcs_http_lite-1.0.0.good.jar
0 Wed Jun 17 16:17:30 CDT 2015 META-INF/
68 Wed Jun 17 16:21:40 CDT 2015 META-INF/MANIFEST.MF
0 Wed Jun 17 16:17:30 CDT 2015 net/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/
5527 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/Constants.class
3533 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSRequest$_getResponse_closure1.class
10655 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSRequest.class
6905 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSResponse.class
$ jar xvf rcs_http_lite-1.0.0.good.jar net/rcsdev/http/Constants.class
inflated: net/rcsdev/http/Constants.class
$ ls -al
total 32
drwxr-xr-x 4 jstortz staff 136 Jun 19 20:15 ./
drwx------+ 14 jstortz staff 476 Jun 19 20:07 ../
drwxr-xr-x 3 jstortz staff 102 Jun 19 20:15 net/
-rw-r--r-- 1 jstortz staff 13091 Jun 19 20:14 rcs_http_lite-1.0.0.good.jar
$ jar uvf rcs_http_lite-1.0.0.good.jar net/rcsdev/http/Constants.class
adding: net/rcsdev/http/Constants.class(in = 5527) (out= 2385)(deflated 56%)
$ ls -al
total 32
drwxr-xr-x 4 jstortz staff 136 Jun 19 20:15 ./
drwx------+ 14 jstortz staff 476 Jun 19 20:07 ../
drwxr-xr-x 3 jstortz staff 102 Jun 19 20:15 net/
-rw-r--r-- 1 jstortz staff 13091 Jun 19 20:15 rcs_http_lite-1.0.0.good.jar
$ jar tvf rcs_http_lite-1.0.0.good.jar
0 Wed Jun 17 16:17:30 CDT 2015 META-INF/
68 Wed Jun 17 16:21:40 CDT 2015 META-INF/MANIFEST.MF
0 Wed Jun 17 16:17:30 CDT 2015 net/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/
0 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/
5527 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/Constants.class
3533 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSRequest$_getResponse_closure1.class
10655 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSRequest.class
6905 Wed Jun 17 16:17:30 CDT 2015 net/rcsdev/http/RCSResponse.class
I took the good jar, extracted the class and then updated the jar with the class (shown in the previous post) and the jar size stayed the same. I tested that jar with the Oracle app and got no exceptions. So it seems that extracting and updating a class on a jar that works does not break said jar.
Next up, I will take the bad jar (the one that throws exceptions) and try extracting/updating a class (not the MANIFEST.MF) and see what that does.
This is kind of interesting. I took the bad jar (the one that throws exceptions) and I extract a class from it, then updated that class right back into the jar (see below for the command line output). You’ll notice that this act DID alter the jar size.
However, when I attempted to use this jar I still got the exceptions thrown.
Does this lead us to believe the issues with with the META-INF directory or its contents and not other resources of the jar, such as class files? That’s what it looks to me like.
Sterling, you mentioned the “central listing”, any more thoughts on that? The contents of the file seem to be consistent through all the jars, but it seems like the jar itself must have structural differences. I’m having a hard time zeroing in on that aspect.
$ jar xvf rcs_http_lite-1.0.0.bad.jar net/rcsdev/http/Constants.class
inflated: net/rcsdev/http/Constants.class
$ ls -al
total 32
drwxr-xr-x 4 jstortz staff 136 Jun 19 20:44 ./
drwx------+ 14 jstortz staff 476 Jun 19 20:07 ../
drwxr-xr-x 3 jstortz staff 102 Jun 19 20:44 net/
-rw-r--r-- 1 jstortz staff 12939 Jun 19 20:44 rcs_http_lite-1.0.0.bad.jar
$ jar uvf rcs_http_lite-1.0.0.bad.jar net/rcsdev/http/Constants.class
adding: net/rcsdev/http/Constants.class(in = 5527) (out= 2385)(deflated 56%)
$ ls -al
total 32
drwxr-xr-x 4 jstortz staff 136 Jun 19 20:45 ./
drwx------+ 14 jstortz staff 476 Jun 19 20:07 ../
drwxr-xr-x 3 jstortz staff 102 Jun 19 20:44 net/
-rw-r--r-- 1 jstortz staff 13091 Jun 19 20:45 rcs_http_lite-1.0.0.bad.jar
I have also tried to build my jar without gradle. I used this command:
jar cvfm myjar.jar ../MANIFEST.MF .
A jar built in this manner does not produce the exception stack traces in the app server.
Without knowing exactly how Gradle builds the jar I could suspect that a class/library used by Gradle could be the issue. Right now though it looks like I can build manually and it works while building with gradle fails. Any ideas on where to go from here?
Team, what is the appropriate process to file an official bug for this? At this point I’ve figured out ways to adjust the jar or build the jar manually that work. It appears to only be jars build with Gradle that cause the issue.
Gradle internally uses Ant. Gradle 2.3 uses Ant 1.9.3, while Gradle 2.4 uses Ant 1.9.4. Gradle 2.5 will depend on 1.9.3 due to regressions in Ant 1.9.4 and 1.9.5, but I am unsure that what you are seeing is actually one of those issues, especially because you say you have tested with Gradle 2.3 which already comes with Ant 1.9.3…
You are correct sir, I did try with both Gradle 2.3 and 2.4. However, you bring up something I’ve not tried…using ANT directly. Knowing now that Gradle just using ant under the hood I can try a few versions with Ant to see if I can reproduce and then perhaps take things up with the Ant team.
I tried creating my jar with Ant 1.9.4 and that jar worked. I then tried with Ant 1.9.5 and that jar worked. So now I’m back at “What is gradle doing” because the jar created by gradle is different and not working. Interesting note, the jars produced by the versions of ant are also all different in size…meaning 1.9.4 and 1.9.5 are doing something different just between the two of them.
Going to try to build using gradle on a different system to see if anything changes.
The gradle file produces a jar of size 12907 and causes the stack trace.
The ant file produces a jar of size 13126 and does NOT cause the stack trace.
The majority of the size difference comes from the different default entries that appear in MANIFEST.MF, Ant adds a few more like those below. However, something else is the issue as I’ve tried making the MANIFEST.MF contents match as well and it still has the same issue.
Ant-Version: Apache Ant 1.9.5
Created-By: 1.7.0_79-b15 (Oracle Corporation)