mirror of
https://github.com/json-iterator/go.git
synced 2025-03-23 21:09:11 +02:00
#12 implement omitempty
This commit is contained in:
parent
ceb8c8a733
commit
d1aa59e34e
@ -22,6 +22,7 @@ type Decoder interface {
|
||||
}
|
||||
|
||||
type Encoder interface {
|
||||
isEmpty(ptr unsafe.Pointer) bool
|
||||
encode(ptr unsafe.Pointer, stream *Stream)
|
||||
encodeInterface(val interface{}, stream *Stream)
|
||||
}
|
||||
@ -59,6 +60,10 @@ func (encoder *funcEncoder) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (encoder *funcEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
var DECODERS unsafe.Pointer
|
||||
var ENCODERS unsafe.Pointer
|
||||
|
||||
@ -187,6 +192,14 @@ func (encoder *optionalEncoder) encodeInterface(val interface{}, stream *Stream)
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (encoder *optionalEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
if *((*unsafe.Pointer)(ptr)) == nil {
|
||||
return true
|
||||
} else {
|
||||
return encoder.valueEncoder.isEmpty(*((*unsafe.Pointer)(ptr)))
|
||||
}
|
||||
}
|
||||
|
||||
type mapDecoder struct {
|
||||
mapType reflect.Type
|
||||
elemType reflect.Type
|
||||
@ -240,6 +253,14 @@ func (encoder *mapEncoder) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (encoder *mapEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
mapInterface := encoder.mapInterface
|
||||
mapInterface.word = ptr
|
||||
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
|
||||
realVal := reflect.ValueOf(*realInterface)
|
||||
return realVal.Len() == 0
|
||||
}
|
||||
|
||||
type mapInterfaceEncoder struct {
|
||||
mapType reflect.Type
|
||||
elemType reflect.Type
|
||||
@ -269,6 +290,15 @@ func (encoder *mapInterfaceEncoder) encodeInterface(val interface{}, stream *Str
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (encoder *mapInterfaceEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
mapInterface := encoder.mapInterface
|
||||
mapInterface.word = ptr
|
||||
realInterface := (*interface{})(unsafe.Pointer(&mapInterface))
|
||||
realVal := reflect.ValueOf(*realInterface)
|
||||
|
||||
return realVal.Len() == 0
|
||||
}
|
||||
|
||||
// emptyInterface is the header for an interface{} value.
|
||||
type emptyInterface struct {
|
||||
typ *struct{}
|
||||
|
@ -53,6 +53,11 @@ func (encoder *sliceEncoder) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (encoder *sliceEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
slice := (*sliceHeader)(ptr)
|
||||
return slice.Len == 0
|
||||
}
|
||||
|
||||
type sliceDecoder struct {
|
||||
sliceType reflect.Type
|
||||
elemType reflect.Type
|
||||
|
@ -19,6 +19,10 @@ func (encoder *stringCodec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *stringCodec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*string)(ptr)) == ""
|
||||
}
|
||||
|
||||
type intCodec struct {
|
||||
}
|
||||
|
||||
@ -34,6 +38,10 @@ func (encoder *intCodec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *intCodec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*int)(ptr)) == 0
|
||||
}
|
||||
|
||||
type int8Codec struct {
|
||||
}
|
||||
|
||||
@ -49,6 +57,10 @@ func (encoder *int8Codec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *int8Codec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*int8)(ptr)) == 0
|
||||
}
|
||||
|
||||
type int16Codec struct {
|
||||
}
|
||||
|
||||
@ -64,6 +76,10 @@ func (encoder *int16Codec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *int16Codec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*int16)(ptr)) == 0
|
||||
}
|
||||
|
||||
type int32Codec struct {
|
||||
}
|
||||
|
||||
@ -79,6 +95,10 @@ func (encoder *int32Codec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *int32Codec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*int32)(ptr)) == 0
|
||||
}
|
||||
|
||||
type int64Codec struct {
|
||||
}
|
||||
|
||||
@ -94,6 +114,10 @@ func (encoder *int64Codec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *int64Codec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*int64)(ptr)) == 0
|
||||
}
|
||||
|
||||
type uintCodec struct {
|
||||
}
|
||||
|
||||
@ -109,6 +133,10 @@ func (encoder *uintCodec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *uintCodec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*uint)(ptr)) == 0
|
||||
}
|
||||
|
||||
type uint8Codec struct {
|
||||
}
|
||||
|
||||
@ -124,6 +152,10 @@ func (encoder *uint8Codec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *uint8Codec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*uint8)(ptr)) == 0
|
||||
}
|
||||
|
||||
type uint16Codec struct {
|
||||
}
|
||||
|
||||
@ -139,6 +171,10 @@ func (encoder *uint16Codec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *uint16Codec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*uint16)(ptr)) == 0
|
||||
}
|
||||
|
||||
type uint32Codec struct {
|
||||
}
|
||||
|
||||
@ -154,6 +190,10 @@ func (encoder *uint32Codec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *uint32Codec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*uint32)(ptr)) == 0
|
||||
}
|
||||
|
||||
type uint64Codec struct {
|
||||
}
|
||||
|
||||
@ -169,6 +209,10 @@ func (encoder *uint64Codec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *uint64Codec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*uint64)(ptr)) == 0
|
||||
}
|
||||
|
||||
type float32Codec struct {
|
||||
}
|
||||
|
||||
@ -184,6 +228,10 @@ func (encoder *float32Codec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *float32Codec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*float32)(ptr)) == 0
|
||||
}
|
||||
|
||||
type float64Codec struct {
|
||||
}
|
||||
|
||||
@ -199,6 +247,10 @@ func (encoder *float64Codec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *float64Codec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return *((*float64)(ptr)) == 0
|
||||
}
|
||||
|
||||
type boolCodec struct {
|
||||
}
|
||||
|
||||
@ -214,6 +266,10 @@ func (encoder *boolCodec) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (codec *boolCodec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return !(*((*bool)(ptr)))
|
||||
}
|
||||
|
||||
type interfaceCodec struct {
|
||||
}
|
||||
|
||||
@ -229,6 +285,10 @@ func (encoder *interfaceCodec) encodeInterface(val interface{}, stream *Stream)
|
||||
stream.WriteVal(val)
|
||||
}
|
||||
|
||||
func (codec *interfaceCodec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return ptr == nil
|
||||
}
|
||||
|
||||
type anyCodec struct {
|
||||
}
|
||||
|
||||
@ -244,6 +304,10 @@ func (encoder *anyCodec) encodeInterface(val interface{}, stream *Stream) {
|
||||
(val.(Any)).WriteTo(stream)
|
||||
}
|
||||
|
||||
func (encoder *anyCodec) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return (*((*Any)(ptr))).Size() == 0
|
||||
}
|
||||
|
||||
type stringNumberDecoder struct {
|
||||
elemDecoder Decoder
|
||||
}
|
||||
|
@ -33,9 +33,16 @@ func encoderOfStruct(typ reflect.Type) (Encoder, error) {
|
||||
fieldNames = []string{tagParts[0]}
|
||||
}
|
||||
}
|
||||
omitempty := false
|
||||
for _, tagPart := range tagParts {
|
||||
if tagPart == "omitempty" {
|
||||
omitempty = true
|
||||
}
|
||||
}
|
||||
var encoder Encoder
|
||||
var err error
|
||||
if len(fieldNames) > 0 {
|
||||
encoder, err := encoderOfType(field.Type)
|
||||
encoder, err = encoderOfType(field.Type)
|
||||
if err != nil {
|
||||
return prefix(fmt.Sprintf("{%s}", field.Name)).addToEncoder(encoder, err)
|
||||
}
|
||||
@ -46,14 +53,11 @@ func encoderOfStruct(typ reflect.Type) (Encoder, error) {
|
||||
}
|
||||
}
|
||||
for _, fieldName := range fieldNames {
|
||||
if structEncoder_.firstField == nil {
|
||||
structEncoder_.firstField = &structFieldEncoder{&field, fieldName, encoder}
|
||||
} else {
|
||||
structEncoder_.fields = append(structEncoder_.fields, &structFieldEncoder{&field, fieldName, encoder})
|
||||
}
|
||||
structEncoder_.fields = append(structEncoder_.fields,
|
||||
&structFieldEncoder{&field, fieldName, encoder, omitempty})
|
||||
}
|
||||
}
|
||||
if structEncoder_.firstField == nil {
|
||||
if len(structEncoder_.fields) == 0 {
|
||||
return &emptyStructEncoder{}, nil
|
||||
}
|
||||
return structEncoder_, nil
|
||||
@ -1024,6 +1028,7 @@ type structFieldEncoder struct {
|
||||
field *reflect.StructField
|
||||
fieldName string
|
||||
fieldEncoder Encoder
|
||||
omitempty bool
|
||||
}
|
||||
|
||||
func (encoder *structFieldEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
@ -1039,18 +1044,28 @@ func (encoder *structFieldEncoder) encodeInterface(val interface{}, stream *Stre
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (encoder *structFieldEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
fieldPtr := uintptr(ptr) + encoder.field.Offset
|
||||
return encoder.fieldEncoder.isEmpty(unsafe.Pointer(fieldPtr))
|
||||
}
|
||||
|
||||
|
||||
type structEncoder struct {
|
||||
firstField *structFieldEncoder
|
||||
fields []*structFieldEncoder
|
||||
}
|
||||
|
||||
func (encoder *structEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
stream.WriteObjectStart()
|
||||
encoder.firstField.encode(ptr, stream)
|
||||
isNotFirst := false
|
||||
for _, field := range encoder.fields {
|
||||
stream.WriteMore()
|
||||
if isNotFirst {
|
||||
stream.WriteMore()
|
||||
}
|
||||
if field.omitempty && field.isEmpty(ptr) {
|
||||
continue
|
||||
}
|
||||
field.encode(ptr, stream)
|
||||
isNotFirst = true
|
||||
}
|
||||
stream.WriteObjectEnd()
|
||||
}
|
||||
@ -1059,6 +1074,15 @@ func (encoder *structEncoder) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (encoder *structEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
for _, field := range encoder.fields {
|
||||
if !field.isEmpty(ptr) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
type emptyStructEncoder struct {
|
||||
}
|
||||
@ -1069,4 +1093,8 @@ func (encoder *emptyStructEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
|
||||
func (encoder *emptyStructEncoder) encodeInterface(val interface{}, stream *Stream) {
|
||||
WriteToStream(val, stream, encoder)
|
||||
}
|
||||
|
||||
func (encoder *emptyStructEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return true
|
||||
}
|
@ -158,4 +158,17 @@ func Test_mixed(t *testing.T) {
|
||||
should.Nil(err)
|
||||
should.Equal(1, aa.ID)
|
||||
should.Equal("123", aa.Payload["account"])
|
||||
}
|
||||
|
||||
func Test_omit_empty(t *testing.T) {
|
||||
should := require.New(t)
|
||||
type TestObject struct {
|
||||
Field1 string `json:"field-1,omitempty"`
|
||||
Field2 string `json:"field-2,omitempty"`
|
||||
}
|
||||
obj := TestObject{}
|
||||
obj.Field2 = "hello"
|
||||
str, err := MarshalToString(&obj)
|
||||
should.Nil(err)
|
||||
should.Equal(`{"field-2":"hello"}`, str)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user