Skip to content
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

Deserialization depends on lexicographical ordering of types #296

Open
simsurace opened this issue Dec 2, 2024 · 1 comment
Open

Deserialization depends on lexicographical ordering of types #296

simsurace opened this issue Dec 2, 2024 · 1 comment

Comments

@simsurace
Copy link
Contributor

This is unexpected and may be a bug.

using JSON3, StructTypes

struct Type1
    name::String
    n::Int
end

struct Type2
    name::String
end

struct Type3
    name::String
    n::Int
end

json_string = """
    [
        {
            "name": "test",
            "n": 1
        },
        {
            "name": "test"
        }
    ]
    """

JSON3.read(json_string, Vector{Union{Type1,Type2}}) # [Type1("test", 1), Type2("test")]
JSON3.read(json_string, Vector{Union{Type3,Type2}}) # [Type2("test"), Type2("test")]

The parsing as Type2 in the second example drops one field of the json data.

@simsurace
Copy link
Contributor Author

Ok, I digged into it a bit. This seems to come down to the comment here:

JSON3.jl/src/structs.jl

Lines 70 to 89 in 02e2ecf

@generated function read(::Struct, buf, pos, len, b, T::Union; kw...)
U = first(T.parameters) # Extract Union from Type
# Julia implementation detail: Unions are sorted :)
# This lets us avoid the below try-catch when U <: Union{Missing,T}
if U.a === Nothing || U.a === Missing
:(if buf[pos] == UInt8('n')
return read(StructType($(U.a)), buf, pos, len, b, $(U.a))
else
return read(StructType($(U.b)), buf, pos, len, b, $(U.b); kw...)
end)
else
return :(
try
return read(StructType($(U.a)), buf, pos, len, b, $(U.a); kw...)
catch e
return read(StructType($(U.b)), buf, pos, len, b, $(U.b); kw...)
end
)
end
end

And JSON3.jl not failing when there are extra fields. So JSON3.read("{\"name\":\"test\",\"n\":1}", Type2) does not fail.
Might we add a keyword argument ignore_extra_fields::Bool=false to JSON3.read to opt into throwing an error when an extra field is encountered?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant