Saturday, 24 April 2010

Building EJBs with Clojure

Rich Hickey, the inventor of Clojure, recently announced support for Java annotations in Clojure. This is great news, and in this entry I will show an example of how to create a simple stateless EJB in Clojure.

A simple stateless session bean

I base my example on the simple stateless example from OpenEJB, an embeddable and lightweight EJB 3.0 implementation. I have based my code as closely as possible to the original, for the sake of comparison.

The local interface

The local interface is fairly simple. There are no annotations needed, and is easily written with a simple definterface.

(definterface CalculatorLocal
  (#^int sum [#^int add1, #^int add2])
  (#^int multiply [#^int mult1, #^int mult2]))
The remote interface

The remote interface is remarkably similar to the local interface, but includes our first annotation:

(definterface #^{Remote {}} CalculatorRemote
  (#^int sum [#^int add1, #^int add2])
  (#^int multiply [#^int mult1, #^int mult2]))

The #^{Remote {}} is equivalent to Java’s @Remote annotation on the interface. Note that in order for this code to work, you must import javax.ejb.Remote, as in Java.

The bean

Now that the business interfaces have been implemented, we can now implement the bean itself.

(deftype #^{Stateless {}} CalculatorImpl []
  (sum [this add1 add2]
    (+ add1 add2))
  (multiply [this mult1 mult2]
    (* mult1 mult2)))

Similar to the remote interface, the bean is annotated, this time with #^{Stateless {}} for javax.ejb.Stateless. Otherwise, this type is implemented just like any other using deftype.

And that is all there is to it. You can AOT compile the above forms, and you will have a working stateless session bean you can drop into any EJB container.

Get the bean from GitHub

I have created ejb-annot, a simple Clojure project that implements the above bean, along with some unit tests to show that the bean will work. It uses an embedded OpenEJB instance as the bean container.

To see the bean in action, simply:

git clone
cd ejb-annot
lein deps
lein compile
lein ejb-test

Note that it is ejb-test and not test. This is because OpenEJB seems to have some issues when running from within the same JVM as Leiningen, due to some class loading issues. Also, for OpenEJB to automatically discover the bean, it needs to find an ejb-jar.xml in the same path as the class files.

Final thoughts

Annotations in Clojure are dead simple and will help make Clojure more Java EE friendly. In fact it was an order of magnitude more difficult to get the tests to run within Leiningen than it was to implement the bean and the tests.

I would like to thank Rich for implementing annotations in Clojure. I attempted to add some EJB annotation support in a library last fall, but never completed the project. Now, none of it will be necessary.