mirror of
https://github.com/json-iterator/go.git
synced 2025-04-20 11:28:49 +02:00
when embedded ptr is nil, the fields should be omitted
This commit is contained in:
parent
a7a34507ab
commit
9dafbc667f
@ -340,14 +340,10 @@ func createEncoderOfType(cfg *frozenConfig, prefix string, typ reflect.Type) Val
|
||||
}
|
||||
if typ.Implements(textMarshalerType) {
|
||||
checkIsEmpty := createCheckIsEmpty(cfg, typ)
|
||||
templateInterface := reflect.New(typ).Elem().Interface()
|
||||
var encoder ValEncoder = &textMarshalerEncoder{
|
||||
templateInterface: extractInterface(templateInterface),
|
||||
valType: reflect2.Type2(typ),
|
||||
checkIsEmpty: checkIsEmpty,
|
||||
}
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
encoder = &OptionalEncoder{encoder}
|
||||
}
|
||||
return encoder
|
||||
}
|
||||
if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
|
||||
@ -393,10 +389,7 @@ func createCheckIsEmpty(cfg *frozenConfig, typ reflect.Type) checkIsEmpty {
|
||||
case reflect.Bool:
|
||||
return &boolCodec{}
|
||||
case reflect.Interface:
|
||||
if typ.NumMethod() == 0 {
|
||||
return &emptyInterfaceCodec{}
|
||||
}
|
||||
return &nonEmptyInterfaceCodec{}
|
||||
return &dynamicEncoder{reflect2.Type2(typ)}
|
||||
case reflect.Struct:
|
||||
return &structEncoder{typ: typ}
|
||||
case reflect.Array:
|
||||
@ -492,10 +485,7 @@ func createEncoderOfSimpleType(cfg *frozenConfig, prefix string, typ reflect.Typ
|
||||
}
|
||||
return &boolCodec{}
|
||||
case reflect.Interface:
|
||||
if typ.NumMethod() == 0 {
|
||||
return &emptyInterfaceCodec{}
|
||||
}
|
||||
return &nonEmptyInterfaceCodec{}
|
||||
return &dynamicEncoder{reflect2.Type2(typ)}
|
||||
case reflect.Struct:
|
||||
return encoderOfStruct(cfg, prefix, typ)
|
||||
case reflect.Array:
|
||||
|
@ -17,8 +17,6 @@ var extensions = []Extension{}
|
||||
|
||||
// StructDescriptor describe how should we encode/decode the struct
|
||||
type StructDescriptor struct {
|
||||
onePtrEmbedded bool
|
||||
onePtrOptimization bool
|
||||
Type reflect.Type
|
||||
Fields []*Binding
|
||||
}
|
||||
@ -297,25 +295,7 @@ func describeStruct(cfg *frozenConfig, prefix string, typ reflect.Type) *StructD
|
||||
return createStructDescriptor(cfg, typ, bindings, embeddedBindings)
|
||||
}
|
||||
func createStructDescriptor(cfg *frozenConfig, typ reflect.Type, bindings []*Binding, embeddedBindings []*Binding) *StructDescriptor {
|
||||
onePtrEmbedded := false
|
||||
onePtrOptimization := false
|
||||
if typ.NumField() == 1 {
|
||||
firstField := typ.Field(0)
|
||||
switch firstField.Type.Kind() {
|
||||
case reflect.Ptr:
|
||||
if firstField.Anonymous && firstField.Type.Elem().Kind() == reflect.Struct {
|
||||
onePtrEmbedded = true
|
||||
}
|
||||
fallthrough
|
||||
case reflect.Map:
|
||||
onePtrOptimization = true
|
||||
case reflect.Struct:
|
||||
onePtrOptimization = isStructOnePtr(firstField.Type)
|
||||
}
|
||||
}
|
||||
structDescriptor := &StructDescriptor{
|
||||
onePtrEmbedded: onePtrEmbedded,
|
||||
onePtrOptimization: onePtrOptimization,
|
||||
Type: typ,
|
||||
Fields: bindings,
|
||||
}
|
||||
|
@ -357,6 +357,20 @@ func (codec *nonEmptyInterfaceCodec) IsEmpty(ptr unsafe.Pointer) bool {
|
||||
return nonEmptyInterface.word == nil
|
||||
}
|
||||
|
||||
type dynamicEncoder struct {
|
||||
valType reflect2.Type
|
||||
}
|
||||
|
||||
func (encoder *dynamicEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
obj := encoder.valType.UnsafeIndirect(ptr)
|
||||
stream.WriteVal(obj)
|
||||
}
|
||||
|
||||
func (encoder *dynamicEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
||||
return encoder.valType.UnsafeIndirect(ptr) == nil
|
||||
}
|
||||
|
||||
|
||||
type anyCodec struct {
|
||||
}
|
||||
|
||||
@ -390,7 +404,7 @@ func (codec *jsonNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
func (codec *jsonNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
number := *((*json.Number)(ptr))
|
||||
if len(number) == 0 {
|
||||
stream.WriteRaw("0")
|
||||
stream.writeByte('0')
|
||||
} else {
|
||||
stream.WriteRaw(string(number))
|
||||
}
|
||||
@ -418,7 +432,7 @@ func (codec *jsoniterNumberCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
func (codec *jsoniterNumberCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
number := *((*Number)(ptr))
|
||||
if len(number) == 0 {
|
||||
stream.WriteRaw("0")
|
||||
stream.writeByte('0')
|
||||
} else {
|
||||
stream.WriteRaw(string(number))
|
||||
}
|
||||
@ -603,15 +617,17 @@ func (encoder *marshalerEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
||||
}
|
||||
|
||||
type textMarshalerEncoder struct {
|
||||
templateInterface emptyInterface
|
||||
valType reflect2.Type
|
||||
checkIsEmpty checkIsEmpty
|
||||
}
|
||||
|
||||
func (encoder *textMarshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
templateInterface := encoder.templateInterface
|
||||
templateInterface.word = ptr
|
||||
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
|
||||
marshaler := (*realInterface).(encoding.TextMarshaler)
|
||||
obj := encoder.valType.UnsafeIndirect(ptr)
|
||||
if obj == nil {
|
||||
stream.WriteNil()
|
||||
return
|
||||
}
|
||||
marshaler := (obj).(encoding.TextMarshaler)
|
||||
bytes, err := marshaler.MarshalText()
|
||||
if err != nil {
|
||||
stream.Error = err
|
||||
|
@ -88,5 +88,22 @@ func (encoder *dereferenceEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
}
|
||||
|
||||
func (encoder *dereferenceEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
||||
return encoder.ValueEncoder.IsEmpty(*((*unsafe.Pointer)(ptr)))
|
||||
dePtr := *((*unsafe.Pointer)(ptr))
|
||||
if dePtr == nil {
|
||||
return true
|
||||
}
|
||||
return encoder.ValueEncoder.IsEmpty(dePtr)
|
||||
}
|
||||
|
||||
func (encoder *dereferenceEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
|
||||
deReferenced := *((*unsafe.Pointer)(ptr))
|
||||
if deReferenced == nil {
|
||||
return true
|
||||
}
|
||||
isEmbeddedPtrNil, converted := encoder.ValueEncoder.(IsEmbeddedPtrNil)
|
||||
if !converted {
|
||||
return false
|
||||
}
|
||||
fieldPtr := unsafe.Pointer(deReferenced)
|
||||
return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
|
||||
}
|
@ -42,8 +42,7 @@ func encoderOfStruct(cfg *frozenConfig, prefix string, typ reflect.Type) ValEnco
|
||||
})
|
||||
}
|
||||
}
|
||||
return &structEncoder{typ, structDescriptor.onePtrEmbedded,
|
||||
structDescriptor.onePtrOptimization, finalOrderedFields}
|
||||
return &structEncoder{typ, finalOrderedFields}
|
||||
}
|
||||
|
||||
func resolveConflictBinding(cfg *frozenConfig, old, new *Binding) (ignoreOld, ignoreNew bool) {
|
||||
@ -120,11 +119,22 @@ func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
||||
return encoder.fieldEncoder.IsEmpty(fieldPtr)
|
||||
}
|
||||
|
||||
func (encoder *structFieldEncoder) IsEmbeddedPtrNil(ptr unsafe.Pointer) bool {
|
||||
isEmbeddedPtrNil, converted := encoder.fieldEncoder.(IsEmbeddedPtrNil)
|
||||
if !converted {
|
||||
return false
|
||||
}
|
||||
fieldPtr := unsafe.Pointer(uintptr(ptr) + encoder.field.Offset)
|
||||
return isEmbeddedPtrNil.IsEmbeddedPtrNil(fieldPtr)
|
||||
}
|
||||
|
||||
type IsEmbeddedPtrNil interface {
|
||||
IsEmbeddedPtrNil(ptr unsafe.Pointer) bool
|
||||
}
|
||||
|
||||
type structEncoder struct {
|
||||
typ reflect.Type
|
||||
onePtrEmbedded bool
|
||||
onePtrOptimization bool
|
||||
fields []structFieldTo
|
||||
typ reflect.Type
|
||||
fields []structFieldTo
|
||||
}
|
||||
|
||||
type structFieldTo struct {
|
||||
@ -139,6 +149,9 @@ func (encoder *structEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
if field.encoder.omitempty && field.encoder.IsEmpty(ptr) {
|
||||
continue
|
||||
}
|
||||
if field.encoder.IsEmbeddedPtrNil(ptr) {
|
||||
continue
|
||||
}
|
||||
if isNotFirst {
|
||||
stream.WriteMore()
|
||||
}
|
@ -92,7 +92,8 @@ func init() {
|
||||
}{&StructVarious{}},
|
||||
struct {
|
||||
*StructVarious
|
||||
}{},
|
||||
Field int
|
||||
}{nil, 10},
|
||||
struct {
|
||||
Field1 int
|
||||
Field2 [1]*float64
|
||||
@ -172,7 +173,6 @@ type CacheItem struct {
|
||||
MaxAge int `json:"cacheAge"`
|
||||
}
|
||||
|
||||
|
||||
type orderA struct {
|
||||
Field2 string
|
||||
}
|
||||
@ -193,4 +193,4 @@ type structOrder struct {
|
||||
Field3 string
|
||||
orderB
|
||||
Field7 string
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user