Ruby中使用JSON.parse转换Routeguide::Rectangle对象报错问题
Ruby JSON解析嵌套自定义类报错解决
问题背景
我有一个Ruby自定义类Routeguide::Rectangle,结构如下(其中lo和hi都是Routeguide::Point类的实例):
<Routeguide::Rectangle: lo: <Routeguide::Point: latitude: 400000000, longitude: -750000000>, hi: <Routeguide::Point: latitude: 420000000, longitude: -730000000>>
对应的正确JSON字符串为:
json_string = '{"lo":{"latitude":400000000,"longitude":-750000000},"hi":{"latitude":420000000,"longitude":-730000000}}'
尝试用以下代码将JSON解析为Routeguide::Rectangle对象:
JSON.parse(json_string, object_class: Routeguide::Rectangle)
执行后抛出错误:
#<ArgumentError: Unknown field: latitude>
堆栈信息:
[ "/Users/psen/.rbenv/versions/2.7.7/lib/ruby/2.7.0/json/common.rb:156:in `[]='", "/Users/psen/.rbenv/versions/2.7.7/lib/ruby/2.7.0/json/common.rb:156:in `parse'", "/Users/psen/.rbenv/versions/2.7.7/lib/ruby/2.7.0/json/common.rb:156:in `parse'" ]
报错原因
Ruby标准库的JSON.parse方法使用object_class参数时,只会将顶层哈希转换为指定类的实例,但不会自动处理嵌套的自定义类。当解析到lo或hi内部的latitude字段时,会尝试直接给Routeguide::Rectangle实例设置这个不存在的属性,导致报错。
解决方案
方案1:手动解析构建对象
先把JSON解析成普通哈希,再逐层创建自定义类实例:
hash = JSON.parse(json_string) lo_point = Routeguide::Point.new(latitude: hash["lo"]["latitude"], longitude: hash["lo"]["longitude"]) hi_point = Routeguide::Point.new(latitude: hash["hi"]["latitude"], longitude: hash["hi"]["longitude"]) rectangle = Routeguide::Rectangle.new(lo: lo_point, hi: hi_point)
方案2:给自定义类添加from_json方法
在Routeguide::Point和Routeguide::Rectangle中实现专属的JSON解析逻辑,封装细节:
class Routeguide::Point attr_accessor :latitude, :longitude def initialize(latitude:, longitude:) @latitude = latitude @longitude = longitude end def self.from_json(json_str) hash = JSON.parse(json_str) new(latitude: hash["latitude"], longitude: hash["longitude"]) end end class Routeguide::Rectangle attr_accessor :lo, :hi def initialize(lo:, hi:) @lo = lo @hi = hi end def self.from_json(json_str) hash = JSON.parse(json_str) lo_point = Routeguide::Point.from_json(JSON.generate(hash["lo"])) hi_point = Routeguide::Point.from_json(JSON.generate(hash["hi"])) new(lo: lo_point, hi: hi_point) end end # 使用方式 rectangle = Routeguide::Rectangle.from_json(json_string)
方案3:重写[]=方法适配嵌套解析
通过重写Routeguide::Rectangle的[]=方法,识别嵌套字段并转换为对应类实例:
class Routeguide::Rectangle attr_accessor :lo, :hi def []=(key, value) if %w[lo hi].include?(key) # 将嵌套哈希转换为Routeguide::Point实例 instance_variable_set("@#{key}", Routeguide::Point.new(latitude: value["latitude"], longitude: value["longitude"])) else super end end end # 现在可以直接用JSON.parse解析 rectangle = JSON.parse(json_string, object_class: Routeguide::Rectangle)
内容的提问来源于stack exchange,提问作者Prateek Sen
相关产品推荐
相关产品推荐

