You've already forked json-iterator
mirror of
https://github.com/json-iterator/go.git
synced 2025-06-24 23:16:47 +02:00
implement #230 DisallowUnknownFields option added
This commit is contained in:
17
api_tests/decoder_test.go
Normal file
17
api_tests/decoder_test.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"github.com/json-iterator/go"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_disallowUnknownFields(t *testing.T) {
|
||||||
|
should := require.New(t)
|
||||||
|
type TestObject struct{}
|
||||||
|
var obj TestObject
|
||||||
|
decoder := jsoniter.NewDecoder(bytes.NewBufferString(`{"field1":100}`))
|
||||||
|
decoder.DisallowUnknownFields()
|
||||||
|
should.Error(decoder.Decode(&obj))
|
||||||
|
}
|
@ -95,13 +95,23 @@ func (adapter *Decoder) Buffered() io.Reader {
|
|||||||
return bytes.NewReader(remaining)
|
return bytes.NewReader(remaining)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UseNumber for number JSON element, use float64 or json.NumberValue (alias of string)
|
// UseNumber causes the Decoder to unmarshal a number into an interface{} as a
|
||||||
|
// Number instead of as a float64.
|
||||||
func (adapter *Decoder) UseNumber() {
|
func (adapter *Decoder) UseNumber() {
|
||||||
cfg := adapter.iter.cfg.configBeforeFrozen
|
cfg := adapter.iter.cfg.configBeforeFrozen
|
||||||
cfg.UseNumber = true
|
cfg.UseNumber = true
|
||||||
adapter.iter.cfg = cfg.frozeWithCacheReuse()
|
adapter.iter.cfg = cfg.frozeWithCacheReuse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DisallowUnknownFields causes the Decoder to return an error when the destination
|
||||||
|
// is a struct and the input contains object keys which do not match any
|
||||||
|
// non-ignored, exported fields in the destination.
|
||||||
|
func (adapter *Decoder) DisallowUnknownFields() {
|
||||||
|
cfg := adapter.iter.cfg.configBeforeFrozen
|
||||||
|
cfg.DisallowUnknownFields = true
|
||||||
|
adapter.iter.cfg = cfg.frozeWithCacheReuse()
|
||||||
|
}
|
||||||
|
|
||||||
// NewEncoder same as json.NewEncoder
|
// NewEncoder same as json.NewEncoder
|
||||||
func NewEncoder(writer io.Writer) *Encoder {
|
func NewEncoder(writer io.Writer) *Encoder {
|
||||||
return ConfigDefault.NewEncoder(writer)
|
return ConfigDefault.NewEncoder(writer)
|
||||||
|
@ -16,6 +16,7 @@ type Config struct {
|
|||||||
EscapeHTML bool
|
EscapeHTML bool
|
||||||
SortMapKeys bool
|
SortMapKeys bool
|
||||||
UseNumber bool
|
UseNumber bool
|
||||||
|
DisallowUnknownFields bool
|
||||||
TagKey string
|
TagKey string
|
||||||
OnlyTaggedField bool
|
OnlyTaggedField bool
|
||||||
ValidateJsonRawMessage bool
|
ValidateJsonRawMessage bool
|
||||||
@ -65,6 +66,7 @@ func (cfg Config) Froze() API {
|
|||||||
indentionStep: cfg.IndentionStep,
|
indentionStep: cfg.IndentionStep,
|
||||||
objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString,
|
objectFieldMustBeSimpleString: cfg.ObjectFieldMustBeSimpleString,
|
||||||
onlyTaggedField: cfg.OnlyTaggedField,
|
onlyTaggedField: cfg.OnlyTaggedField,
|
||||||
|
disallowUnknownFields: cfg.DisallowUnknownFields,
|
||||||
streamPool: make(chan *Stream, 16),
|
streamPool: make(chan *Stream, 16),
|
||||||
iteratorPool: make(chan *Iterator, 16),
|
iteratorPool: make(chan *Iterator, 16),
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ type frozenConfig struct {
|
|||||||
indentionStep int
|
indentionStep int
|
||||||
objectFieldMustBeSimpleString bool
|
objectFieldMustBeSimpleString bool
|
||||||
onlyTaggedField bool
|
onlyTaggedField bool
|
||||||
|
disallowUnknownFields bool
|
||||||
cacheLock *sync.RWMutex
|
cacheLock *sync.RWMutex
|
||||||
decoderCache map[reflect.Type]ValDecoder
|
decoderCache map[reflect.Type]ValDecoder
|
||||||
encoderCache map[reflect.Type]ValEncoder
|
encoderCache map[reflect.Type]ValEncoder
|
||||||
|
@ -99,7 +99,7 @@ func decoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValDeco
|
|||||||
for k, binding := range bindings {
|
for k, binding := range bindings {
|
||||||
fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder)
|
fields[strings.ToLower(k)] = binding.Decoder.(*structFieldDecoder)
|
||||||
}
|
}
|
||||||
return createStructDecoder(typ, fields)
|
return createStructDecoder(cfg, typ, fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
type structFieldEncoder struct {
|
type structFieldEncoder struct {
|
||||||
|
@ -8,7 +8,10 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder) ValDecoder {
|
func createStructDecoder(cfg *frozenConfig, typ reflect.Type, fields map[string]*structFieldDecoder) ValDecoder {
|
||||||
|
if cfg.disallowUnknownFields {
|
||||||
|
return &generalStructDecoder{typ: typ, fields: fields, disallowUnknownFields: true}
|
||||||
|
}
|
||||||
knownHash := map[int32]struct{}{
|
knownHash := map[int32]struct{}{
|
||||||
0: {},
|
0: {},
|
||||||
}
|
}
|
||||||
@ -20,7 +23,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName)
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
knownHash[fieldHash] = struct{}{}
|
knownHash[fieldHash] = struct{}{}
|
||||||
return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder}
|
return &oneFieldStructDecoder{typ, fieldHash, fieldDecoder}
|
||||||
@ -34,7 +37,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName)
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
knownHash[fieldHash] = struct{}{}
|
knownHash[fieldHash] = struct{}{}
|
||||||
if fieldHash1 == 0 {
|
if fieldHash1 == 0 {
|
||||||
@ -57,7 +60,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName)
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
knownHash[fieldHash] = struct{}{}
|
knownHash[fieldHash] = struct{}{}
|
||||||
if fieldName1 == 0 {
|
if fieldName1 == 0 {
|
||||||
@ -88,7 +91,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName)
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
knownHash[fieldHash] = struct{}{}
|
knownHash[fieldHash] = struct{}{}
|
||||||
if fieldName1 == 0 {
|
if fieldName1 == 0 {
|
||||||
@ -125,7 +128,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName)
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
knownHash[fieldHash] = struct{}{}
|
knownHash[fieldHash] = struct{}{}
|
||||||
if fieldName1 == 0 {
|
if fieldName1 == 0 {
|
||||||
@ -168,7 +171,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName)
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
knownHash[fieldHash] = struct{}{}
|
knownHash[fieldHash] = struct{}{}
|
||||||
if fieldName1 == 0 {
|
if fieldName1 == 0 {
|
||||||
@ -217,7 +220,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName)
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
knownHash[fieldHash] = struct{}{}
|
knownHash[fieldHash] = struct{}{}
|
||||||
if fieldName1 == 0 {
|
if fieldName1 == 0 {
|
||||||
@ -272,7 +275,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName)
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
knownHash[fieldHash] = struct{}{}
|
knownHash[fieldHash] = struct{}{}
|
||||||
if fieldName1 == 0 {
|
if fieldName1 == 0 {
|
||||||
@ -333,7 +336,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName)
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
knownHash[fieldHash] = struct{}{}
|
knownHash[fieldHash] = struct{}{}
|
||||||
if fieldName1 == 0 {
|
if fieldName1 == 0 {
|
||||||
@ -400,7 +403,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldHash := calcHash(fieldName)
|
fieldHash := calcHash(fieldName)
|
||||||
_, known := knownHash[fieldHash]
|
_, known := knownHash[fieldHash]
|
||||||
if known {
|
if known {
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
knownHash[fieldHash] = struct{}{}
|
knownHash[fieldHash] = struct{}{}
|
||||||
if fieldName1 == 0 {
|
if fieldName1 == 0 {
|
||||||
@ -447,12 +450,13 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
fieldName9, fieldDecoder9,
|
fieldName9, fieldDecoder9,
|
||||||
fieldName10, fieldDecoder10}
|
fieldName10, fieldDecoder10}
|
||||||
}
|
}
|
||||||
return &generalStructDecoder{typ, fields}
|
return &generalStructDecoder{typ, fields, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
type generalStructDecoder struct {
|
type generalStructDecoder struct {
|
||||||
typ reflect.Type
|
typ reflect.Type
|
||||||
fields map[string]*structFieldDecoder
|
fields map[string]*structFieldDecoder
|
||||||
|
disallowUnknownFields bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||||
@ -473,6 +477,11 @@ func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator)
|
|||||||
}
|
}
|
||||||
fieldDecoder := decoder.fields[strings.ToLower(field)]
|
fieldDecoder := decoder.fields[strings.ToLower(field)]
|
||||||
if fieldDecoder == nil {
|
if fieldDecoder == nil {
|
||||||
|
if decoder.disallowUnknownFields {
|
||||||
|
iter.ReportError("ReadObject", "found unknown field: "+field)
|
||||||
|
iter.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
iter.Skip()
|
iter.Skip()
|
||||||
} else {
|
} else {
|
||||||
fieldDecoder.Decode(ptr, iter)
|
fieldDecoder.Decode(ptr, iter)
|
||||||
@ -490,6 +499,11 @@ func (decoder *generalStructDecoder) Decode(ptr unsafe.Pointer, iter *Iterator)
|
|||||||
}
|
}
|
||||||
fieldDecoder = decoder.fields[strings.ToLower(field)]
|
fieldDecoder = decoder.fields[strings.ToLower(field)]
|
||||||
if fieldDecoder == nil {
|
if fieldDecoder == nil {
|
||||||
|
if decoder.disallowUnknownFields {
|
||||||
|
iter.ReportError("ReadObject", "found unknown field: "+field)
|
||||||
|
iter.Skip()
|
||||||
|
return
|
||||||
|
}
|
||||||
iter.Skip()
|
iter.Skip()
|
||||||
} else {
|
} else {
|
||||||
fieldDecoder.Decode(ptr, iter)
|
fieldDecoder.Decode(ptr, iter)
|
||||||
|
Reference in New Issue
Block a user