使用 Java 对象作为 Clojure 映射

2022-09-03 05:17:08

我有一个Java类,我想在Clojure中使用。但是,我想将其用作Clojure地图。这样做需要采取哪些步骤?

我已经查看了代码 - Java类应该实现它吗?或者应该有一些实现协议的Clojure代码?IPersistentMap

我知道我可以编写一些映射代码,将代码从Java对象显式转换为映射,但是该解决方案具有很高的努力/回报率。此外,我可能会遇到同样的情况很多次。


具体的例子:我有一个用Java编写的解析器。我想用它来解析一些文本,然后访问解析的数据结构的内容,就好像它在Clojure映射中一样:

(def parser (new MyParser))

(let [parse-tree (parser ... parse some text ...)]
  ((parse-tree :items) "itemid"))

答案 1

函数bean浮现在脑海中:

获取 Java 对象,并基于其 JavaBean 属性返回映射抽象的只读实现。

取自网站的示例:

user=> (import java.util.Date)
java.util.Date

user=> (def *now* (Date.))
#'user/*now*

user=> (bean *now*)
{:seconds 57, :date 13, :class java.util.Date,
 :minutes 55, :hours 17, :year 110, :timezoneOffset -330,
 :month 6, :day 2, :time 1279023957492}

答案 2

当然,(参见bean ClojureDoc)工作得很好,但它不让你选择你想要的属性和你不想要的属性。当您将生成的映射输入到函数中时,它会产生影响,在这种情况下,您可能会收到一个错误:“不知道如何编写以下 JSON:(bean javaObject)json-str

当我处理NoSQL DB(mongoDB,neo4j)时,我发现这很烦人,它基本上接受JSON(就像neocons的基础一样)。

那么我的解决方案是什么呢?

(defmacro get-map-from-object-props [object & props]
  ;->> will eval and reorder the next list starting from the end
  (->> (identity props) ;identity is here to return the 'props' seq
       ;map each property with their name as key and the java object invocation as the value
       ;the ~@ is here to unsplice the few properties
       (map (fn [prop] [(keyword (str prop)) `(.. ~object ~@(prop-symbol prop) )]))
       (into {})))

;getter is a simple function that transform a property name to its getter "name" -> "getName"
(defn prop-symbol [prop]
  (map symbol (map getter (clojure.string/split (str prop) #"\\."))))

你可以这样使用它(是的,该函数会处理一连串的属性(如果有的话)

(get-map-from-object-props javaObject property1 property2 property3.property1)

希望能帮助别人...


推荐