Using Maven as a build tool for Clojure

Hi,

I’ve been using Clojure for some time but I’ve never used Maven as my build tool (when using Clojure).

The reason why I want to use Maven is because the company I work at is a java-enterprise-company and maven fits well with the ci/cd-pipeline.

2 Likes

Not sure if that counts as “widely used” but ClojureScript uses it. I’ve also seen other projects use it so seems fine to me. Dunno about the test parts though.

I’m using the clojure-maven-plugin in a Java project to which I’ve added some clojure, and it works ok for the basic stuff. You can run a REPL, run tests (but not with every testing framework; IIRC there’s no runner for Midje for instance), and of course build your project. If your project is Clojure-only, I’m not sure it’s worth the hassle, though, but if you’re doing some mixed Java/Clojure stuff, it gets the job done.

1 Like

Also interesting is Stu Halloway’s drop-dead simple example of calling Clojure from Java, using Maven to package the code (as usual with Java projects).

1 Like

Apache storm previous versions pom.xml is the best place I guess

1 Like

A minimal config could be:

<properties>
  <clojure.nrepl.host>localhost</clojure.nrepl.host>
  <clojure.nrepl.port>4005</clojure.nrepl.port>
</properties>

<plugins>
  <plugin>
    <groupId>com.theoryinpractise</groupId>
    <artifactId>clojure-maven-plugin</artifactId>
    <version>1.8.1</version>
    <extensions>true</extensions>
    <executions>
      <execution>
        <id>clojure-compile</id>
        <phase>compile</phase>
        <goals>
          <goal>compile</goal>
        </goals>
      </execution>
      <execution>
        <id>clojure-test</id>
        <phase>test</phase>
        <goals>
          <goal>test</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <sourceDirectories>
        <sourceDirectory>src/main/clojure</sourceDirectory>
      </sourceDirectories>
      <testSourceDirectories>
        <testSourceDirectory>src/test/clojure</testSourceDirectory>
      </testSourceDirectories>
      <nreplMiddlewares>
        <middleware>cider.nrepl.middleware.apropos/wrap-apropos</middleware>
        <middleware>cider.nrepl.middleware.classpath/wrap-classpath</middleware>
        <middleware>cider.nrepl.middleware.complete/wrap-complete</middleware>
        <middleware>cider.nrepl.middleware.format/wrap-format</middleware>
        <middleware>cider.nrepl.middleware.info/wrap-info</middleware>
        <middleware>cider.nrepl.middleware.inspect/wrap-inspect</middleware>
        <middleware>cider.nrepl.middleware.macroexpand/wrap-macroexpand</middleware>
        <middleware>cider.nrepl.middleware.ns/wrap-ns</middleware>
        <middleware>cider.nrepl.middleware.pprint/wrap-pprint</middleware>
        <middleware>cider.nrepl.middleware.resource/wrap-resource</middleware>
        <middleware>cider.nrepl.middleware.stacktrace/wrap-stacktrace</middleware>
        <middleware>cider.nrepl.middleware.test/wrap-test</middleware>
        <middleware>cider.nrepl.middleware.trace/wrap-trace</middleware>
        <middleware>cider.nrepl.middleware.trace/wrap-refactor</middleware>
        <middleware>cider.nrepl.middleware.undef/wrap-undef</middleware>
      </nreplMiddlewares>
    </configuration>
  </plugin>
</plugins>

And of course, you need to add all your dependencies, as you would other dependencies.

1 Like

If Gradle is an option, clojurephant provides Clojure and ClojureScript support.

Here is a good, simple working Maven Clojure build. With your Clojure code in src/main/clojure, this will build a JAR with just your .clj code.

(clojure-maven-plugin has various options to retain or remove any AOT code from the resultant JAR; here I’m using temporaryOutputDirectory to make sure only the .clj files get packaged.)

There are good resources online for how to extend any POM to build an uber jar (Lein does this out of the box, I think, as uber jars are a common way to deploy clojure apps).

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>simple.clojure.build</groupId>
    <artifactId>example</artifactId>
    <version>0.1-SNAPSHOT</version>
    <packaging>clojure</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.clojure</groupId>
            <artifactId>clojure</artifactId>
            <version>1.10.1</version>
        </dependency>
        <dependency>
            <groupId>org.clojure</groupId>
            <artifactId>core.async</artifactId>
            <version>0.4.490</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>com.theoryinpractise</groupId>
                <artifactId>clojure-maven-plugin</artifactId>
                <version>1.8.2</version>
                <extensions>true</extensions>
                <configuration>
                    <temporaryOutputDirectory>true</temporaryOutputDirectory>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>clojars.org</id>
            <url>http://clojars.org/repo</url>
        </repository>
    </repositories>

</project>