1
0
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:
Tao Wen 2017-05-24 16:04:11 +08:00
parent f6f159e108
commit 7d2ae80c37
4 changed files with 61 additions and 4 deletions

View File

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

View File

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

View File

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

View File

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