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

时间:2016-07-19 08:28:34

标签: ruby json

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

头等舱:

 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对象转换为API,然后将其转换为JSON。所以我在to_json对象上将request称为:

request.to_json

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

(给出错误:&#39; to_json&#39;:错误的参数数量(1代表0)(ArgumentError)&#39;)

我尝试了什么:

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 个答案:

答案 0 :(得分:2)

您提到的答案是“2010年12月”。JSON库已经包含在ruby stdlib中已有好几年了,它完美地将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。