Ruby serialize struct with JSON

随声附和 提交于 2019-12-22 05:06:14

问题


I am trying to serialize a simple struct to JSON which works fine, but I can't get it to create an instance of that struct from the JSON. Here is how I am trying to do it.

require 'rubygems'
require 'json'

Person = Struct.new(:name, :age)

json = Person.new('Adam', 19).to_json
puts json

me = JSON.load(json)
puts me.name

And I get the following output:

"#<struct Person name=\"Adam\", age=19>"
/usr/lib/ruby/1.9.1/json/common.rb:148:in `parse': 746: unexpected token at '"#<struct Person name=\"Adam\", age=19>"' (JSON::ParserError)
    from /usr/lib/ruby/1.9.1/json/common.rb:148:in `parse'
    from /usr/lib/ruby/1.9.1/json/common.rb:309:in `load'
    from why.rb:9:in `<main>'

回答1:


In this case, person.to_json is not doing what you expect.

When you require 'json', the JSON library inserts a #to_json method on Object that is a fallback if there's no specialized #to_json method provided elsewhere. This inserted method is basically the same as calling #to_s#to_json on an object.

In the case of your Person class here, #to_s outputs the standard Object#to_s, which, by default, doesn't provide a string parseable by the JSON library.

However, Struct does provide a #to_h method that can be used to convert that struct to a Hash, and Hash is (upon requiring the JSON library) aware of how to generate a JSON parseable output.

So simply changing:

json = Person.new('Adam', 19).to_json
puts json

to:

person = Person.new('Adam', 19)
puts person.to_h.to_json

will do what you expect.

(An aside, I would actually recommend implementing #to_json on the Person class directly as calling #to_h#to_json violates the Law of Demeter.)




回答2:


You can also define a struct with a to_json method. Depends if you're happy with calling to_h.to_json. If it's only called once internally in a class, it may be tolerable and ignore this. But if the struct is used else where multiple times below is an option.

require 'struct'
require 'json'

MyStruct = Struct.new(:foo, :bar) do
  def to_json
    to_h.to_json
  end
end

simple_struct = MyStruct.new("hello", "world")
simple_struct.to_json

# => "{\"foo\":\"hello\",\"bar\":\"world\"}"


来源:https://stackoverflow.com/questions/28313102/ruby-serialize-struct-with-json

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!