Stuart Marks on Java, Software Systems, and other topics

JDK7, Coin, and Making Libraries Fresh and Minty

Word has probably leaked around the InterTubes by this point, and it is in fact true, that I am now working on the JDK.

My new job (alluded to in this blog post from Joe Darcy) is to run through the JDK libraries and upgrade the code to use new language features of Project Coin (features listed here, JSR here). We’re concentrating on four of the Coin features, namely

I’m working on diamond first. I’ve actually been working on this for a few weeks, but a lot of this time has been spent getting up to speed, pulling over and building OpenJDK (most of this work is being done in the open), understanding testing requirements, development procedures, and so forth. So it wasn’t until earlier this week that I pushed my first changeset into OpenJDK. This changeset was a pass over the java.io, java.lang, java.sql, and java.util (exclusive of java.util.concurrent) packages to upgrade them to use the diamond operator. This consisted of a couple hundred conversions spread over 71 files. After hitting a few other areas of the JDK with diamond, I’ll move on to other Coin features.

First, what is this “diamond” operator?

If you’ve ever written any generic Java code, you’ll understand that it can get quite verbose. The “diamond” operator is a new feature in JDK 7 that allows the programmer to omit the type arguments in the construction of a generic object. The compiler will infer the proper type argument. Actually, the diamond “operator” isn’t an operator at all, it’s an empty type argument list. But it looks like a diamond. For example, instead of

List<String> myList = new ArrayList<String>();

one can simply write

List<String> myList = new ArrayList<>();

Big deal, so the code gets a bit shorter. Who cares? Well, sometimes generic types can get pretty complicated. Consider the following:

This isn’t some crazy hypothetical example; this is from real code! The conversion hasn’t been integrated yet, but you can see the original code in src/share/classes/sun/security/krb5/Config.java.

This raises the question of how I found sites where diamond conversion could be done. Fortunately, there’s some pretty good tooling that does the actual finding and fixing almost automatically. I’m using Jackpot, a syntax-level code pattern matcher and transformer. Somebody has already written a Jackpot-based diamond converter, so all I have to do is run it. I’ll dig up and post more information about Jackpot in the future. Basically, though, it’s the same technology that underlies some of the hinting and refactoring features in NetBeans 7.

Actually, making the code changes is the easy part. The hard part is in “all the rest of the stuff.” That is: breaking down the JDK libraries into suitable chunks, filing bugs, sending webrevs around for review, testing, pushing changes, updating bugs, and keeping track of several changesets all at different stages of the process. It’s not really that hard, but it is a fair amount of work, much more than the code changes themselves. Isn’t that always the case?

Although the diamond conversion seems simple, it belies a surprising amount of complexity. I’ll cover some of those issues in future posts. Meanwhile, enjoy the JDK7 library code as it becomes more fresh and minty!

Does this really work? That is, does it handle methods on Hashtable that don’t exist on HashMap, such as elements(), keys(), or rehash()? There are also semantic differences, such as Hashtable being synchronized whereas HashMap is not. I suppose one could use ConcurrentHashMap (as suggested above) instead.

Again, for this effort I’m concentrating first on diamond and then on other Coin features. I agree that it would be good to get rid of uses of Hashtable, though.

Concerning the question if the rule that replaces Hashtable with HashMap works: in RefactoringNG you can do such transition. You can replace Hashtable with HashMap, Hashtable.contains() with HashMap.containsKey(), Hashtable.elements() with HashMap.values().iterator(), and Hashtable.keys() with HashMap.keySet().iterator() and remove Hashtable.rehash(). Then you have to replace Enumeration with Iterator. You can even add empty implementation of the remove method to anonymous subclasses of Enumeration. But I think that such a transition is not very useful. (I have such rules, so if you are interested in, let me know.)