From 0d57bf1014e330d86022859b9f34b3ea1369d027 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Tue, 9 Feb 2021 09:20:48 +0900 Subject: [PATCH 1/3] Fix encoding of anonymous struct --- encode_compile.go | 38 +++++++++++++++++++++++++++++++++++++- encode_test.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/encode_compile.go b/encode_compile.go index 832cd29..e4fd595 100644 --- a/encode_compile.go +++ b/encode_compile.go @@ -1116,7 +1116,7 @@ func encodeAnonymousStructFieldPairMap(tags structTags, named string, valueCode isTaggedKey: f.isTaggedKey, }) if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField { - for k, v := range encodeAnonymousStructFieldPairMap(tags, named, f.next) { + for k, v := range encodeAnonymousFieldPairRecursively(tags, named, f.next) { anonymousFields[k] = append(anonymousFields[k], v...) } } @@ -1129,6 +1129,42 @@ func encodeAnonymousStructFieldPairMap(tags structTags, named string, valueCode return anonymousFields } +func encodeAnonymousFieldPairRecursively(tags structTags, named string, valueCode *opcode) map[string][]structFieldPair { + anonymousFields := map[string][]structFieldPair{} + f := valueCode + var prevAnonymousField *opcode + for { + if f.displayKey == "" { + if f.nextField == nil { + break + } + prevAnonymousField = f + f = f.nextField + continue + } + + if strings.Contains(f.op.String(), "Anonymous") { + key := fmt.Sprintf("%s.%s", named, f.displayKey) + anonymousFields[key] = append(anonymousFields[key], structFieldPair{ + prevField: prevAnonymousField, + curField: f, + isTaggedKey: f.isTaggedKey, + }) + if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField { + for k, v := range encodeAnonymousFieldPairRecursively(tags, named, f.next) { + anonymousFields[k] = append(anonymousFields[k], v...) + } + } + } + if f.nextField == nil { + break + } + prevAnonymousField = f + f = f.nextField + } + return anonymousFields +} + func encodeOptimizeConflictAnonymousFields(anonymousFields map[string][]structFieldPair) { removedFields := map[*opcode]struct{}{} for _, fieldPairs := range anonymousFields { diff --git a/encode_test.go b/encode_test.go index 2ac1eb4..cfdfa6a 100644 --- a/encode_test.go +++ b/encode_test.go @@ -409,6 +409,53 @@ func Test_Marshal(t *testing.T) { }) } +func TestIssue116(t *testing.T) { + t.Run("first", func(t *testing.T) { + type Boo struct{ B string } + type Struct struct { + A int + Boo *Boo + } + type Embedded struct { + Struct + } + b, err := json.Marshal(Embedded{Struct: Struct{ + A: 1, + Boo: &Boo{B: "foo"}, + }}) + if err != nil { + t.Fatal(err) + } + expected := `{"A":1,"Boo":{"B":"foo"}}` + actual := string(b) + if actual != expected { + t.Fatalf("expected %s but got %s", expected, actual) + } + }) + t.Run("second", func(t *testing.T) { + type Boo struct{ B string } + type Struct struct { + A int + B *Boo + } + type Embedded struct { + Struct + } + b, err := json.Marshal(Embedded{Struct: Struct{ + A: 1, + B: &Boo{B: "foo"}, + }}) + if err != nil { + t.Fatal(err) + } + actual := string(b) + expected := `{"A":1,"B":{"B":"foo"}}` + if actual != expected { + t.Fatalf("expected %s but got %s", expected, actual) + } + }) +} + type marshalJSON struct{} func (*marshalJSON) MarshalJSON() ([]byte, error) { From d2de9a1eb5678e8a685ecb1f7e4f937682593cce Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Tue, 9 Feb 2021 09:23:15 +0900 Subject: [PATCH 2/3] Refactor --- encode_compile.go | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/encode_compile.go b/encode_compile.go index e4fd595..5f07b32 100644 --- a/encode_compile.go +++ b/encode_compile.go @@ -1134,16 +1134,7 @@ func encodeAnonymousFieldPairRecursively(tags structTags, named string, valueCod f := valueCode var prevAnonymousField *opcode for { - if f.displayKey == "" { - if f.nextField == nil { - break - } - prevAnonymousField = f - f = f.nextField - continue - } - - if strings.Contains(f.op.String(), "Anonymous") { + if f.displayKey != "" && strings.Contains(f.op.String(), "Anonymous") { key := fmt.Sprintf("%s.%s", named, f.displayKey) anonymousFields[key] = append(anonymousFields[key], structFieldPair{ prevField: prevAnonymousField, From 7d83cfcea1a96ffc55ad6bc7bd25ff2f72994000 Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Tue, 9 Feb 2021 09:25:33 +0900 Subject: [PATCH 3/3] Fix error by linter --- encode_compile.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/encode_compile.go b/encode_compile.go index 5f07b32..3cc1ff3 100644 --- a/encode_compile.go +++ b/encode_compile.go @@ -1116,7 +1116,7 @@ func encodeAnonymousStructFieldPairMap(tags structTags, named string, valueCode isTaggedKey: f.isTaggedKey, }) if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField { - for k, v := range encodeAnonymousFieldPairRecursively(tags, named, f.next) { + for k, v := range encodeAnonymousFieldPairRecursively(named, f.next) { anonymousFields[k] = append(anonymousFields[k], v...) } } @@ -1129,7 +1129,7 @@ func encodeAnonymousStructFieldPairMap(tags structTags, named string, valueCode return anonymousFields } -func encodeAnonymousFieldPairRecursively(tags structTags, named string, valueCode *opcode) map[string][]structFieldPair { +func encodeAnonymousFieldPairRecursively(named string, valueCode *opcode) map[string][]structFieldPair { anonymousFields := map[string][]structFieldPair{} f := valueCode var prevAnonymousField *opcode @@ -1142,7 +1142,7 @@ func encodeAnonymousFieldPairRecursively(tags structTags, named string, valueCod isTaggedKey: f.isTaggedKey, }) if f.next != nil && f.nextField != f.next && f.next.op.codeType() == codeStructField { - for k, v := range encodeAnonymousFieldPairRecursively(tags, named, f.next) { + for k, v := range encodeAnonymousFieldPairRecursively(named, f.next) { anonymousFields[k] = append(anonymousFields[k], v...) } }