我在Mac上编写了dictation gem,反序列化工作正常。当我在另一台Mac上安装它时,它将无法工作,因为它失败了#34;反序列化对象,因为它只能反序列化为哈希。
我也尝试过两种不同的Ruby版本和Gem版本,但它们都不起作用,只是我第一次编写它的初始版本。
当我在工作环境中尝试此代码时:
require 'json'
class Word
attr_accessor :value, :translation
def initialize(value, translation)
@value = value
@translation = translation
end
def to_json(*args)
{
'json_class' => self.class.name,
'data' => [ @value, @translation ]
}.to_json(*args)
end
class << self
def json_create(object)
new(*object['data'])
end
end
end
str = '{"json_class":"Word","data":["Morgen","Tomorrow"]}'
p JSON.parse(str)
它打印一个Word对象,这是预期的:
#<Word:0x007fcce22c9c58 @translation="Tomorrow", @value="Morgen">
对于其他环境,它总是打印一个哈希:
{"json_class"=>"Word", "data"=>["Morgen", "Tomorrow"]}
我也尝试传递:object_class key
,它引发了另一个例外:
p JSON.parse(str, :object_class => Word)
# => ArgumentError: wrong number of arguments (0 for 2)
我无法在运行时使用以下内容找出require 'json'
版本:
puts Gem.loaded_specs['json'].version
因为Gem.loaded_specs.keys
不包含它。
感谢任何提示。
答案 0 :(得分:1)
从JSON lib的作者那里回复 - 由于安全原因,在较新版本上反序列化自定义对象,您可以:
JSON.parse(str, :create_additions => true)
或者你可以:
JSON.load(str)
所以,我忽略了ruby-doc中的JSON#load部分:
load(source, proc = nil, options = {})
从JSON源加载ruby数据结构并将其返回。来源 可以是类似字符串的对象,类似IO的对象,也可以是对象 响应read方法。如果给出了proc,它将被调用 首先以深度递归方式将任何嵌套的Ruby对象作为参数 订购。要修改默认选项,请在可选选项中传递 论证也是如此。
注意:此方法用于序列化来自可信用户的数据 输入,例如来自您自己的数据库服务器或您的客户端 控制,允许不受信任的用户传递JSON可能是危险的 源于它。可以通过更改解析器的默认选项 :: load_default_options方法。
此方法是加载/转储接口实现的一部分 元帅和YAML。
答案 1 :(得分:0)
直接反序列化为富对象(特别是如果您的JSON来自未知来源)可能是一个非常严重的攻击向量(最近的Rails漏洞与此相关)。
我猜这个功能在Ruby版本之间被禁用,或者至少改为基于白名单的方法。我找不到任何支持这种说法的链接,所以我可能错了。
无论如何,您可能会发现从反序列化的哈希中初始化类更简单,更兼容:
class Word
def self.from_json(json)
args = JSON.parse(json)["data"];
new(*args)
end
end
答案 2 :(得分:0)
这是另一种解决方法,因为我的代码不用于网络通信,因此漏洞不是问题。
在我做之前:
JSON.parse(str)
现在只需添加几行:
obj = JSON.parse(str)
if obj.is_a?(Hash)
class_name = obj['json_class'].split('::').inject(Kernel) { |namespace, const_name| namespace.const_get(const_name) }
args = obj['data']
word = class_name.new(*args)
else
word = obj
end