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










share|improve this question
























  • Added the code.
    – robbieperry22
    Nov 9 at 1:27















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










share|improve this question
























  • Added the code.
    – robbieperry22
    Nov 9 at 1:27













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










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 9 at 1:26

























asked Nov 8 at 23:57









robbieperry22

115




115












  • 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




Added the code.
– robbieperry22
Nov 9 at 1:27












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






share|improve this answer





















  • 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











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















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

























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






share|improve this answer





















  • 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















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






share|improve this answer





















  • 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













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






share|improve this answer












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







share|improve this answer












share|improve this answer



share|improve this answer










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


















  • 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


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














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





















































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







Popular posts from this blog

Schultheiß

Verwaltungsgliederung Dänemarks

Liste der Kulturdenkmale in Wilsdruff