【问题标题】:How to do Ruby object serialization using JSON如何使用 JSON 进行 Ruby 对象序列化
【发布时间】:2010-12-13 15:56:47
【问题描述】:

我有一个像这样的简单容器类的结构(在伪 ruby​​ 中):

class A
  attr_reader :string_field1, :string_field2
  ...
end

class B
  attr_reader: int_field3, :string_field4
  ...
end

# C includes an instance of A and B
class C
  attr_reader: :a_instance, :b_instance
  ...
end

是否有简单的方法可以在 Ruby 中将其反序列化为 JSON?还是应该像this example 那样为每个类创建嵌套的序列化方法?

编辑:

在我的特定场景中,我想将一些 JSON 数据发布到运行 Ruby 的服务器,该服务器将提取数据并采取相应措施。

JSON 的发送者不一定是 Ruby 进程,但可能是某个其他系统的后端。 (尽管在我的测试工具中它是 Ruby)。

所以,我不需要 JSON 采用某种“Ruby 特定”格式,我只是假设如果它实际上是 Ruby 内置的会更容易。

【问题讨论】:

    标签: ruby serialization json


    【解决方案1】:

    对非 JSON 对象使用 Marshal、PStore 或其他 Ruby 解决方案

    人们可能会想知道为什么像 Ruby 这样的完全反射性语言不能自动生成 JSON 并解析任意类。

    但是,除非您坚持使用 JSON 类型,否则除了发送到另一个正在运行的 Ruby 之外,没有其他地方可以发送或接收 JSON 对象。在这种情况下,我怀疑传统观点是“忘记 JSON,使用像核心类 Marshal 这样的原生 Ruby 接口。

    因此,如果您真的要将这些对象发送到 PHP 或非 Ruby 的东西,那么您应该使用 Array 等直接创建支持 JSON 的 Ruby 数据结构,然后您将拥有 JSON.generate 将直接处理的东西与。

    如果您只需要序列化,您可以使用MarshalPStore

    更新:啊哈,好吧,试试这个:

    module AutoJ
      def auto_j
        h = {}
        instance_variables.each do |e|
          o = instance_variable_get e.to_sym
          h[e[1..-1]] = (o.respond_to? :auto_j) ? o.auto_j : o;
        end
        h
      end
      def to_json *a
        auto_j.to_json *a
      end
    end
    

    如果您在每个班级中都使用include AutoJ,则应该使用 DTRT。在您的示例中,这导致

    {
      "a": {
        "string_field1": "aa",
        "string_field2": "bb"
      },
      "b": {
        "int_field3": 123,
        "string_field4": "dd"
      }
    }
    

    您可能希望将auto_j 方法更改为返回h.values 而不仅仅是h,在这种情况下您会得到:

    [
      ["aa", "bb"],
      [123, "dd"]
    ]
    

    【讨论】:

    • 谢谢,请参阅我的说明。我认为它会比现在更加自动化。
    • 请注意封送封包,如lambdasProcs。他们不能。我不知道这是否是一个广泛的列表,也许还有其他无法编组的结构。
    【解决方案2】:

    我遇到了同样的问题(主要是尝试创建任意复杂的 JSON 字符串)而不是解析它们。在寻找了一个非侵入性的类之后,它将接受一个 Ruby 对象(包括嵌套数组)并将其编组为 JSON 字符串,我终于编写了自己的简单序列化程序。此代码还转义特殊字符以创建有效的 JSON。

    http://www.keepingmyhandin.com/Downhome/Sketchup/simplejsonserializerrubyimplementation

    你所要做的就是:

    json  = JSON.new;
    jsonString = json.marshal(obj); # Where obj is a Ruby object
    

    【讨论】:

      【解决方案3】:

      这是我为自定义类实现to_json 的方法。

      在模块中使用self.included 有一点魔力。这是 2006 年的一篇非常好的文章,关于具有实例和类方法的模块http://blog.jayfields.com/2006/12/ruby-instance-and-class-methods-from.html

      该模块旨在包含在任何类中以提供to_json 功能。它拦截attr_accessor 方法而不是使用自己的方法,以便对现有类进行最少的更改。

      to_json 的实现是基于这个answer

      module JSONable
        module ClassMethods
          attr_accessor :attributes
      
          def attr_accessor *attrs
            self.attributes = Array attrs
            super
          end
        end
      
        def self.included(base)
          base.extend(ClassMethods)
        end
      
        def as_json options = {}
          serialized = Hash.new
          self.class.attributes.each do |attribute|
            serialized[attribute] = self.public_send attribute
          end
          serialized
        end
      
        def to_json *a
          as_json.to_json *a
        end
      end
      
      
      class CustomClass
        include JSONable
        attr_accessor :b, :c 
      
        def initialize b: nil, c: nil
          self.b, self.c = b, c
        end
      end
      
      a = CustomClass.new(b: "q", c: 23)
      puts JSON.pretty_generate a
      
      {
        "b": "q",
        "c": 23
      }
      

      【讨论】:

        猜你喜欢
        • 2013-01-31
        • 1970-01-01
        • 2013-03-05
        • 1970-01-01
        • 1970-01-01
        • 2018-12-02
        • 1970-01-01
        • 1970-01-01
        • 2019-07-23
        相关资源
        最近更新 更多