One of the constraints when you work on fundamental software is that you need to be very careful about the classes that you ship. Not just the code itself, but also the version of the compiler that you used to compile these classes.
Despite all my precautions, I have sometimes accidentally shipped classes that were using a compiler that’s too recent. The latest occurrence of this incident was with TestNG’s Eclipse plug-in. Despite all the settings specifying that the JDK should be 1.5, I ended up with 1.6 classes in the feature jar file. I eventually figured out that when you actually build the update site, Eclipse uses some ant tasks which seem to ignore the Eclipse preferences and which revert to the global environment’s JAVA_HOME.
So I ended up writing a quick script that makes one last check before actually uploading the files to the site, which I thought some people might find interesting:
for i in `find . -name \*class` do v=`od -h $i | head -1 | awk '{print $5}'` if [ $v != "3100" ] then echo "Class $i has version $v, expected 3100" exit -1 fi done
#1 by Andrew Binstock on February 21, 2011 - 9:41 pm
I have long held that there should be a full inventory check of the delivered product performed at the end of the CI cycle. This check should:
1) make sure all files are present and no extra files have crept in
2) verify the internal version number of the components
3) verify the language level (your point)
4) verify that all the files are virus-free
ISVs are about the only development orgs that do this regularly. OSS projects and in-house app dev teams almost never do. IMO, this should be a standard best practice that’s a regular part of the the CI cycle.
Pingback: Tweets that mention Verifying the version of your Java classes « Otaku, Cedric's blog -- Topsy.com
#2 by ipsi on February 21, 2011 - 10:53 pm
It’s worth noting that you could probably do the same thing with ‘javap’, which is a disassembler for Java bytecode. Would it be easier or harder? Not sure. But it’s definitely another option if you’d prefer not to go reading bytes directly from the header of a class file.
Of course, javap is also useful for a number of other things, but that’s outside the scope of this post.
#3 by Robert Kovacevic on February 22, 2011 - 2:01 am
Nice, could come in handy. We had the same problem a couple of times, but I was proposing that solution is to have a clean build environment, instead of doing builds on dev machines.
#4 by Justin Lee on February 22, 2011 - 6:16 am
Using the unix file command also returns the bytecode version without so many hoops to jump through.
#5 by Ketan Padegaonkar on February 22, 2011 - 6:27 am
It’s always a good idea to set the source and target versions on javac tasks. Also the following script is a oneliner for the script you mention:
find . -name ‘*.class’ | xargs file
#6 by Martin on February 22, 2011 - 7:41 am
To get this to work on linux (as well as OSX), use:
od -t x2