mirror of
https://github.com/json-iterator/go.git
synced 2025-05-13 21:36:29 +02:00
#27 support json.Unmarshaler
This commit is contained in:
parent
f6f159e108
commit
7d2ae80c37
@ -30,6 +30,17 @@ func (iter *Iterator) ReadBool() (ret bool) {
|
||||
}
|
||||
|
||||
|
||||
func (iter *Iterator) SkipAndReturnBytes() []byte {
|
||||
if iter.reader != nil {
|
||||
panic("reader input does not support this api")
|
||||
}
|
||||
before := iter.head
|
||||
iter.Skip()
|
||||
after := iter.head
|
||||
return iter.buf[before:after]
|
||||
}
|
||||
|
||||
|
||||
// Skip skips a json object and positions to relatively the next json object
|
||||
func (iter *Iterator) Skip() {
|
||||
c := iter.nextToken()
|
||||
|
@ -75,6 +75,7 @@ var fieldEncoders map[string]Encoder
|
||||
var extensions []ExtensionFunc
|
||||
var anyType reflect.Type
|
||||
var marshalerType reflect.Type
|
||||
var unmarshalerType reflect.Type
|
||||
|
||||
func init() {
|
||||
typeDecoders = map[string]Decoder{}
|
||||
@ -86,6 +87,7 @@ func init() {
|
||||
atomic.StorePointer(&ENCODERS, unsafe.Pointer(&map[string]Encoder{}))
|
||||
anyType = reflect.TypeOf((*Any)(nil)).Elem()
|
||||
marshalerType = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
||||
unmarshalerType = reflect.TypeOf((*json.Unmarshaler)(nil)).Elem()
|
||||
}
|
||||
|
||||
func addDecoderToCache(cacheKey reflect.Type, decoder Decoder) {
|
||||
@ -293,9 +295,6 @@ func (p prefix) addToEncoder(encoder Encoder, err error) (Encoder, error) {
|
||||
}
|
||||
|
||||
func decoderOfType(typ reflect.Type) (Decoder, error) {
|
||||
if typ.ConvertibleTo(anyType) {
|
||||
return &anyCodec{}, nil
|
||||
}
|
||||
typeName := typ.String()
|
||||
typeDecoder := typeDecoders[typeName]
|
||||
if typeDecoder != nil {
|
||||
@ -315,6 +314,13 @@ func decoderOfType(typ reflect.Type) (Decoder, error) {
|
||||
}
|
||||
|
||||
func createDecoderOfType(typ reflect.Type) (Decoder, error) {
|
||||
if typ.ConvertibleTo(anyType) {
|
||||
return &anyCodec{}, nil
|
||||
}
|
||||
if typ.ConvertibleTo(unmarshalerType) {
|
||||
templateInterface := reflect.New(typ).Elem().Interface()
|
||||
return &optionalDecoder{typ, &unmarshalerDecoder{extractInterface(templateInterface)}}, nil
|
||||
}
|
||||
switch typ.Kind() {
|
||||
case reflect.String:
|
||||
return &stringCodec{}, nil
|
||||
|
@ -363,3 +363,19 @@ func (encoder *marshalerEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return len(bytes) > 0
|
||||
}
|
||||
}
|
||||
|
||||
type unmarshalerDecoder struct {
|
||||
templateInterface emptyInterface
|
||||
}
|
||||
|
||||
func (decoder *unmarshalerDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
templateInterface := decoder.templateInterface
|
||||
templateInterface.word = ptr
|
||||
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
|
||||
unmarshaler := (*realInterface).(json.Unmarshaler)
|
||||
bytes := iter.SkipAndReturnBytes()
|
||||
err := unmarshaler.UnmarshalJSON(bytes)
|
||||
if err != nil {
|
||||
iter.reportError("unmarshaler", err.Error())
|
||||
}
|
||||
}
|
@ -150,3 +150,27 @@ func Test_marshaler(t *testing.T) {
|
||||
should.Nil(err)
|
||||
should.Equal(`{"Field":"hello"}`, str)
|
||||
}
|
||||
|
||||
type ObjectImplementedUnmarshaler int
|
||||
|
||||
func (obj *ObjectImplementedUnmarshaler) UnmarshalJSON([]byte) error {
|
||||
*obj = 100
|
||||
return nil
|
||||
}
|
||||
|
||||
func Test_unmarshaler(t *testing.T) {
|
||||
type TestObject struct {
|
||||
Field *ObjectImplementedUnmarshaler
|
||||
Field2 string
|
||||
}
|
||||
should := require.New(t)
|
||||
obj := TestObject{}
|
||||
val := ObjectImplementedUnmarshaler(0)
|
||||
obj.Field = &val
|
||||
err := json.Unmarshal([]byte(`{"Field":"hello"}`), &obj)
|
||||
should.Nil(err)
|
||||
should.Equal(100, int(*obj.Field))
|
||||
err = Unmarshal([]byte(`{"Field":"hello"}`), &obj)
|
||||
should.Nil(err)
|
||||
should.Equal(100, int(*obj.Field))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user