Strange behaviour when Unmarshalling into struct in Go
up vote
1
down vote
favorite
I'm developing a tool that can be implemented to simplify the process of creating simple CRUD operations/endpoints. Since my endpoints don't know what kind of struct they'll be receiving, I've created an interface that users can implement, and return an empty object to be filled.
type ItemFactory interface {
GenerateEmptyItem() interface{}
}
And the users would implement something like:
type Test struct {
TestString string `json:"testString"`
TestInt int `json:"testInt"`
TestBool bool `json:"testBool"`
}
func (t Test) GenerateEmptyItem() interface{} {
return Test{}
}
When the Test object gets created, its type is "Test", even though the func returned an interface{}. However, as soon as I try to unmarshal some json of the same format into it, it strips it of its type, and becomes of type "map[string]interface {}".
item := h.ItemFactory.GenerateEmptyItem()
//Prints "Test"
fmt.Printf("%Tn", item)
fmt.Println(reflect.TypeOf(item))
err := ConvertRequestBodyIntoObject(r, &item)
if err != nil {...}
//Prints "map[string]interface {}"
fmt.Printf("%Tn", item)
Func that unmarshalls item:
func ConvertRequestBodyIntoObject(request *http.Request, object interface{}) error {
body, err := ioutil.ReadAll(request.Body)
if err != nil {
return err
}
// Unmarshal body into request object
err = json.Unmarshal(body, object)
if err != nil {
return err
}
return nil
}
Any suggestions as to why this happens, or how I can work around it?
Thanks
go unmarshalling
add a comment |
up vote
1
down vote
favorite
I'm developing a tool that can be implemented to simplify the process of creating simple CRUD operations/endpoints. Since my endpoints don't know what kind of struct they'll be receiving, I've created an interface that users can implement, and return an empty object to be filled.
type ItemFactory interface {
GenerateEmptyItem() interface{}
}
And the users would implement something like:
type Test struct {
TestString string `json:"testString"`
TestInt int `json:"testInt"`
TestBool bool `json:"testBool"`
}
func (t Test) GenerateEmptyItem() interface{} {
return Test{}
}
When the Test object gets created, its type is "Test", even though the func returned an interface{}. However, as soon as I try to unmarshal some json of the same format into it, it strips it of its type, and becomes of type "map[string]interface {}".
item := h.ItemFactory.GenerateEmptyItem()
//Prints "Test"
fmt.Printf("%Tn", item)
fmt.Println(reflect.TypeOf(item))
err := ConvertRequestBodyIntoObject(r, &item)
if err != nil {...}
//Prints "map[string]interface {}"
fmt.Printf("%Tn", item)
Func that unmarshalls item:
func ConvertRequestBodyIntoObject(request *http.Request, object interface{}) error {
body, err := ioutil.ReadAll(request.Body)
if err != nil {
return err
}
// Unmarshal body into request object
err = json.Unmarshal(body, object)
if err != nil {
return err
}
return nil
}
Any suggestions as to why this happens, or how I can work around it?
Thanks
go unmarshalling
Added the code.
– robbieperry22
Nov 9 at 1:27
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I'm developing a tool that can be implemented to simplify the process of creating simple CRUD operations/endpoints. Since my endpoints don't know what kind of struct they'll be receiving, I've created an interface that users can implement, and return an empty object to be filled.
type ItemFactory interface {
GenerateEmptyItem() interface{}
}
And the users would implement something like:
type Test struct {
TestString string `json:"testString"`
TestInt int `json:"testInt"`
TestBool bool `json:"testBool"`
}
func (t Test) GenerateEmptyItem() interface{} {
return Test{}
}
When the Test object gets created, its type is "Test", even though the func returned an interface{}. However, as soon as I try to unmarshal some json of the same format into it, it strips it of its type, and becomes of type "map[string]interface {}".
item := h.ItemFactory.GenerateEmptyItem()
//Prints "Test"
fmt.Printf("%Tn", item)
fmt.Println(reflect.TypeOf(item))
err := ConvertRequestBodyIntoObject(r, &item)
if err != nil {...}
//Prints "map[string]interface {}"
fmt.Printf("%Tn", item)
Func that unmarshalls item:
func ConvertRequestBodyIntoObject(request *http.Request, object interface{}) error {
body, err := ioutil.ReadAll(request.Body)
if err != nil {
return err
}
// Unmarshal body into request object
err = json.Unmarshal(body, object)
if err != nil {
return err
}
return nil
}
Any suggestions as to why this happens, or how I can work around it?
Thanks
go unmarshalling
I'm developing a tool that can be implemented to simplify the process of creating simple CRUD operations/endpoints. Since my endpoints don't know what kind of struct they'll be receiving, I've created an interface that users can implement, and return an empty object to be filled.
type ItemFactory interface {
GenerateEmptyItem() interface{}
}
And the users would implement something like:
type Test struct {
TestString string `json:"testString"`
TestInt int `json:"testInt"`
TestBool bool `json:"testBool"`
}
func (t Test) GenerateEmptyItem() interface{} {
return Test{}
}
When the Test object gets created, its type is "Test", even though the func returned an interface{}. However, as soon as I try to unmarshal some json of the same format into it, it strips it of its type, and becomes of type "map[string]interface {}".
item := h.ItemFactory.GenerateEmptyItem()
//Prints "Test"
fmt.Printf("%Tn", item)
fmt.Println(reflect.TypeOf(item))
err := ConvertRequestBodyIntoObject(r, &item)
if err != nil {...}
//Prints "map[string]interface {}"
fmt.Printf("%Tn", item)
Func that unmarshalls item:
func ConvertRequestBodyIntoObject(request *http.Request, object interface{}) error {
body, err := ioutil.ReadAll(request.Body)
if err != nil {
return err
}
// Unmarshal body into request object
err = json.Unmarshal(body, object)
if err != nil {
return err
}
return nil
}
Any suggestions as to why this happens, or how I can work around it?
Thanks
go unmarshalling
go unmarshalling
edited Nov 9 at 1:26
asked Nov 8 at 23:57
robbieperry22
115
115
Added the code.
– robbieperry22
Nov 9 at 1:27
add a comment |
Added the code.
– robbieperry22
Nov 9 at 1:27
Added the code.
– robbieperry22
Nov 9 at 1:27
Added the code.
– robbieperry22
Nov 9 at 1:27
add a comment |
1 Answer
1
active
oldest
votes
up vote
2
down vote
accepted
Your question lacks an example showing this behavior so I'm just guessing this is what is happening.
func Generate() interface{} {
return Test{}
}
func GeneratePointer() interface{} {
return &Test{}
}
func main() {
vi := Generate()
json.Unmarshal(byte(`{}`), &vi)
fmt.Printf("Generate Type: %Tn", vi)
vp := GeneratePointer()
json.Unmarshal(byte(`{}`), vp)
fmt.Printf("GenerateP Type: %Tn", vp)
}
Which outputs:
Generate Type: map[string]interface {}
GenerateP Type: *main.Test
I suggest you return a pointer in GenerateEmptyItem()
instead of the actual struct value which is demonstrated in the GenerateP()
example.
Playground Example
I can see you already put the example code. Still, the answer remains - return a pointer to your struct from the factory.
– ssemilla
Nov 9 at 1:33
Thanks so much for the response, this solved the issue. Why is it, that it behaves like that when it's not a pointer?
– robbieperry22
Nov 9 at 1:50
@robbieperry22 it can be a little confusing, but think of it this way: when you return something as an interface, it's basically "wrapped" in the interface - the interface value contains the real value. So if you take a pointer to a real value, then wrap it in an interface, you get the expected behavior. If you take a real value, wrap it in an interface, then take a pointer to that, you've now got a pointer to a wrapper containing a value instead of a pointer to a value.
– Adrian
Nov 9 at 14:42
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
Your question lacks an example showing this behavior so I'm just guessing this is what is happening.
func Generate() interface{} {
return Test{}
}
func GeneratePointer() interface{} {
return &Test{}
}
func main() {
vi := Generate()
json.Unmarshal(byte(`{}`), &vi)
fmt.Printf("Generate Type: %Tn", vi)
vp := GeneratePointer()
json.Unmarshal(byte(`{}`), vp)
fmt.Printf("GenerateP Type: %Tn", vp)
}
Which outputs:
Generate Type: map[string]interface {}
GenerateP Type: *main.Test
I suggest you return a pointer in GenerateEmptyItem()
instead of the actual struct value which is demonstrated in the GenerateP()
example.
Playground Example
I can see you already put the example code. Still, the answer remains - return a pointer to your struct from the factory.
– ssemilla
Nov 9 at 1:33
Thanks so much for the response, this solved the issue. Why is it, that it behaves like that when it's not a pointer?
– robbieperry22
Nov 9 at 1:50
@robbieperry22 it can be a little confusing, but think of it this way: when you return something as an interface, it's basically "wrapped" in the interface - the interface value contains the real value. So if you take a pointer to a real value, then wrap it in an interface, you get the expected behavior. If you take a real value, wrap it in an interface, then take a pointer to that, you've now got a pointer to a wrapper containing a value instead of a pointer to a value.
– Adrian
Nov 9 at 14:42
add a comment |
up vote
2
down vote
accepted
Your question lacks an example showing this behavior so I'm just guessing this is what is happening.
func Generate() interface{} {
return Test{}
}
func GeneratePointer() interface{} {
return &Test{}
}
func main() {
vi := Generate()
json.Unmarshal(byte(`{}`), &vi)
fmt.Printf("Generate Type: %Tn", vi)
vp := GeneratePointer()
json.Unmarshal(byte(`{}`), vp)
fmt.Printf("GenerateP Type: %Tn", vp)
}
Which outputs:
Generate Type: map[string]interface {}
GenerateP Type: *main.Test
I suggest you return a pointer in GenerateEmptyItem()
instead of the actual struct value which is demonstrated in the GenerateP()
example.
Playground Example
I can see you already put the example code. Still, the answer remains - return a pointer to your struct from the factory.
– ssemilla
Nov 9 at 1:33
Thanks so much for the response, this solved the issue. Why is it, that it behaves like that when it's not a pointer?
– robbieperry22
Nov 9 at 1:50
@robbieperry22 it can be a little confusing, but think of it this way: when you return something as an interface, it's basically "wrapped" in the interface - the interface value contains the real value. So if you take a pointer to a real value, then wrap it in an interface, you get the expected behavior. If you take a real value, wrap it in an interface, then take a pointer to that, you've now got a pointer to a wrapper containing a value instead of a pointer to a value.
– Adrian
Nov 9 at 14:42
add a comment |
up vote
2
down vote
accepted
up vote
2
down vote
accepted
Your question lacks an example showing this behavior so I'm just guessing this is what is happening.
func Generate() interface{} {
return Test{}
}
func GeneratePointer() interface{} {
return &Test{}
}
func main() {
vi := Generate()
json.Unmarshal(byte(`{}`), &vi)
fmt.Printf("Generate Type: %Tn", vi)
vp := GeneratePointer()
json.Unmarshal(byte(`{}`), vp)
fmt.Printf("GenerateP Type: %Tn", vp)
}
Which outputs:
Generate Type: map[string]interface {}
GenerateP Type: *main.Test
I suggest you return a pointer in GenerateEmptyItem()
instead of the actual struct value which is demonstrated in the GenerateP()
example.
Playground Example
Your question lacks an example showing this behavior so I'm just guessing this is what is happening.
func Generate() interface{} {
return Test{}
}
func GeneratePointer() interface{} {
return &Test{}
}
func main() {
vi := Generate()
json.Unmarshal(byte(`{}`), &vi)
fmt.Printf("Generate Type: %Tn", vi)
vp := GeneratePointer()
json.Unmarshal(byte(`{}`), vp)
fmt.Printf("GenerateP Type: %Tn", vp)
}
Which outputs:
Generate Type: map[string]interface {}
GenerateP Type: *main.Test
I suggest you return a pointer in GenerateEmptyItem()
instead of the actual struct value which is demonstrated in the GenerateP()
example.
Playground Example
answered Nov 9 at 1:29
ssemilla
2,282421
2,282421
I can see you already put the example code. Still, the answer remains - return a pointer to your struct from the factory.
– ssemilla
Nov 9 at 1:33
Thanks so much for the response, this solved the issue. Why is it, that it behaves like that when it's not a pointer?
– robbieperry22
Nov 9 at 1:50
@robbieperry22 it can be a little confusing, but think of it this way: when you return something as an interface, it's basically "wrapped" in the interface - the interface value contains the real value. So if you take a pointer to a real value, then wrap it in an interface, you get the expected behavior. If you take a real value, wrap it in an interface, then take a pointer to that, you've now got a pointer to a wrapper containing a value instead of a pointer to a value.
– Adrian
Nov 9 at 14:42
add a comment |
I can see you already put the example code. Still, the answer remains - return a pointer to your struct from the factory.
– ssemilla
Nov 9 at 1:33
Thanks so much for the response, this solved the issue. Why is it, that it behaves like that when it's not a pointer?
– robbieperry22
Nov 9 at 1:50
@robbieperry22 it can be a little confusing, but think of it this way: when you return something as an interface, it's basically "wrapped" in the interface - the interface value contains the real value. So if you take a pointer to a real value, then wrap it in an interface, you get the expected behavior. If you take a real value, wrap it in an interface, then take a pointer to that, you've now got a pointer to a wrapper containing a value instead of a pointer to a value.
– Adrian
Nov 9 at 14:42
I can see you already put the example code. Still, the answer remains - return a pointer to your struct from the factory.
– ssemilla
Nov 9 at 1:33
I can see you already put the example code. Still, the answer remains - return a pointer to your struct from the factory.
– ssemilla
Nov 9 at 1:33
Thanks so much for the response, this solved the issue. Why is it, that it behaves like that when it's not a pointer?
– robbieperry22
Nov 9 at 1:50
Thanks so much for the response, this solved the issue. Why is it, that it behaves like that when it's not a pointer?
– robbieperry22
Nov 9 at 1:50
@robbieperry22 it can be a little confusing, but think of it this way: when you return something as an interface, it's basically "wrapped" in the interface - the interface value contains the real value. So if you take a pointer to a real value, then wrap it in an interface, you get the expected behavior. If you take a real value, wrap it in an interface, then take a pointer to that, you've now got a pointer to a wrapper containing a value instead of a pointer to a value.
– Adrian
Nov 9 at 14:42
@robbieperry22 it can be a little confusing, but think of it this way: when you return something as an interface, it's basically "wrapped" in the interface - the interface value contains the real value. So if you take a pointer to a real value, then wrap it in an interface, you get the expected behavior. If you take a real value, wrap it in an interface, then take a pointer to that, you've now got a pointer to a wrapper containing a value instead of a pointer to a value.
– Adrian
Nov 9 at 14:42
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53217910%2fstrange-behaviour-when-unmarshalling-into-struct-in-go%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Added the code.
– robbieperry22
Nov 9 at 1:27