Skip to content

Instantly share code, notes, and snippets.

@tkrajina
Last active February 2, 2017 20:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tkrajina/2a37daf381a783a43e5b801c6dbd7e58 to your computer and use it in GitHub Desktop.
Save tkrajina/2a37daf381a783a43e5b801c6dbd7e58 to your computer and use it in GitHub Desktop.
Unmarshal JSON to different structs (based on another field)
package main
import (
"encoding/json"
"fmt"
"sync"
)
type Something struct {
Aaa string `json:"aaa"`
}
type Person struct {
Type string `json:"type"`
RawValue *json.RawMessage `json:"raw"`
value interface{} `json:"-"`
unmarshalValueMutex sync.Mutex `json:"-"`
}
func (p *Person) Value() (interface{}, error) {
if p.RawValue == nil {
return p.value, nil
}
p.unmarshalValueMutex.Lock()
if p.RawValue != nil {
rawValue := p.RawValue
p.RawValue = nil
switch p.Type {
case "string":
p.value = ""
case "struct":
p.value = &Something{}
}
if err := json.Unmarshal([]byte(*rawValue), &p.value); err != nil {
return nil, err
}
}
p.unmarshalValueMutex.Unlock()
return p.value, nil
}
func (p *Person) MarshalJSON() ([]byte, error) {
rawData, err := json.Marshal(p.value)
if err != nil {
return nil, err
}
rawMessage := json.RawMessage(rawData)
p.RawValue = &rawMessage
return json.Marshal(*p) // Important, using p here would end in recursion
}
var _ json.Marshaler = (*Person)(nil)
func panicIfError(err error) {
if err != nil {
panic(err.Error())
}
}
func main() {
test(`{"type":"string","raw":"aaa"}`)
test(`{"type":"struct","raw":{"aaa": "bbb"}}`)
}
func test(jsonString string) {
p := Person{}
json.Unmarshal([]byte(jsonString), &p)
_, err := p.Value()
panicIfError(err)
fmt.Printf("value=%#v\n", p.value)
bytes, err := json.Marshal(&p)
panicIfError(err)
fmt.Println(string(bytes))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment