Friday, May 18, 2012

Building Modern Clojure-now-with-reducers! with JDK 6


The Clojure times, they are a-changin'. Time was, an enterprising young hacker could just clone the Clojure repo from GitHub, run ant to build it, then hack h[er|is] way to [fame|glory]. Now, with the advent of reducers, those days are sadly gone. Or at least slightly delayed.

You see, reducers require some ultra-modern Java-isms; namely, java.util.concurrent.ForkJoin[Pool|Task]. If you have JDK 7 installed as your default JDK (or can arrange to so install it), you have everything you need and your Clojure build should Just Work™.

If you're stuck with JDK 6, you may have a bit more work to do. Your main symptom will be that your Clojure build does *not* Just Work™, but rather fails with an exception of the form java.lang.ClassNotFoundException: jsr166y.ForkJoinPool.

The Clojure Maven build now declares a dependency on an artifact called jsr166y, which provides an implementation of the needed ForkJoin... classes. Running mvn package will detect the new dependency, download the correct jar to your ~/.m2/ directory, and include that jar on the build classpath.

If you prefer to use ant instead of Maven (as I do), you have yet more work to do.

One thing you could do is download the jsr166y jar, stash it somewhere, and manually add it to your classpath. That seems kind of tedious to me; but I guess your tolerance level for tedium could be higher than your tolerance level for Maven.

Luckily, the Clojure core team has anticipated your preference for ant, and they want to alleviate your tedium. Unluckily, their solution actually uses Maven behind the scenes; you ant purists may want to stop reading at this point and just go download the jar and add it to your classpath.

Right before they committed the changes to implement reducers, the Clojure core team added the Maven dependency on jsr166y. Also, for medium-core ant fans, they added a one-time script at the top level of the project: antsetup.sh. Run that script once to create a new file: maven-classpath.properties (and download the jsr166y jar from some Maven repo if you don't already have it). The ant build now includes that properties file and adds the classpath it specifies to the ant build classpath and you're good to go.

Oh. Except for the whole having to sit on the sidewalk ringing a bell and chanting "Unclean!" at regular intervals. But that's a small price to pay for Clojure [fame|glory], right?