-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSON3 does not escape dicts of dicts #297
Comments
Yeah, we've never really supported non-string-like things for object keys because we short-cut by just calling |
Thanks! Json.write() seems to exhibit closer to the intended behavior, but the read seems to have issues. Given Stringify is extensionally equivalent for base-objects, it would be rather unsafe but plausible to put a parse clause around the keys instantiating them I believe. Probably could work better with type detection then parsing the arguments but that's a digression. I'll try to figure something out and come back with a solution for those that make their way here from when this ends up being indexed by google. |
JSON only allows strings as keys, so I can understand that JSON3's default behavior is to shortcut by just calling Here is my workaround when I work my data structures involving dictionaries using non-string keys (it won't work with a dictionary as a key) : # JSON3 does not support Dict when the type of a key is not String.
# Consider the following type.
struct MyType
dict1::Dict{Tuple{Int,Int},String}
dict2::Dict{Tuple{Int,Int,Int}, String}
end
# Serialization / Deserialization of MyType goes through a custom type.
StructTypes.StructType(::Type{MyType}) = StructTypes.CustomStruct()
# You need to define the intermediate types that will be the JSON schema of your type.
struct EntryWrapper{K,V}
key::K
value::V
end
StructTypes.StructType(::Type{EntryWrapper{K,V}}) where {K,V} = StructTypes.Struct()
struct MyTypeJSONRepr
dict1::Vector{EntryWrapper{Tuple{Int,Int}, String}}
dict2::Vector{EntryWrapper{Tuple{Int,Int,Int}, String}}
end
StructTypes.StructType(::Type{MyTypeJSONRepr}) = StructTypes.Struct()
# Define the following constructors to instantiate the intermediate structure from the initial
# one and the other way around.
wrap_entries(dict::Dict{K,V}) where {K,V} = [EntryWrapper(k, v) for (k, v) in dict]
unwrap_entries(vec::Vector{EntryWrapper{K,V}}) where {K,V} = Dict{K,V}(elem.key => elem.value for elem in vec)
MyTypeJSONRepr(initial::MyType) = MyTypeJSONRepr(
wrap_entries(initial.dict1),
wrap_entries(initial.dict2)
)
MyType(repr::MyTypeJSONRepr) = MyType(
unwrap_entries(repr.dict1),
unwrap_entries(repr.dict2)
)
# MyType must be written as a MyTypeJSONRepr.
StructTypes.lower(initial::MyType) = MyTypeJSONRepr(initial)
# MyType must be read from a MyTypeJSONRepr object.
StructTypes.lowertype(::Type{MyType}) = MyTypeJSONRepr
example = MyType(
Dict((1,2) => "3", (4, 5) => "6"),
Dict((10, 11, 12) => "13", (14, 15, 15) => "17")
)
json = JSON3.write(example)
read_example = JSON3.read(json, MyType) |
A dictionary that takes dictionaries as keys (very stupid, I know, but it's a quick-and-dirty solution I'm testing), results in improper serialization when writing to file:
"(Dict{String, BigFloat}("lat" => , "lon" => ), Dict{String, BigFloat}("lat" => , "lon" => ))"
Where "lat" and "lon" are originally strings.
The text was updated successfully, but these errors were encountered: