Sun’s disabling coffee beans

By: on August 2, 2005

As widely reported (even enthusiastically by people other than Sun themselves), Java 1.5 (otherwise known as Tiger, otherwise known as 5.0) has generics. This is done by erasure originally for reasons of backwards compatibility. The idea was that Sun wanted to be able to compile source code with generics in it and run the generated bytecode on old JVMs. However, apparently late in the day, Sun decided not to, citing reasons of missing Exception classes which is a fairly surmountable problem.

So, if you have any Java source file and compile it with javac from the Java 1.5 SDK, the resulting .class files blow up JVMs which don’t support Java 1.5. javac has -source and -target flags so you can do javac -source 1.5 -target 1.4 to try to get it to compile code suitable for 1.4 JVMs. javac blows up saying that source release 1.5 requires target release 1.5.

So, I created a very simple HelloWorld style program which didn’t use generics and compiled it twice: firstly with -source 1.4 -target 1.4 and then with -source 1.5 -target 1.5. The resulting .class file has 1 byte difference between the two versions (in fact, just 1 bit difference). So, I then wrote some code that uses generics, compiled with -source 1.5 -target 1.5, checked that it blew up if run on a 1.4 JVM and then edited this 1 byte in the class file. The change worked and as a result I could run the code with generics on a 1.4 JVM.

I then made use of Java libraries that have been genericifiedized, the most obvious example being the Collections API. I made the same hack and sure enough, it worked.

The danger is of course that you write code which uses APIs which were only introduced in Java 1.5 or worse, APIs who’s behaviour has changed between 1.4 and 1.5. Using javac from the 1.5 SDK will compile against the 1.5 libraries. When you run it in a 1.4 JVM, it’ll be run against the 1.4 libraries. So, you could try to change the libraries that javac compiles against, or you could change the libraries that java runs against — you could make the 1.4 JVM use the 1.5 libraries. For that to happen you would have to unpack all of the Jars in the 1.5 JRE, make the hack on every class, reassemble, point the 1.4 JVM at these hacked libraries and then hope that it all works.

Of course, I’m not sure that you would want to run with the 1.4 JVM when the 1.5 JVM is available unless there was specific behaviour that you wanted. If the cost of validating your products against a 1.5 JVM was exhorbitant then you could continue to use a 1.4 JVM but tell your developers to start using generics, hack up a 1.5 javac coupled with the 1.4 libraries and a hack to change this one magic byte as a development environment and get generics at no extra cost.

Oh and the magic byte? Well, look at the .class files in a hex mode (hexl-mode in emacs works well here). The first 4 bytes are ca fe ba be. The next three bytes are all zeros. Then the next byte is 30 (ASCII 0) for 1.4 and 31 (ASCII 1) for 1.5.


Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>