The problem
We’re considering upgrading to Java 1.4.2 from 1.4.0 on our production servers. Taking the bold step of trying this out in development first uncovered a weird issue: whenever running code with 1.4.2 (whether via Tomcat or junit tests w/ant) we got these errors:
[junit] Oct 27, 2003 5:08:49 PM java.util.jar.Attributes read [junit] WARNING: Duplicate name in Manifest: Class-Path
How I fixed it
- google search: nada.
- Does this mean we have duplicate jars in the classpath? Use
ant -verbose test
to find out. (Oi, 77 entries. I hate classpath issues.) Nothing obvious, but this doesn’t stop me fiddling fruitlessly with build.xml to no effect. - What the hell is a manifest file again? Google provides. A manifest file is created whenever you create a JAR file. Hey, maybe we have a Manifest file in one of our JARs with a duplicate Class-Path entry. (It should be obvious at this point why I get paid the big bucks.)
- So we have somewhere around 70 jar files that could have an extra Class-Path line. (I hate classpath issues.)
- We need to: unpack each one, grep for Class-Path, repeat.
- I copy all suspect JARs to a temp dir and start doing this. Eventually I remember that computers are good at automating repetitive tasks (who knew?) and write a quick shell script:
#!/bin/tcsh jar xf $1 chmod +x META-INF grep -i class META-INF/MANIFEST.MF echo "Finished looking at $1" rm $1 rm -r META-INF/ ls
- Now I can quickly scan a particular jar with
quick.sh foo.jar
. (Full disclosure aside: this is just the final quick.sh; the chmod line is there because I was initially using unzip -l instead of jar xf and it would sometimes not have execute perms on the dirs. As it is now, I don’t think it’s necessary.) - Eventually, I find the cuplrit: struts.jar.
Great! Now I’ve identified the problem, I just need to fix it. This involves unpacking struts.jar, fixing the manifest file (instead of multiple Class-Path: lines with one jar per line, one Class-Path line with multiple jars separated by spaces), and repacking the jar ( jar cmf ../MANIFEST.MF struts.jar *
). Test runs now have regular output. Joy.
What I’d do differently next time
- Read the error message more carefully. Went a bit down the wrong road because of this.
- I haven’t checked this, but I suspect if I read through the release notes for 1.4.2 (and maybe 1.4.1) I’ll find reference to this change.
- I suspect if I’d stopped and thought a bit, I could have come up with an even cleaner solution to looking through all those jar files; it could even be that there’s a tool out there for doing just that. If I had greater facility with shell scripts, I could also have done it that way.
Update: Did some browsing of sun’s Java forums, which are unfortunately behind a registration wall, and therefore not indexed by search engines. [That this is stupid is fairly evident, so I won’t comment further upon it.] What I learned is:
- The specification is clear that if there is more than one Class-Path entry, only the last will be used. Unfortunately, there is a tutorial somewhere on sun.com that says otherwise. This has resulted in many a bug.
- There is also a 72 byte limit to manifest file lines. You can use SPACE + NEWLINE as a continuation marker (again, this is in the spec.)
- There is a bug (registration required) that documents the change. This bug is still marked as in progress at this time, although the description indicates it’s a 1.4.2 change
- Nothing in 1.4.2’s changes file or README document this change.