From 69e40becbf7d462eae0f0092d246541ecc9cc241 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Sat, 10 Apr 2021 16:25:45 +0900 Subject: [PATCH] Fix encoding of omitempty feature for the slice or interface type --- encode_test.go | 46 ++++++++++++++++++++++++ internal/encoder/compiler.go | 2 +- internal/encoder/vm/vm.go | 4 +-- internal/encoder/vm_debug/vm.go | 4 +-- internal/encoder/vm_escaped/vm.go | 4 +-- internal/encoder/vm_escaped_indent/vm.go | 4 +-- internal/encoder/vm_indent/vm.go | 4 +-- 7 files changed, 57 insertions(+), 11 deletions(-) diff --git a/encode_test.go b/encode_test.go index 54fbddf..9c4ce9a 100644 --- a/encode_test.go +++ b/encode_test.go @@ -1806,6 +1806,52 @@ func TestIssue104(t *testing.T) { } } +func TestIssue179(t *testing.T) { + data := ` +{ + "t": { + "t1": false, + "t2": 0, + "t3": "", + "t4": [], + "t5": null, + "t6": null + } +}` + type T struct { + X struct { + T1 bool `json:"t1,omitempty"` + T2 float64 `json:"t2,omitempty"` + T3 string `json:"t3,omitempty"` + T4 []string `json:"t4,omitempty"` + T5 *struct{} `json:"t5,omitempty"` + T6 interface{} `json:"t6,omitempty"` + } `json:"x"` + } + var v T + if err := stdjson.Unmarshal([]byte(data), &v); err != nil { + t.Fatal(err) + } + var v2 T + if err := json.Unmarshal([]byte(data), &v2); err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(v, v2) { + t.Fatalf("failed to decode: expected %v got %v", v, v2) + } + b1, err := stdjson.Marshal(v) + if err != nil { + t.Fatal(err) + } + b2, err := json.Marshal(v2) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(b1, b2) { + t.Fatalf("failed to equal encoded result: expected %q but got %q", b1, b2) + } +} + func TestIssue180(t *testing.T) { v := struct { T struct { diff --git a/internal/encoder/compiler.go b/internal/encoder/compiler.go index 2372586..e55d7f6 100644 --- a/internal/encoder/compiler.go +++ b/internal/encoder/compiler.go @@ -1439,7 +1439,7 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) { Indirect: indirect, Nilcheck: nilcheck, AddrForMarshaler: addrForMarshaler, - IsNextOpPtrType: strings.Contains(valueCode.Op.String(), "Ptr"), + IsNextOpPtrType: strings.Contains(valueCode.Op.String(), "Ptr") || valueCode.Op == OpInterface, IsNilableType: isNilableType, } if fieldIdx == 0 { diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index 951d773..6522548 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -2451,7 +2451,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } p += code.Offset slice := ptrToSlice(p) - if slice.Data == nil { + if slice.Len == 0 { code = code.NextField } else { b = append(b, code.Key...) @@ -3780,7 +3780,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) p += code.Offset slice := ptrToSlice(p) - if slice.Data == nil { + if slice.Len == 0 { code = code.NextField } else { b = append(b, code.Key...) diff --git a/internal/encoder/vm_debug/vm.go b/internal/encoder/vm_debug/vm.go index c55827a..585699b 100644 --- a/internal/encoder/vm_debug/vm.go +++ b/internal/encoder/vm_debug/vm.go @@ -2464,7 +2464,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } p += code.Offset slice := ptrToSlice(p) - if slice.Data == nil { + if slice.Len == 0 { code = code.NextField } else { b = append(b, code.Key...) @@ -3793,7 +3793,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) p += code.Offset slice := ptrToSlice(p) - if slice.Data == nil { + if slice.Len == 0 { code = code.NextField } else { b = append(b, code.Key...) diff --git a/internal/encoder/vm_escaped/vm.go b/internal/encoder/vm_escaped/vm.go index 719e8f9..b0c608f 100644 --- a/internal/encoder/vm_escaped/vm.go +++ b/internal/encoder/vm_escaped/vm.go @@ -2451,7 +2451,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } p += code.Offset slice := ptrToSlice(p) - if slice.Data == nil { + if slice.Len == 0 { code = code.NextField } else { b = append(b, code.EscapedKey...) @@ -3780,7 +3780,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) p += code.Offset slice := ptrToSlice(p) - if slice.Data == nil { + if slice.Len == 0 { code = code.NextField } else { b = append(b, code.EscapedKey...) diff --git a/internal/encoder/vm_escaped_indent/vm.go b/internal/encoder/vm_escaped_indent/vm.go index 23f2cbf..00c03d9 100644 --- a/internal/encoder/vm_escaped_indent/vm.go +++ b/internal/encoder/vm_escaped_indent/vm.go @@ -2576,7 +2576,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } p += code.Offset slice := ptrToSlice(p) - if slice.Data == nil { + if slice.Len == 0 { code = code.NextField } else { b = appendIndent(ctx, b, code.Indent+1) @@ -4059,7 +4059,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) p += code.Offset slice := ptrToSlice(p) - if slice.Data == nil { + if slice.Len == 0 { code = code.NextField } else { b = appendIndent(ctx, b, code.Indent) diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index 4406462..518ddaf 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -2576,7 +2576,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt } p += code.Offset slice := ptrToSlice(p) - if slice.Data == nil { + if slice.Len == 0 { code = code.NextField } else { b = appendIndent(ctx, b, code.Indent+1) @@ -4059,7 +4059,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) p += code.Offset slice := ptrToSlice(p) - if slice.Data == nil { + if slice.Len == 0 { code = code.NextField } else { b = appendIndent(ctx, b, code.Indent)