OpenJDK is a very good thing - but you have to test for it
When one month ago it has been announced that OpenJDK had been freed by the last encumbrances, I said I was happy: it was really great news, an important milestone in the opensourcing of Java. A proof of the important benefits of that milestone has been given by the inclusion of OpenJDK in more and more Linux distributions.
But I also said another thing: that even though OpenJDK is guaranteed to be Java, in the sense that it passes the Test Compatibility Kit, if you wish to deploy an application with no Java embedded and you imagine that it could be run with either Sun's JDK/JRE or OpenJDK you have to esplicitly test for both. From my point of view, it is an obvious thing: the two things are different bits, and when you have different bits you have to test for all, even if both are certified in the same way. There's no such a thing as a perfect certification. Looking at comments to my post and other related blogs, not everybody agreed with me.
Unfortunately, I was right, as I've just discovered I'm a first victim of the thing. One of the milestones that I hoped to achieve with blueMarine 0.9.RC3 was the compability with OpenJDK, but now that I managed in testing it, I discovered a showstopper.
In a few words, I made a big mistake in jrawio, which is a ImageI/O provider. I registered some services by means of the META-INF/services facility, and I put them under META-INF/services/javax.imageio.spi.ImageReaderSpi, while two of them are indeed implementations of another interface, ImageInputStreamSpi.
Now, since this code exists since two years and is inside all the versions of blueMarine that have been released in the meantime, it appears that Sun's JDK is forgiving; while OpenJDK throws a ClassCastException:
[exec] java.lang.ClassCastException: Cannot cast it.tidalwave.imageio.io.FileImageInputStream2Spi to javax.imageio.spi.ImageReaderSpi
[exec] at java.lang.Class.cast(Class.java:3007)
[exec] at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:362)
[exec] Caused: java.util.ServiceConfigurationError: javax.imageio.spi.ImageReaderSpi: Provider it.tidalwave.imageio.io.FileImageInputStream2Spi could not be instantiated
[exec] at java.util.ServiceLoader.fail(ServiceLoader.java:224)
[exec] at java.util.ServiceLoader.access$100(ServiceLoader.java:181)
[exec] at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:370)
[exec] at java.util.ServiceLoader$1.next(ServiceLoader.java:438)
[exec] at javax.imageio.spi.IIORegistry.registerApplicationClasspathSpis(IIORegistry.java:210)
[exec] at javax.imageio.ImageIO.scanForPlugins(ImageIO.java:109)
Now, I'd like to point out two things:
- the behaviour of OpenJDK seems to be more correct than the one of Sun's JDK, but it's a gray area AFAIK (it's exactly the kind of gray area I feared);
- it's a fault of mine, and is probably related to lack of tests in jrawio (I still didn't understand what happens to the mistakenly registered services: they are just ignored or they are instantiated? In the latter case, something should be broken in blueMarine, but I didn't realize. To tell the truth this involves the support for a specific Canon file format, which I could have test badly).
Nevertheless, the point is that I have an application which runs quite well on Linux boxes with Sun's JDK; doesn't at all with OpenJDK. I specifically tested it, so I discovered the problem. If I had only announced that blueMarine is automatically fine with OpenJDK I would have faced with shame and disgrace ;-)
So, the morale is that whenever there's a single bit different from a tested configuration, you have to test again. It's the basic rule and you should stick with it.