Error formatting macro: pagetree: java.lang.NullPointerException
Skip to end of metadata
Go to start of metadata
You are viewing an old version of this page. View the current version. Compare with Current  |   View Page History

Current clojure-maven-plugin

  • Source at
  • Good:
    • Deployed to Maven Central
    • Does not depend on any specific version of Clojure
      • Written in Java
    • Handles different JDK versions with the Maven toolchain API
    • Handles different operating systems fairly well
    • Does many things
      • compile, test, swank, nailgun, gendoc, autodoc, etc.
  • Not so good:
    • Not developed under the Clojure CA
      • May be unable to get permission from all contributors
    • Tries to do too many things?
    • Forks a new Java sub-process on every execution
    • Confusing configuration variables
    • Bad defaults
      • AOT-compile everything

What do we need?

  • Essential tasks for building & releasing Clojure projects with Maven
    • AOT-compile
    • Run tests
    • Add Clojure sources to a JAR
  • Useful features for developers
    • Automatic namespace discovery from .clj sources
    • Run a REPL, possibly with wrappers like readline
    • Run a SWANK server
    • Run a Nailgun server
    • Execute arbitrary Clojure code with the project's dependencies on the classpath
    • Execute Clojure in-process or forked
  • The ideal
    • Generic way to execute Clojure code during a Maven build
    • With declarative configuration syntax for common tasks


  • Use maven-exec-plugin
    • Supports running any Java class in-process or forked
    • Manages project classpath / dependencies
    • Using it makes the build more script-like, less declarative
  • Use maven-antrun-plugin
    • Supports anything Ant can do
    • Even more flexible than maven-exec-plugin
    • Even more script-like
  • Create a plugin that calls maven-exec-plugin
    • BUT Maven plugins may not depend on other plugins
  • Rewrite clojure-maven-plugin in Java, duplicating some functionality of maven-exec-plugin
    • Configuration option to run in-process or fork
  • Rewrite clojure-maven-plugin in Clojure
    • Can it still launch a process with a different version of Clojure?

Radical Change Thought

Instead of having just "one" plugin, maybe it would be better to break it up to multiple artifacts/plugins, with specific functionality.  For ultimate flexibility I'm guessing each of these artifacts would have to be a separate git repo, with their own lifecycles.

  • org.clojure.mojo/nsdiscovery
    • Namespace discovery code, the existing code, split out.
  • org.clojure.mojo/clojure-maven-embedder
    • Support code to actually execute clojure code, be it in process, forked.
    • Make use of clojure-jsr223 from Armando Blancas ( has signed contributor agreement ), project hasn't been updated since 2009, could be good to also move this under the org.clojure umbrella and give it some new life.  By using a javax.scripting/forking model we keep the direct dependency on clojure outside of the plugin, allowing independent choice of version the end developers project.  This would work well with my idea of having the mojo just a thin umbrella which delegates out to the actual implementation in clojure.
      • Use of jsr223 could probably even be used by the forked VM model as well.
      • Non-forked VMs would preclude any toolchain support/mixed VM
      • jsr223 support would also play well into embedded clojure scripts inside a POM somehow.
  • org.clojure.mojo/clojure-maven-plugin
    • The core of the original plugin
    • A single configurable source directory, with NO namespace configuration settings.  We still use the nsdicovery artifact however, the original reason for namespace selection/filtering was when pulling in multiple clojure projects as git submodules etc.  In a more modular world that we've moved to, with clojars and dependency management, I think this is no longer really needed.  Maybe we need a compiler-directive metadata element that the compiler looks at to ignore/use, which all tools can then use?
    • Stripped down to maybe just the compile goal, and nothing else, default to a temporary output path so we get the strictness of compilation, but no AOT artifacts by default.
    • If we keep each goal, the mojo code should just delegate to an implementation in a supporting artifact - which may or may not be java or clojure based.
  • org.clojure.mojo/clojure-surefire-driver
    • Implements the running of clojure tests using the new surefire 2.7 pluggable provides code, allows reuse of surefires forking model, configuration, debug support etc.
    • The original goal in clojure-maven-plugin could now delegate to this code.
  • org.clojure.mojo/swank-maven-plugin
    • I remember the original code for this goal was actually a separate plugin, maybe it should return to being one?
  • org.clojure.mojo/clojure-archetype
    • I believe Stuart had set one up a long time ago, would be good to pull it back in with everything and update it for the custom packaging etc.

What do other JVM languages do?

  • Scala Maven Plugin
    • add-source goal to add
    • compile and testCompile goals
    • "continuous compilation" goal (infinite loop, compiles on file save)
    • "continuous testing" goal
    • "console" goal starts a REPL
    • "run" goal supports multiple configurations with different main class and arguments
  • JRuby Maven Plugin
    • Still "alpha" as of "Last Published: 07/06/2006"
    • See also JRUBY-434
  • GMaven (Groovy)
    • Includes a Maven archetype for Groovy projects
    • Allows shell-style glob to select files to compile
  • maven-jython-plugin
    • Executes Jython as a sub-process