Unmarshalling JSON data into a Go struct can be a straightforward task. However, when dealing with JSON documents that contain dynamic data structures, where the type of a field can vary, the process can become more complex. This article explores a solution to this challenge without introducing generic placeholder fields.
Consider the following JSON spec:
{ "some_data": "foo", "dynamic_field": { "type": "A", "name": "Johnny" }, "other_data": "bar" }
{ "some_data": "foo", "dynamic_field": { "type": "B", "address": "Somewhere" }, "other_data": "bar" }
Both JSON documents should be unmarshalled into the same Go struct:
type BigStruct struct { SomeData string `json:"some_data"` DynamicField Something `json:"dynamic_field"` OtherData string `json:"other_data"` }
The key question is: how to create the Something type and implement the unmarshalling logic?
The solution involves creating an interface for the Something type:
type Something interface { GetType() string }
Next, define specific struct types that implement the Something interface:
type BaseDynamicType struct { Type string `json:"type"` } type DynamicTypeA struct { BaseDynamicType Name string `json:"name"` } type DynamicTypeB struct { BaseDynamicType Address string `json:"address"` }
The DynamicType interface method allows the JSON data to be unmarshalled into the appropriate structure:
func (d *DynamicType) UnmarshalJSON(data []byte) error { var typ struct { Type string `json:"type"` } if err := json.Unmarshal(data, &typ); err != nil { return err } switch typ.Type { case "A": d.Value = new(TypeA) case "B": d.Value = new(TypeB) } return json.Unmarshal(data, d.Value) }
This method inspects the JSON data and creates an instance of TypeA or TypeB as needed.
Finally, implement the UnmarshalJSON method on the BigStruct type:
func (b *BigStruct) UnmarshalJSON(data []byte) error { var tmp BigStruct // avoids infinite recursion return json.Unmarshal(data, &tmp) }
This method uses a temporary BigStruct type to avoid recursion and allows the dynamic field to be unmarshalled using the appropriate DynamicType type based on the type field in the JSON data.
This solution provides a clean and efficient way to unmarshal dynamic JSON data without the need for additional generic placeholder fields. By employing an interface and implementing custom UnmarshalJSON methods, the Go struct can adapt to the dynamic data structure in the JSON input.
The above is the detailed content of How to Unmarshal Dynamic JSON in Go without Generic Placeholder Fields?. For more information, please follow other related articles on the PHP Chinese website!