[英]Clojure defrecord serialization ClassNotFoundException
I was trying to serialise one of my records to a human readable format. 我试图将我的一个记录序列化为人类可读的格式。 While serialising using Java serialiser worked fine I am trying to use print-dup. 虽然使用Java序列化器进行序列化工作正常但我正在尝试使用print-dup。 The problem I am facing is that while writing the record goes fine reading the record results in clojure.lang.LispReader$ReaderException: java.lang.ClassNotFoundException: common.dummy.Doodh. 我面临的问题是,在编写记录时,可以很好地读取记录结果clojure.lang.LispReader $ ReaderException:java.lang.ClassNotFoundException:common.dummy.Doodh。 Am I messing up the namespaces or something? 我搞乱了命名空间或什么? Please note that this is not a problem with Java serialisation. 请注意,这不是Java序列化的问题。 Code below in the simplest form 以下代码以最简单的形式
(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)
)
text file contents: 文本文件内容:
#common.dummy.Doodh["moooh", "Cows"]
Don't use def inside function definitions. 不要在函数定义中使用def。 When you are using def, you create a var in your namespace and possibly manipulate it as a side-effect with every function call. 当您使用def时,您在命名空间中创建一个var,并可能将其作为每个函数调用的副作用进行操作。 Use let-blocks. 使用let-blocks。
If you want to save Clojure data structures in a file, use clojure.edn
. 如果要将Clojure数据结构保存在文件中,请使用clojure.edn
。 It is safe (eg without your knowledge, no functions defined in the file will be invoked) but it allows to enable custom readers (see more below). 它是安全的(例如,在您不知情的情况下,不会调用文件中定义的函数)但它允许启用自定义阅读器(请参阅下文)。
A type defined with defrecord can be printed in a (Clojure-reader-)readable way using pr-str
(thanks to @A. Webb for noting that). 用defrecord定义的类型可以使用pr-str
以(Clojure-reader-)可读方式打印(感谢@A.Web注意到)。 In your example, I don't see why you would not stick to a hash-map in the first place, but if you really need a defrecord here, you may convert it into a readable string before your write it to the file. 在你的例子中,我不明白你为什么不首先坚持使用哈希映射,但如果你真的需要一个defrecord,你可以在将它写入文件之前将其转换为可读的字符串。
(defrecord Doodh [id name]) (defn output [filename obj] (spit filename (pr-str obj)) (defn pull [filename] (with-in-str (slurp filename) (read)))
read
makes your code vulnerable to function calls in the slurped files (like #=(java.lang.System/exit 0)
). 使用read
会使您的代码容易受到slurped文件中的函数调用的攻击(例如#=(java.lang.System/exit 0)
)。 Using a custom reader with EDN 使用带EDN的自定义阅读器
We extend our type Doodh by implementing the toString method of the java.lang.Object interface: 我们通过实现java.lang.Object接口的toString方法来扩展我们的类型Doodh:
(defrecord Doodh [id name] Object (toString [this] (str "#Doodh" (into {} this))))
Because spit uses str, we can now omit the output function and simply invoke spit from eg the REPL: 因为spit使用str,我们现在可以省略输出函数并简单地从例如REPL调用spit:
(spit "Doodh.edn" (map->Doodh {:id "134" :name "Berta"}))
Doodh.edn: #Doodh{:id 134, :name "Berta"} Doodh.edn:#Doodh {:id 134,:name“Berta”}
Now to make sure that the Doodh will be read back, we invoke clojure.edn/read-string
with a custom reader function: 现在为了确保读回Doodh,我们使用自定义读取器函数调用clojure.edn/read-string
:
(defn pull [filename] (->> (slurp filename) (clojure.edn/read-string {:readers {'Doodh map->Doodh}})))
If you read back "Doodh.edn" using the new pull, you should receive a valid Doodh. 如果您使用新拉回读“Doodh.edn”,您应该收到有效的Doodh。 At the REPL: 在REPL:
(pull "Doodh.edn") => #user.Doodh{:id 134, :name "Berta"}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.