Then do two-staged decoding—exploiting the fact encoding/json
has a special type RawMessage
with the semantics "just save the sequence of bytes representing this value as is":
package main
import (
"encoding/json"
"fmt"
)
type message struct {
Type string `json:"type"`
Data json.RawMessage `json:"data"`
}
type A struct {
Foo string
Bar string
}
type B struct {
Quux int
Blorb []int
}
func decodeMessage(b []byte) (interface{}, error) {
var m message
err := json.Unmarshal(b, &m)
if err != nil {
return nil, err
}
switch m.Type {
case "a":
var a A
err = json.Unmarshal(m.Data, &a)
if err != nil {
return nil, err
}
return a, nil
case "b":
var b B
err = json.Unmarshal(m.Data, &b)
if err != nil {
return nil, err
}
return b, nil
}
return nil, fmt.Errorf("cannot handle type: %s", m.Type)
}
const msgA = `{
"type": "a",
"data": {
"Foo": "xyzzy",
"Bar": "r0xx0rz"
}
}`
const msgB = `{
"type": "b",
"data": {
"Quux": 42,
"Blorb": [1, 2, 3, 4]
}
}`
const msgX = `{
"type": "x",
"data": null
}`
func main() {
for _, s := range []string{msgA, msgB, msgX} {
d, err := decodeMessage([]byte(s))
fmt.Println(d, err)
}
}
Playground.
Another variant which is a bit different:
package main
import (
"encoding/json"
"fmt"
)
type message struct {
Type string `json:"type"`
Data json.RawMessage `json:"data"`
}
type A struct {
Foo string
Bar string
}
type B struct {
Quux int
Blorb []int
}
func decodeMessage(b []byte) (interface{}, error) {
var m message
err := json.Unmarshal(b, &m)
if err != nil {
return nil, err
}
var v interface{}
switch m.Type {
case "a":
v = &A{}
case "b":
v = &B{}
default:
return nil, fmt.Errorf("cannot handle type: %s", m.Type)
}
err = json.Unmarshal(m.Data, v)
if err != nil {
return nil, err
}
return v, nil
}
const msgA = `{
"type": "a",
"data": {
"Foo": "xyzzy",
"Bar": "r0xx0rz"
}
}`
const msgB = `{
"type": "b",
"data": {
"Quux": 42,
"Blorb": [1, 2, 3, 4]
}
}`
const msgX = `{
"type": "x",
"data": null
}`
func main() {
for _, s := range []string{msgA, msgB, msgX} {
d, err := decodeMessage([]byte(s))
fmt.Println(d, err)
}
}
Playground.