简体   繁体   English

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

[英]Custom to_json for nested complex objects in Ruby

I'm new to Ruby and having a little trouble json . 我是Ruby新手,但json有点麻烦。 I have inherited my classes with custom made JSONable class, as explained HERE in this answer . 我已经用自定义的JSONable类继承了我的类,如本答案所述 I have customized it according to my need, but I couldn't figure out how to make it work with custom nested (complex) objects, according to my requirement. 我已经根据需要对它进行了自定义,但是我无法根据自己的需求弄清楚如何使其与自定义嵌套(复杂)对象一起使用。 I have following scenario. 我有以下情况。

First Class: 头等舱:

 class Option < JSONable

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

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

 ......

Second Class: 二等舱:

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

Third Class: 第三类:

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

I call it as: 我称其为:

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

My ultimate goal is to send this request object to an API , after converting it to JSON. 我的最终目标是将request对象转换为JSON之后,将其发送到API so i call to_json on request object as: 所以我在request对象上调用to_json为:

request.to_json

But here, suggested solution in that post (JSONable) fails in this case, as it can't convert the nested complex objects request.search and request.search.Options to Json. 但是这里,该帖子中的建议解决方案(JSONable)在这种情况下失败了,因为它无法将嵌套的复杂对象request.searchrequest.search.Options转换为Json。

(gives error: in 'to_json': wrong number of arguments (1 for 0) (ArgumentError)') (给出错误:在'to_json'中:错误的参数数量(1代表0)(ArgumentError)')

What I tried: 我试过的

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
.....

This converts the nested model without any problem, but it messes up the 3rd level json. 这样可以毫无问题地转换嵌套模型,但是会弄乱3级json。 The result is as following: 结果如下:

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

And API doesn't respond. 而且API没有响应。 It seems as it messes up the boolean variables, which should be something like: 似乎弄乱了布尔变量,应该是这样的:

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

but it gives: 但它给出:

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

So the API logic can't cast it to corresponding bool objects anymore. 因此,API逻辑无法将其bool为相应的bool对象。 JSON validator also fails to validate this result, i checked online 我在线检查了JSON验证程序也无法验证此结果

Questions: 问题:

  • How can I avoid this, and produce valid JSON in this case? 如何避免这种情况,并在这种情况下产生有效的JSON?

  • How can I apply generic check to in my JSONable class to check if the object is of some custom class / complex object. 如何在我的JSONable类中应用泛型检查,以检查对象是否属于某些自定义类/复杂对象。

(currently i have checked only for specific classes as:) (目前,我只检查了以下特定课程:)

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

Other Info: 其他资讯:

  • It works fine for all complex objects, having no nested objects 它适用于所有没有嵌套对象的复杂对象
  • API is developed in .NET API是在.NET中开发的
  • I'm not using Rails, its a Ruby console app (I'm new to Ruby) 我没有使用Rails,而是一个Ruby控制台应用程序(我是Ruby的新手)

The answer you referred is dated “Dec 2010.” JSON library is included in ruby stdlib for years already and it perfectly converts Hash instances to json. 您提到的答案的日期为“ 2010年12月” JSON库已包含在ruby stdlib中已有数年之久,并且可以完美地将Hash实例转换为json。 That said, you just need to construct hashes out of your objects and then call JSON.dump on the resulting hash. 就是说,您只需JSON.dump对象中构造哈希,然后在生成的哈希上调用JSON.dump I have no idea what JSONable is and you definitely do not need it. 我不知道什么是JSONable ,您肯定不需要它。 Introduce some base class, let's call it Base : 介绍一些基类,我们称它为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

Now just derive your classes from Base to make them respond to to_h , define all your instance variables as you did, and call: 现在,仅从Base派生您的类以使它们响应to_h ,像您一样定义所有实例变量,然后调用:

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

The above should produce the nested JSON, hashes are happily converted to json by this library automagically. 上面的代码应该生成嵌套的JSON,此库会自动将哈希值愉快地转换为json。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM