Ruby 中嵌套复杂对象的自定义 to_json

Posted

技术标签:

【中文标题】Ruby 中嵌套复杂对象的自定义 to_json【英文标题】:Custom to_json for nested complex objects in Ruby 【发布时间】:2016-11-22 00:48:38 【问题描述】:

我是 Ruby 的新手,遇到了一些麻烦 json。正如HERE in this answer 解释的那样,我已经用定制的JSONable 类继承了我的类。我已根据需要对其进行了自定义,但根据我的要求,我无法弄清楚如何使其与自定义嵌套(复杂)对象一起使用。我有以下情况。

头等舱:

 class Option < JSONable

 def IncludeAll=(includeAll) #bool
  @includeAll = includeAll
 end

 def IncludeAddress=(includeAddress) #bool
  @includeAddress= includeAddress
 end

 ......

二等:

class Search < JSONable

def CustomerId=(customerId)
  @customerId = customerId
end

def identifier=(identifier)
  @identifier = identifier
end

def Options=(options) #This is expected to be of Class Option, declared above
 @options = options
end

第三类:

class Request < JSONable

def DateTimeStamp=(dateTimeStamp)
 @dateTimeStamp = dateTimeStamp
end

def SDKVersion=(sDKVersion)
 @sDKVersion = sDKVersion
end

def RequestMessage=(requestMessage) #This is of type Search, declared above
 @requestMessage = requestMessage
end

我称之为:

search = Search.new
searchOpts = Options.new
request = Request.new

search.identifier = identifier

searchOpts.IncludeAll = false
searchOpts.IncludeAddress = true

search.Options = searchOpts #setting nested level2 property here

//THE MOST OUTER CLASS OBJECT
request.SDKVersion = "xyz"
request.RequestMessage = search #setting nested level1

我的最终目标是将此request 对象转换为 JSON 后发送到API。所以我将request 对象上的to_json 称为:

request.to_json

但是在这里,该帖子中建议的解决方案 (JSONable) 在这种情况下会失败,因为它无法将嵌套的复杂对象 request.searchrequest.search.Options 转换为 Json。

(给出错误:在“to_json”中:参数数量错误(1 代表 0)(ArgumentError)”)

我尝试了什么:

class JSONable
def to_json
    hash = 
    self.instance_variables.each do |var|
     #hash[var] = self.instance_variable_get var #tried to apply following check

    if((self.instance_variable_get var).instance_of? Options ||((varVal).instance_of? Search))
     varVal = self.instance_variable_get var
     hash[var] = varVal.to_json #convert inner object to json
    else 
     hash[var] = self.instance_variable_get var
    end

    end
    hash.to_json
end
.....

这可以毫无问题地转换嵌套模型,但它会弄乱第 3 级 json。结果如下:

"DateTimeStamp":"121212","SDKVersion":"1.5","Culture":"en","RequestMessage":"\"identifier\":\"851848913\",\"Options\":\"\\\"IncludeAll\\\":true,\\\"IncludeAssociatedEntities\\\":true,\\\"IncludeAddress\\\":true,\\\"IncludePaymentInstructions\\\":true\""

API 没有响应。似乎它弄乱了布尔变量,应该是这样的:

"SearchOption":"\"IncludeAll\":true,\"IncludeAssociatedEntities\":true,\...

但它给出了:

"SearchOption\":\"\\\"IncludeAll\\\":true,\\\"IncludeAssociatedEntities\\\":true,\\\"Includ...

因此 API 逻辑不能再将其转换为对应的 bool 对象。 JSON验证器也无法验证这个结果,我在网上查过

问题:

如何避免这种情况,并在这种情况下生成有效的 JSON?

如何在我的 JSONable 类中应用通用检查来检查对象是否属于某个自定义类/复杂对象。

(目前我只检查了特定的类:)

if((self.instance_variable_get var).instance_of? Options ||((varVal).instance_of? Search))

其他信息:

它适用于所有复杂对象,没有嵌套对象 API 是在 .NET 中开发的 我没有使用 Rails,它是一个 Ruby 控制台应用程序(我是 Ruby 新手)

【问题讨论】:

【参考方案1】:

您提到的答案日期为“2010 年 12 月”。 JSON 库已经包含在 ruby​​ 标准库中多年了,它完美地将 Hash 实例转换为 json。也就是说,您只需要从对象构造散列,然后在生成的散列上调用 JSON.dump。我不知道JSONable 是什么,你绝对不需要它。引入一些基类,我们称之为Base

class Base
  def to_h
    instance_variables.map do |iv|
      value = instance_variable_get(:"@#iv")
      [
        iv.to_s[1..-1], # name without leading `@`
        case value
        when Base then value.to_h # Base instance? convert deeply
        when Array # Array? convert elements
          value.map do |e|
            e.respond_to?(:to_h) ? e.to_h : e
          end
        else value # seems to be non-convertable, put as is
        end
      ]
    end.to_h
  end
end

现在只需从Base 派生您的类,让它们响应to_h,像您一样定义所有实例变量,然后调用:

require 'json'
JSON.dump request.to_h # request.to_h.to_json should work as well

上面应该会生成嵌套的 JSON,哈希值会被这个库自动转换为 json。

【讨论】:

谢谢穆达索布瓦。我有一个名为Customer 的类,它继承了JSONable。我将这个 to_h 方法放在 JSONable 类中,以测试您的建议,即我的 JSONable 等同于您的 Base 类。 (将when Base 替换为when JSONable。当我将客户对象上的to_h 称为result = JSON.dump cutomerObj.to_h 时,我得到:to_h': undefined local variable or method instance' for #<0x00000002dacb20>

以上是关于Ruby 中嵌套复杂对象的自定义 to_json的主要内容,如果未能解决你的问题,请参考以下文章

使用映射库将嵌套对象映射到 C# 中的自定义对象

用于深层嵌套对象的自定义Json Serializer

spark-xml 中具有嵌套父节点的自定义模式

jOOQ & PostgreSQL:将从复杂 jsonb 中提取的嵌套 json 对象映射到自定义类型

无法将当前 JSON 数组(例如 [1,2,3])反序列化为具有复杂和嵌套对象的类型

达梦数据库的自定义类型