Skip to content

Commit

Permalink
Merge pull request #85 from zerosnake0/issue84
Browse files Browse the repository at this point in the history
fix embedded struct copy
  • Loading branch information
jinzhu authored Feb 26, 2021
2 parents db116d0 + dcb8619 commit 46cc1a5
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 11 deletions.
19 changes: 8 additions & 11 deletions copier.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,27 +194,24 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error)
// process for nested anonymous field
destFieldNotSet := false
if f, ok := dest.Type().FieldByName(name); ok {
for idx, x := range f.Index {
if x >= dest.NumField() {
continue
}
for idx := range f.Index {
destField := dest.FieldByIndex(f.Index[:idx+1])

destFieldKind := dest.Field(x).Kind()
if destFieldKind != reflect.Ptr {
if destField.Kind() != reflect.Ptr {
continue
}

if !dest.Field(x).IsNil() {
if !destField.IsNil() {
continue
}

if !dest.Field(x).CanSet() {
if !destField.CanSet() {
destFieldNotSet = true
break
}

newValue := reflect.New(dest.FieldByIndex(f.Index[0 : idx+1]).Type().Elem())
dest.Field(x).Set(newValue)
// destField is a nil pointer that can be set
newValue := reflect.New(destField.Type().Elem())
destField.Set(newValue)
}
}

Expand Down
89 changes: 89 additions & 0 deletions copier_issue84_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package copier_test

import (
"fmt"
"testing"
"time"

"github.com/jinzhu/copier"
)

type Embedded struct {
Field1 string
Field2 string
}

type Embedder struct {
Embedded
PtrField *string
}

type Timestamps struct {
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

type NotWork struct {
ID string `json:"id"`
UserID *string `json:"user_id"`
Name string `json:"name"`
Website *string `json:"website"`
Timestamps
}

type Work struct {
ID string `json:"id"`
Name string `json:"name"`
UserID *string `json:"user_id"`
Website *string `json:"website"`
Timestamps
}

func TestIssue84(t *testing.T) {
t.Run("test1", func(t *testing.T) {
var embedder Embedder
embedded := Embedded{
Field1: "1",
Field2: "2",
}
err := copier.Copy(&embedder, &embedded)
if err != nil {
t.Errorf("unable to copy: %s", err)
}
if embedder.Field1 != embedded.Field1 {
t.Errorf("field1 value is %s instead of %s", embedder.Field1, embedded.Field1)
}
if embedder.Field2 != embedded.Field2 {
t.Errorf("field2 value is %s instead of %s", embedder.Field2, embedded.Field2)
}
})
t.Run("from issue", func(t *testing.T) {
notWorkObj := NotWork{
ID: "123",
Name: "name",
Website: nil,
UserID: nil,
Timestamps: Timestamps{
UpdatedAt: time.Now(),
},
}
workObj := Work{
ID: "123",
Name: "name",
Website: nil,
UserID: nil,
Timestamps: Timestamps{
UpdatedAt: time.Now(),
},
}

destObj1 := Work{}
destObj2 := NotWork{}

copier.CopyWithOption(&destObj1, &workObj, copier.Option{IgnoreEmpty: true, DeepCopy: false})
fmt.Println(destObj1)

copier.CopyWithOption(&destObj2, &notWorkObj, copier.Option{IgnoreEmpty: true, DeepCopy: false})
fmt.Println(destObj2)
})
}

0 comments on commit 46cc1a5

Please sign in to comment.