jinzhu / copier Goto Github PK
View Code? Open in Web Editor NEWCopier for golang, copy value from struct to struct and more
License: MIT License
Copier for golang, copy value from struct to struct and more
License: MIT License
Currently, copying a struct field pointer is copying pointer. So modifications on struct source or dst affect both structs.
type Details struct {
Info string
Info2 *string
}
type User struct {
Details *Details
}
info2 := "world"
from := User{Details: &Details{Info: "hello", Info2: &info2}}
to := User{}
copier.Copy(&to, from)
*to.Details.Info2 = "new value" // => *from.Details.Info2 is now set to "new value"
res := []SampleArray{}
if err := copier.Copy(&SampleArray, sourceArray); err != nil {
return nil, errors.Wrap(err, "failed to copy response")
}
if sourceArray is zero length array then res is nil !!
i want res is zero length array!!
Lower case field names are ignored and not copied.
is this by design?
https://play.golang.org/p/hZnz2rIy2_Z
Please look at the example code.
I can copy this struct:
type Work struct {
ID string `json:"id"`
Name string `json:"name"`
UserID *string `json:"user_id"`
Website *string `json:"website"`
Timestamps
}
but not this:
type NotWork struct {
ID string `json:"id"`
UserID *string `json:"user_id"`
Name string `json:"name"`
Website *string `json:"website"`
Timestamps
}
https://play.golang.org/p/dGhNPDZQtPu
Hi everyone,
I had several issue copying a structure to another which contain pointers.
It seems that if your structure cointain some pointer to another struct, the pointer address from the source is copied rather than building a new object and set the value of the pointer to the new instance.
So when you change the value of the destination object for instance, you will automatically change the value of the source ... which is not what I / (we ?) expect.
I shared the example here
I think that is a huge issue
Thanks in advance :) !
Have you seen these benchmarks here? https://github.com/gotidy/copy#benchmark
What do you think about it? Can we improve by taking a cue from there?
The difference is very high.
Thanks for your effort and your help. 😃
type structSameName1 struct {
A string
B int64
C time.Time
}
type structSameName2 struct {
A string
B time.Time
C int64
}
obj1 := structSameName1{A: "123", B: 2, C: time.Now()}
obj2 := &structSameName2{}
err := copier.Copy(obj2, &obj1)
t.Log(err)
It will raise an error
panic: reflect: call of reflect.Value.FieldByName on int64 Value
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type Person struct {
Name string
}
func main() {
a := []Person{Person{Name: "Li"}}
b := []Person{}
err := copier.Copy(&b, &a)
fmt.Println(err)
fmt.Println(b)
}
source slice type unsupported
<nil>
[{Li}]
copy is successful, but err is not none.
maybe you should add "return None" after https://github.com/jinzhu/copier/blob/master/copier.go#L90
// Model
type User struct {
JoinedAt time.Time
ReleavedAt *time.Time
}
// Resource
type UserResource struct {
JoinedAt string
ReceivedAt string
}
Want to copy from User to UserResource.
var m = make(map[string]string)
m["a"] = "ccc"
from := []interface{}{[]int{7,8,9},2,3, m, errors.New("aaaa")}
var to []interface{}
copier.CopyWithOption(&to, &from, copier.Option{
IgnoreEmpty: false,
DeepCopy: true,
})
from[0].([]int)[0] = 10
fmt.Println(to)
this code will panic
The implementation doesn't actually create a new slice for the copy. The test doesn't catch this because the test is also flawed. I don't understand reflect
enough to attempt a fix.
The patch pasted in here fixes the test and hence surfaces the bug.
diff --git a/copier_test.go b/copier_test.go
index 977194d3..869e4e03 100644
--- a/copier_test.go
+++ b/copier_test.go
@@ -175,7 +175,9 @@ func TestAssignableTypeMethod(t *testing.T) {
}
func TestCopyStruct(t *testing.T) {
- user := User{Name: "Jinzhu", Age: 18, Role: "Admin", Notes: []string{"hello world"}, flags: []byte{'x'}}
+ notes := make([]string, 0, 10)
+ notes = append(notes, "hello world")
+ user := User{Name: "Jinzhu", Age: 18, Role: "Admin", Notes: notes, flags: []byte{'x'}}
employee := Employee{}
Copy(&employee, &user)
Is there a way to copy only the not null fields?
Example:
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type Player struct {
Firstname string
Username *string
UserDetail *UserDetail
}
type PlayerInput struct {
Firstname *string
Username *string
UserDetail *UserDetail
}
type UserDetail struct {
Email *string
}
func main() {
inputFirstname := "Bob"
input := PlayerInput{
Firstname: &inputFirstname,
}
outputUsername := "BobTheBob"
output := Player{
Username: &outputUsername,
}
copier.Copy(&output, &input)
fmt.Printf("%#v \n", output)
}
I get:
main.Player{Firstname:"Bob", Username:(*string)(nil), UserDetail:(*main.UserDetail)(nil)}
I would:
main.Player{Firstname:"Bob", Username:"BobTheBob", UserDetail:(*main.UserDetail)(nil)}
Is this possible?
In some scenarios, it is not necessary to copy all the fields.
In the cache, data is stored with pointers. Now there is a scenario where only some fields of this data need to be removed, but the pointer content cannot be modified. Due to the complexity of data structure, only deep copy can be used.
type CollectionAlias struct {
CollectionName string `json:"collection_name"`
Name string `json:"name"`
}
func createNewCollectionAlias(collectionName string, name string) *api.CollectionAlias {
return &api.CollectionAlias{
CollectionName: collectionName,
Name: name,
}
}
...
expectedResult := []*api.CollectionAlias{
createNewCollectionAlias("collection", "collection_alias1"),
createNewCollectionAlias("collection", "collection_alias2"),
createNewCollectionAlias("collection", "collection_alias3"),
}
mockedResult := []*api.CollectionAlias{}
copier.Copy(&mockedResult, &expectedResult) // <--- panic here
This bug is reproducible for all versions > v0.2.0
You can get more details here.
Issue demonstrated in following code snippet.
package main
import (
"fmt"
"github.com/jinzhu/copier"
)
type A struct {
X []int
}
type B struct {
X []int
}
func main() {
x := []int{1, 50}
a := A{X: x}
b := B{}
copier.Copy(&b, a)
fmt.Printf("X0 in B %v %v\n", b.X[0], b.X[1]) // Returns 1
fmt.Printf("X0 in A %v %v\n", a.X[0], a.X[1]) // Returns 1
a.X[0] = -1
a.X[1] = -50
fmt.Printf("X in B %v %v\n", b.X[0], b.X[1]) // Returns -1
fmt.Printf("X in A %v %v\n", a.X[0], a.X[1]) // Returns -1
}
type slice0 struct {
sl1 []slice1
}
type slice1 struct {
sl2 []slice2
}
type slice2 struct {
sl2 []int
}
realdata := slice0{[]slice1{slice1{[]slice2{slice2{[]int{1, 2, 3}}}}}}
var copydata slice0
copier.Copy(©data, &realdata)
copydata.sl1[0] = slice1{[]slice2{slice2{[]int{10, 20, 30}}}}
Playground example
https://play.golang.org/p/drVdfl5hx7M
Running above example results in error index out of range
.
Hello,
This package is missing a license. Could you specify what license it has?
Most go packages just use a vanilla MIT license like this:
The MIT License (MIT)
Copyright (c) 2015 Jinzhu
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Thanks!
Ernesto
https://play.golang.org/p/XPEKi-yqqFA
Hi everyone,
I'm facing an error using the Copy() method when I copy an interface{} (real type : slice of pointers to struct) to an other interface{}.
See above the example.
This test case was correct in version v0.1.0 and is wfrom from version v0.2.0 to v0.2.5
so if I have a struct:
package main
import "log"
var s = struct{Foo string}{"foo"}
func acceptStruct(a interface{}, b interface{}) bool {
return a == b
}
func main() {
log.Println(acceptStruct(s, &s))
}
will the first argument be copied - and how is the copy different than the deep copy that this library uses?
https://play.golang.org/p/RJOgBhY1oGo
Hi everyone,
I'm facing again a panic using the CopyWithOptions() method.
See above the example.
It seems this is related to map[x]interface{}
@jinzhu
https://play.golang.org/p/pbA2Z1XJotV
Hi everyone,
I'm not abble to copy structure of type time.Time
.
See the example above.
like https://godoc.org/github.com/imdario/mergo#Map
Could we add this feature?
refs #38 - I have updated a comment to improve the clarity of the documentation, please look into it.
https://play.golang.org/p/MxExk1tAYqu
Performing a deep copy of a struct that has an unset interface{}
field will cause a panic with: panic: reflect: New(nil)
. It looks like copier is assuming the field will have an underlying type, which isn't always the case.
Not sure if interface{} objects are supported but I'm trying to clone a JSON object of type map[string]interface{}
without success.
Here's my test:
import "mytest/copier"
import "encoding/json"
import "io/ioutil"
import "fmt"
func main() {
var jsonObject map[string]interface{}
data, _ := ioutil.ReadFile("./test.json")
json.NewDecoder(data).Decode(&jsonObject)
fmt.Println("Result:", jsonObject)
}
Output:
panic: reflect: NumField of non-struct type
goroutine 1 [running]:
panic(0x361fc0, 0xc42013abe0)
/usr/local/Cellar/go/1.7.3/libexec/src/runtime/panic.go:500 +0x1a1
reflect.(*rtype).NumField(0x396420, 0xabdc8)
/usr/local/Cellar/go/1.7.3/libexec/src/reflect/type.go:1003 +0x96
copier.deepFields(0x58fac0, 0x396420, 0x195, 0x58fac0, 0x396420)
/Users/guatedude/Projects/go/src/mytest/copier/copier.go:123 +0x76
copier.Copy(0x384820, 0xc420134230, 0x384820, 0xc420134228, 0xc420131470, 0xc42012d640)
/Users/guatedude/Projects/go/src/mytest/copier/copier.go:70 +0x3d2
main.main()
/Users/guatedude/Projects/go/src/mytest/main.go:63 +0x11c7
Like this
type Elem1 struct {
E Elem1
E1 int
}
type Elem2 struct {
E Elem2
E1 int
}
type A struct {
B Elem1
}
type C struct {
B Elem2
}
a := new(A)
c := new(C)
copy(c, a)
will panic
From struct have time.Time attribute and I want to copy that to string in another struct. @jinzhu
import "fmt"
import "github.com/jinzhu/copier"
type Outer struct {
Inner Inner
}
type Inner struct {
intPtr *int
}
type DriverOptions struct {
GenOptions map[string]interface{}
}
func main() {
intVal := 5
outer := Outer{
Inner: Inner{
intPtr: &intVal,
},
}
from := DriverOptions{
GenOptions: map[string]interface{}{
"key": outer,
},
}
to := DriverOptions{}
if err := copier.Copy(&to, &from); nil != err {
return
}
*to.GenOptions["key"].(Outer).Inner.intPtr = 6
fmt.Println(*from.GenOptions["key"].(Outer).Inner.intPtr)
}
6
有两个struct的属性字段名不同,但是含义却是相同的,例如:
type User struct {
Name string
}
type UserVo struct{
UserName string
}
Java中类似的库orika就提供了下面的处理方案。
mapperFactory.classMap(PersonSource.class, PersonDestination.class)
.field("firstName", "givenName")
.field("lastName", "sirName")
.byDefault()
.register();
这种场景还是比较常见的,希望能提供类似的功能支持
刚发现PR中前两天正好有人提了。
Copy different field name from tag flag #86
It's a bit similar to #17:
import (
"log"
"github.com/jinzhu/copier"
)
type x struct{ Name string }
type structSameName1 struct {
A string
B []x
}
type structSameName2 struct {
A string
B x
}
func main() {
obj1 := structSameName1{A: "123", B: []x{{Name: "ee"}}}
obj2 := &structSameName2{}
err := copier.Copy(obj2, &obj1)
log.Println(err)
}
Running this will lead to panic:
panic: reflect: call of reflect.Value.FieldByName on slice Value
Not sure if this is a bug, but it won't panic in an old e15f8e2. And thanks for your time on this project :)
As code shown as below, elements in slices aren't merged but appended due to fromType.ConvertibleTo(toType)
is false
.
In my view the two struct is identical expect for all fields is ptr
type, and if you directly copy the struct it's working fine.
Seems like root cause is behavior of isSlice
flag and if from.Kind() == reflect.Slice && to.Kind() == reflect.Slice && fromType.ConvertibleTo(toType)
branch isn't consistent. But currently I don't know how to fix this. Could you please provide some clarification and help?
Thx.
type TestStruct struct {
Name string `json:"name"`
Number int `json:"number"`
}
type TestPtrStruct struct {
Name *string `json:"name"`
Number *int `json:"number"`
}
func main() {
s := "def"
ts := []TestStruct{{Name: "abc"}}
tps := []TestPtrStruct{{Name: &s}}
err := copier.Copy(&ts, &tps)
if err != nil {
fmt.Printf("error while copy: %v\n", err)
return
}
fmt.Println(ts)
t := TestStruct{Name: "abc"}
tp := TestPtrStruct{Name: &s}
err = copier.Copy(&t, &tp)
if err != nil {
fmt.Printf("error while copy: %v\n", err)
return
}
fmt.Println(t)
}
Output:
[{abc 0} {def 0}]
{def 0}
Expected output:
[{def 0}]
{def 0}
Here is the setup:
type Outer struct {
Inner Inner1
}
type Inner1 struct {
Inner *Inner2
}
type Inner2 struct {
Foo string
}
func TestDeepCopy(t *testing.T) {
original := &Outer{Inner: Inner1{Inner: &Inner2{Foo: "foo"}}}
copied := &Outer{}
copier.Copy(copied, original)
copied.Inner.Inner.Foo = "bar"
assert.Equal(t, "foo", original.Inner.Inner.Foo)
}
Outer
is the type that I want to copy, it has a nested struct via value: Inner1
, that struct has a nested struct via pointer: *Inner2
.
After coping I update the most inner field Foo
in the new struct, and expect, that it won't change in the original struct. But it does change.
hi dear,
i have some struct like this
type BaseModel struct {
ID uint `json:"id" gorm:"primary_key"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
DeletedAt *time.Time `json:"deletedAt"`
}
// PostResource post resource
type PostResource struct {
BaseModel
Title string `json:"title"`
Description string `json:"description"`
// Tags []Tag `json:"tags"`
}
// Post post model
type Post struct {
BaseModel
UserID int `json:"-"`
ImageID int `json:"-"`
TagID int `json:"-"`
Hit int `json:"hit"`
Title string `json:"title"`
Slug string `json:"slug"`
Description string `json:"description"`
Body string `json:"body"`
User User `json:"user"`
Tags []Tag `gorm:"many2many:pivot_tip_tag;"`
}
i am trying copy Post to PostResource, but the BaseModel fields(ID,CreatedAt,UpdatedAt,DeletedAt) not copying.
do you have any idea ?
In the readme, you have a "Role", and "SuperRule": is that a typo of "SuperRole"?
I am using your library in my project.
Compilation Errror:-
vendor/github.com/jinzhu/copier/copier.go:211:10: v.IsZero undefined (type reflect.Value has no field or method IsZero)
assigned by the same field name in Struct, is there a way assign copy by json tag?
The following code causes a panic:
package main
import "github.com/jinzhu/copier"
func main() {
type nested struct {
A string
}
type parentA struct {
*nested
}
type parentB struct {
*nested
}
a := parentA{nested: &nested{A: "a"}}
b := parentB{}
copier.Copy(&b, &a)
}
stack trace:
$ go run copier_panic.go
panic: reflect: indirection through nil pointer to embedded struct
goroutine 1 [running]:
reflect.Value.FieldByIndex(0x4d4fe0, 0xc04206e020, 0x199, 0xc0420500d0, 0x2, 0x2, 0x0, 0x568f40, 0x4c8a00)
C:/tools/go/src/reflect/value.go:804 +0x276
reflect.Value.FieldByName(0x4d4fe0, 0xc04206e020, 0x199, 0x4b5ea6, 0x1, 0x4c8a00, 0xc042044250, 0x198)
C:/tools/go/src/reflect/value.go:820 +0x16e
github.com/jinzhu/copier.Copy(0x4c2a60, 0xc04206e020, 0x4c2a20, 0xc04206e018, 0x0, 0x0)
E:/workspace/golang/src/github.com/jinzhu/copier/copier.go:71 +0x491
main.main()
E:/workspace/golang/src/playground/copier_panic.go:18 +0xb1
exit status 2
The issue originates from this:
Line 71 in db4671f
Is this something that can be fixed in copier
? I don't know enough about reflection but if you can guide me, I can make a PR to fix this.
The io.Copy function in the standard library is of form io.Copy(dst, src)
but your Copy function is Copy(src, dst)
. Should it be changed?
That would break existing code though.
https://play.golang.org/p/7-NoMKFRhsY
I'm need make a full copy of structs like in the sample, but time fields is zero.
I'm use last version of library (v0.2.8)
https://play.golang.org/p/INvrWLUd6BD
package main
import (
"github.com/jinzhu/copier"
)
func main() {
type Basic struct {
ID int
Name string
Addr string
}
type S struct {
Basic
Level int
}
s1 := S{}
var s2 S
copier.Copy(&s2, s1)
}
Crashed with nested struct. seemed cause by copier.go+193.
if f, ok := dest.Type().FieldByName(name); ok {
for idx, x := range f.Index {
destFieldKind := dest.Field(x).Kind()
as mentioned by: https://golang.org/pkg/reflect/#StructField
" Index []int // index sequence for Type.FieldByIndex ", the index can't used by dest.Field(x)
At the moment I am unable to copy struct A to struct B.
It does not copy because this check: fromField.Type().AssignableTo(toField.Type()) on line 73 returns false. It is false because fromField type is *string and toField type is string.
Is it possible to copy these two kind of structs?
type A struct {
Title *string
Description *string
Status *bool
}
type B struct {
Title string
Description string
Status bool
}
Can you please say if there are any problem when field name on on Struct is Capital, and other (same name) starts with (small) lowercase letter.
Also, what happens with embedded fields....do they get copied too??
Can we have non empty values copying functionality from one struct to another. Basically it should check for zero values in the source struct, and assign to destination only when it is not empty.
Does not make copy of map.
Example:
https://play.golang.org/p/C3nwT2W9BNs
I was trying to use the copier to copy a struct but isn't working for me. Following is the code:
https://goplay.space/#ARoaaKRtM2K
type Cat struct {
age int
name string
}
func main() {
firstCat := Cat{7, "Wilson"}
secondCat := Cat{}
copier.Copy(&secondCat, &firstCat)
fmt.Println(firstCat)
fmt.Println(secondCat)
}
I expect the output to print {7, "Wilson"} two times but it prints {7, "Wilson"} {0 }.
https://play.golang.org/p/bONC5Pfw0V8
Running this program produces an error (expected none):
panic: reflect: Field index out of range
goroutine 1 [running]:
reflect.Value.Field(0x5e0620, 0xc0001b5c00, 0x199, 0x3, 0x5e5a00, 0xc0001b5c00, 0x199)
/usr/local/go-faketime/src/reflect/value.go:854 +0xd9
github.com/jinzhu/copier.copier(0x5b7f40, 0xc0001b5c00, 0x5b7f40, 0xc0001b5b90, 0x0, 0x5d39a0, 0xc000113e01)
/tmp/gopath536822222/pkg/mod/github.com/jinzhu/[email protected]/copier.go:196 +0x17cd
github.com/jinzhu/copier.Copy(...)
/tmp/gopath536822222/pkg/mod/github.com/jinzhu/[email protected]/copier.go:35
main.main()
/tmp/sandbox082636651/prog.go:29 +0x1ab
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.