1
0
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:
Tao Wen
2018-02-05 23:03:53 +08:00
parent 7990317be5
commit 71f74dc71e
6 changed files with 60 additions and 16 deletions

17
api_tests/decoder_test.go Normal file
View 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))
}

View File

@ -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)

View File

@ -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),
} }

View File

@ -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

View File

@ -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 {

View File

@ -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)