Java 9 was recently released on September 21st, 2017. If you’re a Clojure developer, you’re probably keen to try it out to see some of the new features and performance improvements available. To do so, you need to do a few things. For most projects, this will be a small to moderate amount of work.
Leiningen has been updated to include support for Java 9. You need to upgrade to at least 2.8.0 to be able to use it. At the time of writing 2.8.1 is the latest version available. Run
lein upgrade 2.8.1 or simply
lein upgrade to get the latest version.
Boot has also been updated to include support for Java 9. Support was added in Boot 2.7.0. This was released in December 2016, so you are probably already using it. Update boot with
boot -u to get the latest version.
Add the java.xml.bind module
One of the new features in Java 9 is modules. At the time of writing, the latest release of ClojureScript depends on
java.xml.bind package has been deprecated in Java 9 and put inside a non-default module. If you try to compile a ClojureScript project without adding this module, you will get an error like this:
<Exception details> ... Caused by: java.lang.ClassNotFoundException: javax.xml.bind.DatatypeConverter
To get access to it, you need to add the new JVM option
--add-modules "java.xml.bind". In Leiningen you can add
:jvm-opts ["--add-modules" "java.xml.bind"] to your
project.clj file. CLJS-2377 tracks this issue, and it has already been resolved on master. You can also add
-Djdk.launcher.addmods=java.xml.bind to the environment variable
--add-modules doesn’t work when set in
JAVA_TOOL_OPTIONS). I recommend setting this with direnv to help everyone on your team use the same settings.
If you need to run your project with Leiningen on both Java 8 and Java 9 then you will run into trouble by just adding
:jvm-opts ["--add-modules" "java.xml.bind"]. Depending on your version of Java 8 and Leiningen, you will get an error.
Unrecognized option: --add-modules Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. Error encountered performing task 'do' with profile(s): 'base,system,user,provided,dev,dev-run' Subprocess failed
This is because older JVM’s don’t understand the new option. One workaround is to detect the version of the JDK that your system is using with a bash script, and only set
JAVA_TOOL_OPTIONS when 9 or up is detected. Another possibility is to add this to your
project.clj and let Leiningen apply the settings when it starts up (This method was suggested by Peter Monks).
:jvm-opts ~(let [version (System/getProperty "java.version") [major _ _] (clojure.string/split version #"\.")] (if (>= (java.lang.Integer/parseInt major) 9) ["--add-modules" "java.xml.bind"] ))
Upgrade your libraries
Toby Crawley has a list of libraries affected by old versions of Dynapath, along with other Java 9 issues. There are many other Java and Clojure dependencies affected by changes in Java 9, so it’s worth checking for updates before you upgrade. One of note is http-kit which also depends on
New versions of Clojure and ClojureScript
If you’ve applied the steps above, you won’t need to upgrade Clojure or ClojureScript. However they both have fixes to improve compatibility with Java 9. ClojureScript 1.10.63 and up include CLJS-2377 which avoids depending on
java.xml.bind. Clojure 1.9-beta1 has support for running on the bootclasspath under Java 9. If you don’t want to upgrade Leiningen to 2.8.1, then upgrading Clojure to 1.9-beta1 or higher should also work.