Plain Old Clojure Object

Those times you need to have Java APIs.. Some of these APIs need to return data. In Clojure it is usually a map:

{:q “What is..?” :a 42}

In Java it is not that simple for several reasons.. Java maps are mutable, there are no idiomatic tools to inspect, destructure them, Java (programmers) like different types for different POJOs, etc..

So this data needs to be encapsulated in a way Java likes it, usually in a form of an object with private fields and getters with no behavior, i.e. POJOs.

Of course a Clojure project may have Java sources, where these POJOs can live, but why not just stick to Clojure all the way and create them using gen-class. Why? Because it is fun, and also because we can easily :require and use other Clojure libraries in these POJOs in case we need to.

JSL: Java as a second language


Oh yea, and let’s call them POCOs, cause they kind of are:

(ns poco)
 
(gen-class 
  :name org.stargate.PlainOldClojureObject
  :state "state"
  :init "init"
  :constructors {[Boolean Boolean String] []}
  :methods [[isHuman [] Boolean]
            [isFound [] Boolean]
            [planet [] String]])
 
(defn -init [human? found? planet]
  [[] (atom {:human? human?
             :found? found?
             :planet planet})])
 
(defn- get-field [this k]
  (@(.state this) k))
 
(defn -isHuman [this]
  (get-field this :human?))
 
(defn -isFound [this]
  (get-field this :found?))
 
(defn -planet [this]
  (get-field this :planet))
 
(defn -toString [this]
  (str @(.state this)))

This compiles and behaves exactly like a Java POJO would, since it is a POJO, I mean POCO:

user=> (import '[org.stargate PlainOldClojureObject])
org.stargate.PlainOldClojureObject
 
user=> (def poco (PlainOldClojureObject. true true "42"))
#'user/poco
 
user=> poco
#object[org.stargate.PlainOldClojureObject 0x68033b90 "{:human? true, :found? true, :planet \"42\"}"]
 
user=> (.isHuman poco)
true
user=> (.isFound poco)
true
user=> (.planet poco)
"42"

Of course there are records, but POCOs are just more fun 🙂