Clojure Goodness: Turn Java Object To Map With bean Function
The map data structure is used a lot in Clojure. When we want to use Java objects in our Clojure code we can convert the Java object to a map with the bean
function. This function will use reflection to get all the properties of the Java object and converts each property with the property value to a key with value in the resulting map. The bean
function will not recursively convert nested objects to a map, only the top-level properties are turned into key value pairs.
We see several examples of using the bean
function in the following code snippet:
(ns mrhaki.core.bean
(:require [clojure.test :refer [is]])
(:import (java.net URI)
(mrhaki.java Person Address)))
(is (= {:path "",
:rawQuery "search=clojure",
:fragment nil,
:authority "www.mrhaki.com",
:rawAuthority "www.mrhaki.com",
:port -1,
:absolute true,
:host "www.mrhaki.com",
:rawPath "",
:opaque false,
:rawSchemeSpecificPart "//www.mrhaki.com?search=clojure",
:class java.net.URI,
:rawUserInfo nil,
:query "search=clojure",
:rawFragment nil,
:scheme "https",
:userInfo nil,
:schemeSpecificPart "//www.mrhaki.com?search=clojure"}
(bean (URI. "https://www.mrhaki.com?search=clojure"))))
(comment "For the next sample we use a Java class Person
with properties name and alias of type String and
a third property of type Address. The Java class Address
has a single String property city.
Pseudo code:
class Person { String name, alias; Address address; }
class Address { String city; }")
(def person (Person. "Hubert" "mrhaki" (Address. "Tilburg")))
(is (= {:name "Hubert" :alias "mrhaki"}
(select-keys (bean person) [:name :alias])))
;; Properties with custom classes are not automatically
;; also converted to a map representation.
(is (instance? mrhaki.java.Address (:address (bean person))))
(is (= {:city "Tilburg"}
(select-keys (bean (:address (bean person))) [:city])))
(is (= {:address {:city "Tilburg", :class mrhaki.java.Address},
:alias "mrhaki",
:class mrhaki.java.Person,
:name "Hubert"}
(assoc (bean person) :address (bean (.getAddress person)))))
Written with Clojure 1.10.1.