Sometimes you want to perform some extra validatoon logic in unmarshaling json, or you want to override some types. Here's one way to do it
You want to modify some fields, perform some extra calcs but the json unmarshaling bits remain the same?
You shadow the type, losing its methods (UnmarshalJSON), use the standard unmarshaling logic on it, then copy the data back and perform your modifications.
No need for awkward MyInt
s in your struct
1package main
2
3import (
4 "encoding/json"
5 "fmt"
6)
7
8func main() {
9 j := []byte(`{"int": -5, "string": "foobar"}`)
10
11 type PlainS S
12
13 var plainS PlainS
14 _ = json.Unmarshal(j, &plainS)
15 fmt.Println(plainS) //{-5 0 foobar}
16
17 var s S
18 _ = json.Unmarshal(j, &s)
19 fmt.Println(s) // {1 -50 foobar}
20
21}
22
23type S struct {
24 Int int
25 calculatedInt int
26 String string
27}
28
29func (s *S) UnmarshalJSON(b []byte) error {
30 type S2 S
31 var s2 S2
32 err := json.Unmarshal(b, &s2)
33 if err != nil {
34 return err
35 }
36
37 // perform modifications
38 s2.calculatedInt = s2.Int * 10
39 if s2.Int < 0 {
40 s2.Int = 1
41 }
42 *s = S(s2)
43 return nil
44}
Sometimes you just need to override some unmarshaling logic
for some fields
but you can't or don't have access to add UnmarshalJSON
to the types.
You shadow the type, you then create a new type embedding the shadowed type with the overrides you want.
1package main
2
3import (
4 "encoding/json"
5 "fmt"
6)
7
8func main() {
9 j := []byte(`{"int": 5, "string": "foobar"}`)
10
11 type PlainS S
12
13 var plainS PlainS
14 _ = json.Unmarshal(j, &plainS)
15 fmt.Println(plainS) //{ foobar}
16
17 var s S
18 _ = json.Unmarshal(j, &s)
19 fmt.Println(s) // {five foobar}
20
21}
22
23type S struct {
24 Int string
25 String string
26}
27
28func (s *S) UnmarshalJSON(b []byte) error {
29 type S2 S
30 type S3 struct {
31 S2
32 Int int
33 }
34 var s3 S3
35 err := json.Unmarshal(b, &s3)
36 if err != nil {
37 return err
38 }
39
40 // perform type convs
41 if s3.Int == 5 {
42 s3.S2.Int = "five"
43 }
44 *s = S(s3.S2)
45 return nil
46}