1
0
mirror of https://github.com/json-iterator/go.git synced 2025-04-20 11:28:49 +02:00

fix marshaler support for iface case

This commit is contained in:
Tao Wen 2018-02-18 21:05:42 +08:00
parent 2074f25bd3
commit 43d9384d67
6 changed files with 246 additions and 91 deletions

View File

@ -330,6 +330,13 @@ func createEncoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) Val
if typ.AssignableTo(jsoniterNumberType) {
return &jsoniterNumberCodec{}
}
if typ == marshalerType {
checkIsEmpty := createCheckIsEmpty(cfg, typ)
var encoder ValEncoder = &directMarshalerEncoder{
checkIsEmpty: checkIsEmpty,
}
return encoder
}
if typ.Implements(marshalerType) {
checkIsEmpty := createCheckIsEmpty(cfg, typ)
var encoder ValEncoder = &marshalerEncoder{
@ -338,6 +345,22 @@ func createEncoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) Val
}
return encoder
}
ptrType := reflect.PtrTo(typ)
if ptrType.Implements(marshalerType) {
checkIsEmpty := createCheckIsEmpty(cfg, ptrType)
var encoder ValEncoder = &marshalerEncoder{
valType: reflect2.Type2(ptrType),
checkIsEmpty: checkIsEmpty,
}
return &referenceEncoder{encoder}
}
if typ == textMarshalerType {
checkIsEmpty := createCheckIsEmpty(cfg, typ)
var encoder ValEncoder = &directTextMarshalerEncoder{
checkIsEmpty: checkIsEmpty,
}
return encoder
}
if typ.Implements(textMarshalerType) {
checkIsEmpty := createCheckIsEmpty(cfg, typ)
var encoder ValEncoder = &textMarshalerEncoder{
@ -346,6 +369,14 @@ func createEncoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) Val
}
return encoder
}
if ptrType.Implements(textMarshalerType) {
checkIsEmpty := createCheckIsEmpty(cfg, ptrType)
var encoder ValEncoder = &textMarshalerEncoder{
valType: reflect2.Type2(ptrType),
checkIsEmpty: checkIsEmpty,
}
return &referenceEncoder{encoder}
}
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
return &base64Codec{}
}

View File

@ -0,0 +1,134 @@
package jsoniter
import (
"github.com/v2pro/plz/reflect2"
"unsafe"
"encoding"
"encoding/json"
)
type marshalerEncoder struct {
checkIsEmpty checkIsEmpty
valType reflect2.Type
}
func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
obj := encoder.valType.UnsafeIndirect(ptr)
if encoder.valType.IsNullable() && reflect2.IsNil(obj) {
stream.WriteNil()
return
}
marshaler := obj.(json.Marshaler)
bytes, err := marshaler.MarshalJSON()
if err != nil {
stream.Error = err
} else {
stream.Write(bytes)
}
}
func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.checkIsEmpty.IsEmpty(ptr)
}
type directMarshalerEncoder struct {
checkIsEmpty checkIsEmpty
}
func (encoder *directMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
marshaler := *(*json.Marshaler)(ptr)
if marshaler == nil {
stream.WriteNil()
return
}
bytes, err := marshaler.MarshalJSON()
if err != nil {
stream.Error = err
} else {
stream.Write(bytes)
}
}
func (encoder *directMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.checkIsEmpty.IsEmpty(ptr)
}
type textMarshalerEncoder struct {
valType reflect2.Type
checkIsEmpty checkIsEmpty
}
func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
obj := encoder.valType.UnsafeIndirect(ptr)
if encoder.valType.IsNullable() && reflect2.IsNil(obj) {
stream.WriteNil()
return
}
marshaler := (obj).(encoding.TextMarshaler)
bytes, err := marshaler.MarshalText()
if err != nil {
stream.Error = err
} else {
stream.WriteString(string(bytes))
}
}
func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.checkIsEmpty.IsEmpty(ptr)
}
type directTextMarshalerEncoder struct {
checkIsEmpty checkIsEmpty
}
func (encoder *directTextMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
marshaler := *(*encoding.TextMarshaler)(ptr)
if marshaler == nil {
stream.WriteNil()
return
}
bytes, err := marshaler.MarshalText()
if err != nil {
stream.Error = err
} else {
stream.WriteString(string(bytes))
}
}
func (encoder *directTextMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.checkIsEmpty.IsEmpty(ptr)
}
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)
iter.nextToken()
iter.unreadByte() // skip spaces
bytes := iter.SkipAndReturnBytes()
err := unmarshaler.UnmarshalJSON(bytes)
if err != nil {
iter.ReportError("unmarshalerDecoder", err.Error())
}
}
type textUnmarshalerDecoder struct {
templateInterface emptyInterface
}
func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
templateInterface := decoder.templateInterface
templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
unmarshaler := (*realInterface).(encoding.TextUnmarshaler)
str := iter.ReadString()
err := unmarshaler.UnmarshalText([]byte(str))
if err != nil {
iter.ReportError("textUnmarshalerDecoder", err.Error())
}
}

View File

@ -1,7 +1,6 @@
package jsoniter
import (
"encoding"
"encoding/base64"
"encoding/json"
"reflect"
@ -591,85 +590,3 @@ func (encoder *stringModeStringEncoder) Encode(ptr unsafe.Pointer, stream *Strea
func (encoder *stringModeStringEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.elemEncoder.IsEmpty(ptr)
}
type marshalerEncoder struct {
checkIsEmpty checkIsEmpty
valType reflect2.Type
}
func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
obj := encoder.valType.UnsafeIndirect(ptr)
if reflect2.IsNil(obj) {
stream.WriteNil()
return
}
marshaler := obj.(json.Marshaler)
bytes, err := marshaler.MarshalJSON()
if err != nil {
stream.Error = err
} else {
stream.Write(bytes)
}
}
func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.checkIsEmpty.IsEmpty(ptr)
}
type textMarshalerEncoder struct {
valType reflect2.Type
checkIsEmpty checkIsEmpty
}
func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
obj := encoder.valType.UnsafeIndirect(ptr)
if reflect2.IsNil(obj) {
stream.WriteNil()
return
}
marshaler := (obj).(encoding.TextMarshaler)
bytes, err := marshaler.MarshalText()
if err != nil {
stream.Error = err
} else {
stream.WriteString(string(bytes))
}
}
func (encoder *textMarshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.checkIsEmpty.IsEmpty(ptr)
}
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)
iter.nextToken()
iter.unreadByte() // skip spaces
bytes := iter.SkipAndReturnBytes()
err := unmarshaler.UnmarshalJSON(bytes)
if err != nil {
iter.ReportError("unmarshalerDecoder", err.Error())
}
}
type textUnmarshalerDecoder struct {
templateInterface emptyInterface
}
func (decoder *textUnmarshalerDecoder) Decode(ptr unsafe.Pointer, iter *Iterator) {
templateInterface := decoder.templateInterface
templateInterface.word = ptr
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
unmarshaler := (*realInterface).(encoding.TextUnmarshaler)
str := iter.ReadString()
err := unmarshaler.UnmarshalText([]byte(str))
if err != nil {
iter.ReportError("textUnmarshalerDecoder", err.Error())
}
}

View File

@ -106,4 +106,16 @@ func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
}
fieldPtr := unsafe.Pointer(deReferenced)
return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
}
type referenceEncoder struct {
encoder ValEncoder
}
func (encoder *referenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
encoder.encoder.Encode(unsafe.Pointer(&ptr), stream)
}
func (encoder *referenceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
return encoder.encoder.IsEmpty(unsafe.Pointer(&ptr))
}

View File

@ -71,19 +71,57 @@ func init() {
Map map[string]string
})(nil),
(*[]uint8)(nil),
(*[]GeoLocation)(nil),
(*[]jsonMarshaler)(nil),
(*[]jsonMarshalerMap)(nil),
(*[]textMarshaler)(nil),
(*[]textMarshalerMap)(nil),
)
}
type GeoLocation struct {
type jsonMarshaler struct {
Id string `json:"id,omitempty" db:"id"`
}
func (p *GeoLocation) MarshalJSON() ([]byte, error) {
func (p *jsonMarshaler) MarshalJSON() ([]byte, error) {
return []byte(`{}`), nil
}
func (p *GeoLocation) UnmarshalJSON(input []byte) error {
func (p *jsonMarshaler) UnmarshalJSON(input []byte) error {
p.Id = "hello"
return nil
}
type jsonMarshalerMap map[int]int
func (p *jsonMarshalerMap) MarshalJSON() ([]byte, error) {
return []byte(`{}`), nil
}
func (p *jsonMarshalerMap) UnmarshalJSON(input []byte) error {
return nil
}
type textMarshaler struct {
Id string `json:"id,omitempty" db:"id"`
}
func (p *textMarshaler) MarshalText() ([]byte, error) {
return []byte(`{}`), nil
}
func (p *textMarshaler) UnmarshalText(input []byte) error {
p.Id = "hello"
return nil
}
type textMarshalerMap map[int]int
func (p *textMarshalerMap) MarshalText() ([]byte, error) {
return []byte(`{}`), nil
}
func (p *textMarshalerMap) UnmarshalText(input []byte) error {
return nil
}

View File

@ -1,19 +1,42 @@
package test
import (
"encoding/json"
"encoding"
)
func init() {
jsonMarshaler := json.Marshaler(fakeJsonMarshaler{})
textMarshaler := encoding.TextMarshaler(fakeTextMarshaler{})
marshalCases = append(marshalCases,
withChan{},
fakeJsonMarshaler{},
&jsonMarshaler,
fakeTextMarshaler{},
&textMarshaler,
)
}
type withChan struct {
type fakeJsonMarshaler struct {
F2 chan []byte
}
func (q withChan) MarshalJSON() ([]byte, error) {
func (q fakeJsonMarshaler) MarshalJSON() ([]byte, error) {
return []byte(`""`), nil
}
func (q *withChan) UnmarshalJSON(value []byte) error {
func (q *fakeJsonMarshaler) UnmarshalJSON(value []byte) error {
return nil
}
type fakeTextMarshaler struct {
F2 chan []byte
}
func (q fakeTextMarshaler) MarshalText() ([]byte, error) {
return []byte(`""`), nil
}
func (q *fakeTextMarshaler) UnmarshalText(value []byte) error {
return nil
}