假设我有一个简单的类
class Person
attr_accessor :name
def say
puts name
end
end
有没有办法将它序列化为JSON并返回并获取同一类的实例? 例如,我希望有一个像
这样的代码p = Person.new
p.name = 'bob'
json = JSON.serialize p
# json should be smth. containing { 'name' : 'bob' }
# and maybe some additional information required for later deserialization
p2 = JSON.deserialize
p2.say
# should output 'bob'
我尝试了as_json(我猜测来自ActiveSupport),但结果是{' name':' bob'}显然类型信息丢失,反序列化后我只有哈希,不是Person实例。
答案 0 :(得分:1)
Ruby的JSON库支持Marshal接口。简答:您需要在班级中定义#to_json
和self#json_create
。
诀窍是你需要在json本身中存储要往返的类的名称;执行此操作的默认位置是键json_class
的值,并且可能没有理由更改它。
这是一个非常简单的例子:
require 'json'
class A
attr_accessor :a,:b
def initialize(a,b)
@a = a
@b = b
end
def to_json(*a)
{
"json_class" => self.class.name,
"data" => {:a => @a, :b=>@b}
}.to_json(*a)
end
def self.json_create(h)
self.new(h["data"]["a"], h["data"]["b"])
end
end
然后,您可以使用JSON.generate
和JSON.load
来往返。请注意,JSON.parse
不工作;它只会给你预期的哈希值。
[29] pry(main)> x = A.new(1,2)
=> #<A:0x007fbda457efe0 @a=1, @b=2>
[30] pry(main)> y = A.new(3,4)
=> #<A:0x007fbda456ea78 @a=3, @b=4>
[31] pry(main)> str = JSON.generate(x)
=> "{\"json_class\":\"A\",\"data\":{\"a\":1,\"b\":2}}"
[32] pry(main)> z = JSON.load(str)
=> #<A:0x007fbda43fc050 @a=1, @b=2>
[33] pry(main)> arr = [x,y,z]
=> [#<A:0x007fbda457efe0 @a=1, @b=2>, #<A:0x007fbda456ea78 @a=3, @b=4>, #<A:0x007fbda43fc050 @a=1, @b=2>]
[34] pry(main)> str = JSON.generate(arr)
=> "[{\"json_class\":\"A\",\"data\":{\"a\":1,\"b\":2}},{\"json_class\":\"A\",\"data\":{\"a\":3,\"b\":4}},{\"json_class\":\"A\",\"data\":{\"a\":1,\"b\":2}}]"
[35] pry(main)> arr2 = JSON.load(str)
=> [#<A:0x007fbda4120a48 @a=1, @b=2>, #<A:0x007fbda4120700 @a=3, @b=4>, #<A:0x007fbda4120340 @a=1, @b=2>]