[英]Clojure defrecord serialization ClassNotFoundException
我試圖將我的一個記錄序列化為人類可讀的格式。 雖然使用Java序列化器進行序列化工作正常但我正在嘗試使用print-dup。 我面臨的問題是,在編寫記錄時,可以很好地讀取記錄結果clojure.lang.LispReader $ ReaderException:java.lang.ClassNotFoundException:common.dummy.Doodh。 我搞亂了命名空間或什么? 請注意,這不是Java序列化的問題。 以下代碼以最簡單的形式
(ns common.dummy)
(defrecord Doodh [id name])
(defn output [filename obj]
(def trr(map->Doodh {:id "moooh" :name "Cows"}))
(def my-string (binding [*print-dup* true] (pr-str trr)))
(spit filename my-string)
)
(defn pull [filename]
(def my-data (with-in-str (slurp filename) (read)))
(println my-data)
)
文本文件內容:
#common.dummy.Doodh["moooh", "Cows"]
不要在函數定義中使用def。 當您使用def時,您在命名空間中創建一個var,並可能將其作為每個函數調用的副作用進行操作。 使用let-blocks。
如果要將Clojure數據結構保存在文件中,請使用clojure.edn
。 它是安全的(例如,在您不知情的情況下,不會調用文件中定義的函數)但它允許啟用自定義閱讀器(請參閱下文)。
用defrecord定義的類型可以使用pr-str
以(Clojure-reader-)可讀方式打印(感謝@A.Web注意到)。 在你的例子中,我不明白你為什么不首先堅持使用哈希映射,但如果你真的需要一個defrecord,你可以在將它寫入文件之前將其轉換為可讀的字符串。
(defrecord Doodh [id name]) (defn output [filename obj] (spit filename (pr-str obj)) (defn pull [filename] (with-in-str (slurp filename) (read)))
read
會使您的代碼容易受到slurped文件中的函數調用的攻擊(例如#=(java.lang.System/exit 0)
)。 使用帶EDN的自定義閱讀器
我們通過實現java.lang.Object接口的toString方法來擴展我們的類型Doodh:
(defrecord Doodh [id name] Object (toString [this] (str "#Doodh" (into {} this))))
因為spit使用str,我們現在可以省略輸出函數並簡單地從例如REPL調用spit:
(spit "Doodh.edn" (map->Doodh {:id "134" :name "Berta"}))
Doodh.edn:#Doodh {:id 134,:name“Berta”}
現在為了確保讀回Doodh,我們使用自定義讀取器函數調用clojure.edn/read-string
:
(defn pull [filename] (->> (slurp filename) (clojure.edn/read-string {:readers {'Doodh map->Doodh}})))
如果您使用新拉回讀“Doodh.edn”,您應該收到有效的Doodh。 在REPL:
(pull "Doodh.edn") => #user.Doodh{:id 134, :name "Berta"}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.