Reputation:
I need to specify a type for decoding JSON data in a flexible manner, meaning the type needs to be specified at runtime.
Consider this snippet: http://play.golang.org/p/F-Jy4ufMPz
s := `{"b":[{"x":9},{"x":4}]}`
var a struct {
B []interface{}
}
err := json.Unmarshal([]byte(s), &a)
if err != nil {
panic(err)
}
fmt.Println(a)
Which will produce {[map[x:9] map[x:4]]}
. I want to decode to an array of a specific (struct) type instead of []interface{}
, without specifying it at compile time.
Is that somehow possible without creating the array up front? (the number of returned items is unknown)
The only way I can think of right now is to encode the returned maps again later, and decode them to the specified type, which would create unnecessary processing overhead.
Upvotes: 4
Views: 1768
Reputation: 78065
If not specifying it at compile time, you still need to specify it somewhere.
If specified before the retrieval of the Json data, you can simply do a switch case, Unmarshalling it to your desired object.
If specified within the Json data, you can marshal the "flexible" part into a json.RawMessage
to process it after you've decided what type of struct is suitable:
package main
import (
"encoding/json"
"fmt"
)
var s = `{"type":"structx", "data":{"x":9,"xstring":"This is structX"}}`
type JsonStruct struct {
Type string
Data json.RawMessage
}
type StructX struct {
X float64
Xstring string
}
type StructY struct {
Y bool
}
func main() {
var a *JsonStruct
err := json.Unmarshal([]byte(s), &a)
if err != nil {
panic(err)
}
switch a.Type {
case "structx":
// We Unmashal the RawMessage part into a StructX
var s *StructX
json.Unmarshal([]byte(a.Data), &s)
if err != nil {
panic(err)
}
fmt.Println(s)
case "structy":
// Do the same but for structY
}
}
Upvotes: 5