package main
import (
"encoding/json"
"fmt"
)
type RawJson struct {
RawMessage []byte
}
func (r *RawJson) MarshalJSON() ([]byte, error) {
fmt.Println("Marshal Raw")
return r.RawMessage, nil
}
func (r *RawJson) UnmarshalJSON(d []byte) error {
fmt.Println("Unmarshal Raw")
r.RawMessage = d
return nil
}
type Test1 struct {
Sdsdsdsd string `json:"sdsdsdsd"`
Name string `json:"name"`
}
func (r *Test1) MarshalJSON() ([]byte, error) {
fmt.Println("Marshal Test1")
type Alias Test1
aux := (*Alias)(r)
return json.Marshal(&aux)
}
func (r *Test1) UnmarshalJSON(d []byte) error {
fmt.Println("Unmarshal Test1")
type Alias Test1
aux := (*Alias)(r)
return json.Unmarshal(d, aux)
}
type Test struct {
Test1
RawJson RawJson `json:"embeded"`
}
var testJson = `{
"name":"testtest",
"embeded":{
"test":1,
"xxx":1,
"yyy":[1,2,4,5]
},
"sdsdsdsd" : "sdsd"
}`
func main() {
t := &Test{}
json.Unmarshal([]byte(testJson), &t)
fmt.Printf("%v \n", t.Sdsdsdsd)
b, _ := json.Marshal(t)
fmt.Println(string(b))
}
If you have custom unmarshel for both types Test1 and RawJson - only one will be cold (unmarsheler for Test1 ) , but when we delete custom unmarsheler for Test1 Raw custom unmarsheler starts working
By embedding Test1 in Test, Test1.UnmashalJSON is promoted to be Test.UnmarshalJSON. Because of this promotion, Test fulfills json.Unmarshaler, which causes json.Unmarshal to assume that Test knows how to unmarshal itself. Thus json.Unmarshal only calls Test.Unmarshal (i.e., Test1.Unmarshal).
Implement Test.UnmarshalJSONand Test.MarshalJSON. This is a bit annoying because the contents of Test1 and Test.RawJson are at the same level in testJson. This can be handled by creating an anonymous struct that has the fields in Test that aren’t in Test1. Here is a working example for unmarshal: https://play.golang.org/p/u6FA4Ktu-A (line 48). Marshal should work in a similar way.
Also, check your errors. Following http://pocketgophers.com/error-checking-while-prototyping/ requires little thinking and lets you see when errors occur. Using log.SetFlags(log.Lshortfile) along with log.Print (instead of fmt.Print) also gives line numbers to help find and give context to debugging output.