diff --git a/src/JSON3.jl b/src/JSON3.jl index f85527f..0783e31 100644 --- a/src/JSON3.jl +++ b/src/JSON3.jl @@ -32,7 +32,7 @@ invalid JSON at byte position $pos while parsing type $T: $error $(String(buf[max(1, pos-25):min(end, pos+25)])) """)) -@enum Error UnexpectedEOF ExpectedOpeningObjectChar ExpectedOpeningQuoteChar ExpectedOpeningArrayChar ExpectedClosingArrayChar ExpectedComma ExpectedSemiColon ExpectedNewline InvalidChar InvalidNumber +@enum Error UnexpectedEOF ExpectedOpeningObjectChar ExpectedOpeningQuoteChar ExpectedOpeningArrayChar ExpectedClosingArrayChar ExpectedComma ExpectedSemiColon ExpectedNewline InvalidChar InvalidNumber ExtraField # AbstractDict interface Base.length(obj::Object) = getnontypemask(gettape(obj)[2]) diff --git a/src/read.jl b/src/read.jl index 50354d4..5271878 100644 --- a/src/read.jl +++ b/src/read.jl @@ -26,6 +26,7 @@ Read JSON. * `dateformat`: A [`DateFormat`](https://docs.julialang.org/en/v1/stdlib/Dates/#Dates.DateFormat) describing the format of dates in the JSON so that they can be read into `Date`s, `Time`s, or `DateTime`s when reading into a type. [default `Dates.default_format(T)`] * `parsequoted`: Accept quoted values when reading into a NumberType. [default `false`] * `numbertype`: Type to parse numbers as. [default `nothing`, which parses numbers as Int if possible, Float64 otherwise] +* `ignore_extra_fields`: Ignore extra fields in the JSON when reading into a struct. [default `true`] """ function read(json::AbstractString; jsonlines::Bool=false, numbertype::Union{DataType, Nothing}=nothing, kw...) diff --git a/src/structs.jl b/src/structs.jl index 9a42ff2..d9e218d 100644 --- a/src/structs.jl +++ b/src/structs.jl @@ -558,7 +558,7 @@ end return end -function read(::Struct, buf, pos, len, b, ::Type{T}; kw...) where {T} +function read(::Struct, buf, pos, len, b, ::Type{T}; ignore_extra_fields::Bool=true, kw...) where {T} values = Vector{Any}(undef, fieldcount(T)) if b != UInt8('{') error = ExpectedOpeningObjectChar @@ -612,7 +612,12 @@ function read(::Struct, buf, pos, len, b, ::Type{T}; kw...) where {T} if StructTypes.applyfield(c, T, key) pos = c.pos else - pos, _ = read(Struct(), buf, pos, len, b, Any) + if ignore_extra_fields + pos, _ = read(Struct(), buf, pos, len, b, Any) + else + error = ExtraField + @goto invalid + end end @eof b = getbyte(buf, pos) diff --git a/test/runtests.jl b/test/runtests.jl index a036012..c5af29c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1109,4 +1109,12 @@ y[1] = x @testset "Arrow" include("arrow.jl") end +# https://github.com/quinnj/JSON3.jl/issues/296 +struct TypeWithoutExtraField + a::Int +end +string_with_extra_field = "{\"a\": 1, \"b\": 2}" +@test JSON3.read(string_with_extra_field, TypeWithoutExtraField) == TypeWithoutExtraField(1) +@test_throws ArgumentError JSON3.read(string_with_extra_field, TypeWithoutExtraField, ignore_extra_fields=false) + end # @testset "JSON3"