-
Notifications
You must be signed in to change notification settings - Fork 58
Open
Description
Hi,
After some experimentation, I finally found a minimal working solution to serialize & deserialize structs containing abstract type instances.
I did not want to be intrusive by adding an extra :type field to the structures being serialized. I had a bit of trouble figuring out how to make it work, so I’m sharing my code here in case it helps someone else. Also, I’d appreciate if someone could double-check it for correctness or offer improvements.
Here's the working example:
# Stuff to serialize/deserialize
#
abstract type AbstractShape end
struct Circle <: AbstractShape
radius::Float64 # note: no extra :type field
end
struct Square <: AbstractShape
side::Float64 # note: no extra :type field
end
struct ShapeHolder
name::String
shape::AbstractShape
end
# ================================================================
using JSON3, StructTypes
# ================================================================
StructTypes.StructType(::Type{AbstractShape}) = StructTypes.AbstractType()
StructTypes.subtypekey(::Type{AbstractShape}) = :type
StructTypes.subtypes(::Type{AbstractShape}) = (circle=Circle,square=Square)
# ================================================================
StructTypes.StructType(t::Type{Circle}) = StructTypes.CustomStruct() # Mandatory otherwise lower() is not called
StructTypes.lower(h::Circle) = Dict(
"type" => "circle",
"radius" => h.radius
)
StructTypes.StructType(t::Type{Square}) = StructTypes.CustomStruct() # Mandatory otherwise lower() is not called
StructTypes.lower(h::Square) = Dict(
"type" => "square",
"side" => h.side
)
StructTypes.construct(::Type{Circle}, x::Dict) = Circle(x["radius"])
StructTypes.construct(::Type{Square}, x::Dict) = Square(x["side"])
# ================================================================
function StructTypes.construct(t::Type{AbstractShape}, x::Dict)
# field containing instance type information
type_field = String(StructTypes.subtypekey(t))
# get type information as string
type_field_value = x[type_field]
# get type
type = StructTypes.subtypes(type_field_value)
# create instance
StructTypes.construct(type,x)
end
Now the example in action
h = ShapeHolder("my shape", Circle(3.0))
# serialize
json_str = JSON3.write(h) # is "{\"name\":\"my shape\",\"shape\":{\"radius\":3.0,\"type\":\"circle\"}}"
# deserialize
parsed = JSON3.read(json_str, ShapeHolder) # is ShapeHolder("my shape", Circle(3.0))
Thank you for your package !
Best,
Vincent
Metadata
Metadata
Assignees
Labels
No labels