Search code examples
clojurejava-17java-record

How to convert Java 17 record to Clojure map?


There is a standard function clojure.core/bean converting POJO to map:

class MyPojo{
  public String getFirst(){ return "abc"; }
  public int getSecond(){ return 15; }
}

IFn bean = Clojure.var("clojure.core", "bean")

var result = bean.invoke(new MyPojo())

// result => {:first = abc, :second = 15}

For Java 17 record classes this function would not work, because records do not follow POJO convention "get***" for properties.

Is there Clojure support for Java 17 record instances in the same manner?


Solution

  • Java 16 introduces Class.getRecordComponents. So given an instance of a record, you can look up the record's class, and from there its record components. Each record component has a name and a getter Method, which you can use to look up the value of that component. You can put these pieces together to build an analogue of bean.

    (defn record->map [r]
      (into {} (for [^java.lang.reflect.RecordComponent c (seq (.getRecordComponents (class r)))]
                 [(keyword (.getName c))
                  (.invoke (.getAccessor c) r nil)])))