我有一个我想在Clojure中使用的Java类。但是,我想将它用作Clojure地图。这样做的步骤是什么?
我查看了IPersistentMap
的代码 - Java类应该实现吗?或者是否应该有一些实现协议的Clojure代码?
我知道我可以编写一些映射代码,将代码从Java对象显式转换为映射,但该解决方案具有很高的工作/回报率。此外,我可能会多次遇到同样的情况。
具体示例:我有一个用Java编写的解析器。我想使用它来解析一些文本,然后访问解析数据结构的内容,就好像它是在Clojure映射中一样:
(def parser (new MyParser))
(let [parse-tree (parser ... parse some text ...)]
((parse-tree :items) "itemid"))
答案 0 :(得分:22)
我想到了函数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}
答案 1 :(得分:5)
当然(bean javaObject)
(请参阅bean ClojureDoc)效果很好,但它不会让您选择所需的属性和不属于您的属性。将结果映射输入json-str
函数时会产生影响,在这种情况下,您可能会收到错误消息:“不知道如何编写JSON ......”
当我处理基本接受JSON的NoSQL DB(mongoDB,neo4j)时,我觉得很烦人。(就像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)
希望能帮到某人......
答案 2 :(得分:1)
Clojure关键字可以查找实现java.lang.Map接口所需(只读)部分的任何内容。问题可能是你实际上没有使用clojure关键字作为键,所以这可能对你没有帮助。
IPersistentMap;你的解析器可能没有实现与该接口相关的任何东西。
就个人而言,我会写一个直接转换函数。 Clojure使用了很多这些(例如seq),转换后,你知道你正在处理一个真正的持久性地图,而不是某些时候只能表现得像的东西(所以你可以实际上在它上面调用seq,keys,vals等。)
可替换地;
答案 3 :(得分:1)
如果只使用带有(实习)字符串的java.util.HashMap作为键,并在几行Clojure中进行转换呢?:
(into {} (java.util.HashMap. {"foo" "bar" "baz" "quux"})) ?
{"foo" "bar" "baz" "quux"}
或使用关键字:
(into {}
(map
(juxt
#(keyword (key %))
#(val %))
(java.util.HashMap. {"foo" "bar" "baz" "quux"})))
{:baz "quux", :foo "bar"}
答案 4 :(得分:0)
bean
可以正常工作,但是不能很好地处理某些Java对象。
(import java.awt.Insets)
(bean (Insets. 1 2 3 4))
=> {:class java.awt.Insets}
但是有一个Java解决此Java问题的方法:
(import (com.fasterxml.jackson.databind ObjectMapper))
(import (java.util Map))
(into {} (.. (ObjectMapper.) (convertValue (Insets. 1 2 3 4) Map)))
=> {"top" 1, "left" 2, "bottom" 3, "right" 4}
答案 5 :(得分:-2)
user=> (defn parser [text]
"{ :items { \"itemid\" 55 }}");Mock
user=> (let [parse-tree (read-string (parser "Abracadabra"))]
((parse-tree :items) "itemid"))
55