Lets think we have config file like: (I use json)
This is short syntax
{
"network": "test-network"
}
And long syntax
{
"network": {
"name": "test-network",
"description": "for testing purposes"
}
}
When reading this configurations we should give own decoder function to parse and write to the our object.
Before to do that lets check our example.
First create struct for long and short format and try unmarshal.
package main
import (
"encoding/json"
"fmt"
)
type NetworkDescription struct {
Name string `json:"name"`
Description string `json:"description"`
}
type NetworkLong struct {
Network NetworkDescription `json:"network"`
}
type NetworkShort struct {
Network string `json:"network"`
}
func main() {
networkLongTest1 := &NetworkLong{}
err := json.Unmarshal([]byte(`{"network":{"name":"foo","description":"bar"}}`), networkLongTest1)
fmt.Printf("%#v\nErr: %v", networkLongTest1, err)
networkLongTest2 := &NetworkLong{}
err = json.Unmarshal([]byte(`{"network":"foo"}`), networkLongTest2)
fmt.Printf("%#v\nErr: %v", networkLongTest2, err)
}
Result obviously give error in second try
$ go run main.go
&main.NetworkLong{Network:main.NetworkDescription{Name:"foo", Description:"bar"}}
Err: <nil>
&main.NetworkLong{Network:main.NetworkDescription{Name:"", Description:""}}
Err: json: cannot unmarshal string into Go struct field NetworkLong.network of type main.NetworkDescription
Good now we can use this error in our custom Unmarshaler's interface implementation.
I am using stdlib's json
to unmarshaller so Unmarshaler interface has one function UnmarshalJSON([]byte) error
We can create new struct type and use that one but I will just modify our NetworkLong
struct because I will turn short version to the long.
type NetworkLong struct {
Network NetworkDescription `json:"network"`
}
func (n *NetworkLong) UnmarshalJSON(b []byte) error {
// change type to don't use our custom unmarshal
type longFormat NetworkLong
nLong := &longFormat{}
err := json.Unmarshal(b, &nLong)
if err != nil {
nShort := &NetworkShort{}
err = json.Unmarshal(b, nShort)
if err != nil {
return err
}
n.Network = NetworkDescription{
Name: nShort.Network,
}
return nil
}
*n = NetworkLong(*nLong)
return nil
}
And our result is
&main.NetworkLong{Network:main.NetworkDescription{Name:"foo", Description:"bar"}}
Err: <nil>
&main.NetworkLong{Network:main.NetworkDescription{Name:"foo", Description:""}}
Err: <nil>
Check in the playground
Top comments (0)