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>'
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.)
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 throughout a system below is a convient helper method on the struct.
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\"}"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With