According to ruby-doc and apidock, you can serialize and deserialize an exception using to_json
and json_create
.
But after having wasted some time trying to use them, I still haven't found a way.
Calling exc.to_json
gives me an empty hash, and Exception.json_create(hash)
gives me this error: undefined method 'json_create' for Exception:Class
I guess I could easily recreate those functions since the source is available, but I'd rather understand what I'm doing wrong... Any idea?
More specifically, when the exception contains custom objects which may or may not themselves be serializable.
Incase, if an object contains variables of class type that refer to objects whose classes are not serializable, the object stream methods will NotSerializableException when attempting to write or read an instance. Even ,when a collection is serializable but contains objects that are not serializable, an exception will be show.
Even ,when a collection is serializable but contains objects that are not serializable, an exception will be show. If that field refers to an instance of a serializable class, no exception occurs upon serialization.
The [Serializable] attribute alone is not enough — Exception implements ISerializable which means your derived classes must also implement custom serialization. This involves two steps:
The JSON module doesn't extend Exception by default. You have to require "json/add/exception"
. I'm not sure if this is documented anywhere:
require "json/add/exception"
begin
nil.foo
rescue => exception
ex = exception
end
puts ex.to_json
# => {"json_class":"NoMethodError","m":"undefined method `foo' for nil:NilClass","b":["prog.rb:5:in `<main>'"]}
Check out ext/json/lib/json/add
in the Ruby source to see which classes work this way. If you do require "json/add/core"
it will load JSON extensions for Date, DateTime, Exception, OpenStruct, Range, Regexp, Struct, Symbol, Time, and others.
The answer from Jordan is correct. If you have a case eg. that you need to serialize an Exception and send to to ActiveJob where you want to reconstruct it, then you need to use .as_json
method.
require "json/add/exception"
begin
nil.foo
rescue => exception
ex = exception
end
puts ex.to_json.class
# => String
string = ex.to_json
puts Exception.json_create(string).message
# => m
puts ex.as_json.class
# => Hash
hash = ex.as_json
puts Exception.json_create(hash).message
# => undefined method `foo' for nil:NilClass
You need to read the source code to understand why Exception.json_create(string).message
returns m
:)
It's also important to note that the Exception.json_create
example doesn't keep the error class.
Exception.json_create(JSON.parse(ArgumentError.new('error').to_json))
# => #<Exception: error>
Try instead:
require "json/add/exception"
def deserialize_exception(json)
hash = JSON.parse(json)
hash['json_class'].constantize.json_create(hash)
end
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