The post describes how to unmarshal time.Duration
which is not supported by the default JSON unmarshaler, but the example can be used to unmarshal any custom type.
Here is the JSON we’re unmarshaling:
1
2
3
4
|
{
"addr": "https://example.com",
"timeout": "5s",
}
|
We’d like to convert the 5s
value to a time.Duration
value corresponding to 5 seconds and get the JSON to unmarshal in the following data structure:
1
2
3
4
|
type connection struct {
Addr string `json:"addr"`
Timeout time.Duration `json:"timeout"`
}
|
One way to do it is to implement the Unmarshaler interface and handle the conversion in our UnmarshalJSON function.
1
2
3
4
5
6
7
8
9
10
11
|
// Unmarshaler is the interface implemented by types
// that can unmarshal a JSON description of themselves.
// The input can be assumed to be a valid encoding of
// a JSON value. UnmarshalJSON must copy the JSON data
// if it wishes to retain the data after returning.
//
// By convention, to approximate the behavior of Unmarshal itself,
// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op.
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
|
Below is the complete example. We unmarshal the JSON into a temprary structure where 5s
is a standard string
. Then we convert the string to time.Duration vaue and set it in our structure.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package mypackage
import(
"json/encoding"
"time"
)
type connection struct {
Addr string `json:"addr"`
Timeout time.Duration `json:"timeout"`
}
func (c *connection) UmarshalJSON(data []byte) (err error) {
var tmp struct {
Addr string
Timeout string
}
if err = json.Unmarshal(data, &tmp); err != nil {
return err
}
c.Addr = tmp.Addr
c.Timeout, err = time.ParseDuration(tmp.Timeout)
return err
}
|