'Unmarshal to custom interface
The usual approach for unmarshalling is like this:
atmosphereMap := make(map[string]interface{})
err := json.Unmarshal(bytes, &atmosphereMap)
But how to unmarshal json
data to custom interface:
type CustomInterface interface {
G() float64
}
atmosphereMap := make(map[string]CustomInterface)
err := json.Unmarshal(bytes, &atmosphereMap)
The second way gives me an error:
panic: json: cannot unmarshal object into Go value of type main.CustomInterface
How to do it correctly?
Solution 1:[1]
To unmarshal into a set of types, which all implement a common interface, you can implement the json.Unmarshaler
interface on the parent type, the map[string]CustomInterface
in your case:
type CustomInterfaceMap map[string]CustomInterface
func (m CustomInterfaceMap) UnmarshalJSON(b []byte) error {
data := make(map[string]json.RawMessage)
if err := json.Unmarshal(b, &data); err != nil {
return err
}
for k, v := range data {
var dst CustomInterface
// populate dst with an instance of the actual type you want to unmarshal into
if _, err := strconv.Atoi(string(v)); err == nil {
dst = &CustomImplementationInt{} // notice the dereference
} else {
dst = &CustomImplementationFloat{}
}
if err := json.Unmarshal(v, dst); err != nil {
return err
}
m[k] = dst
}
return nil
}
For a full example, see this playground. Make sure you unmarshal into a CustomInterfaceMap
, not map[string]CustomInterface
, otherwise the custom UnmarshalJSON
method will not be called.
json.RawMessage
is a useful type, which is just a raw encoded JSON value, meaning it is a simple []byte
, into which the JSON is stored in unparsed form.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Leon |