1 // Copyright (c) Microsoft Corporation.
2 // Licensed under the MIT license.
3 4 // Package json provide functions for marshalling an unmarshalling types to JSON. These functions are meant to
5 // be utilized inside of structs that implement json.Unmarshaler and json.Marshaler interfaces.
6 // This package provides the additional functionality of writing fields that are not in the struct when marshalling
7 // to a field called AdditionalFields if that field exists and is a map[string]interface{}.
8 // When marshalling, if the struct has all the same prerequisites, it will uses the keys in AdditionalFields as
9 // extra fields. This package uses encoding/json underneath.
10 package json
11 12 import (
13 "bytes"
14 "encoding/json"
15 "fmt"
16 "reflect"
17 "strings"
18 )
19 20 const addField = "AdditionalFields"
21 22 var (
23 leftBrace = []byte("{")[0]
24 rightBrace = []byte("}")[0]
25 comma = []byte(",")[0]
26 leftParen = []byte("[")[0]
27 rightParen = []byte("]")[0]
28 )
29 30 var mapStrInterType = reflect.TypeOf(map[string]interface{}{})
31 32 // stateFn defines a state machine function. This will be used in all state
33 // machines in this package.
34 type stateFn func() (stateFn, error)
35 36 // Marshal is used to marshal a type into its JSON representation. It
37 // wraps the stdlib calls in order to marshal a struct or *struct so
38 // that a field called "AdditionalFields" of type map[string]interface{}
39 // with "-" used inside struct tag `json:"-"` can be marshalled as if
40 // they were fields within the struct.
41 func Marshal(i interface{}) ([]byte, error) {
42 buff := bytes.Buffer{}
43 enc := json.NewEncoder(&buff)
44 enc.SetEscapeHTML(false)
45 enc.SetIndent("", "")
46 47 v := reflect.ValueOf(i)
48 if v.Kind() != reflect.Ptr && v.CanAddr() {
49 v = v.Addr()
50 }
51 err := marshalStruct(v, &buff, enc)
52 if err != nil {
53 return nil, err
54 }
55 return buff.Bytes(), nil
56 }
57 58 // Unmarshal unmarshals a []byte representing JSON into i, which must be a *struct. In addition, if the struct has
59 // a field called AdditionalFields of type map[string]interface{}, JSON data representing fields not in the struct
60 // will be written as key/value pairs to AdditionalFields.
61 func Unmarshal(b []byte, i interface{}) error {
62 if len(b) == 0 {
63 return nil
64 }
65 66 jdec := json.NewDecoder(bytes.NewBuffer(b))
67 jdec.UseNumber()
68 return unmarshalStruct(jdec, i)
69 }
70 71 // MarshalRaw marshals i into a json.RawMessage. If I cannot be marshalled,
72 // this will panic. This is exposed to help test AdditionalField values
73 // which are stored as json.RawMessage.
74 func MarshalRaw(i interface{}) json.RawMessage {
75 b, err := json.Marshal(i)
76 if err != nil {
77 panic(err)
78 }
79 return json.RawMessage(b)
80 }
81 82 // isDelim simply tests to see if a json.Token is a delimeter.
83 func isDelim(got json.Token) bool {
84 switch got.(type) {
85 case json.Delim:
86 return true
87 }
88 return false
89 }
90 91 // delimIs tests got to see if it is want.
92 func delimIs(got json.Token, want rune) bool {
93 switch v := got.(type) {
94 case json.Delim:
95 if v == json.Delim(want) {
96 return true
97 }
98 }
99 return false
100 }
101 102 // hasMarshalJSON will determine if the value or a pointer to this value has
103 // the MarshalJSON method.
104 func hasMarshalJSON(v reflect.Value) bool {
105 ok := false
106 if _, ok = v.Interface().(json.Marshaler); !ok {
107 var i any
108 if v.Kind() == reflect.Ptr {
109 i = v.Elem().Interface()
110 } else if v.CanAddr() {
111 i = v.Addr().Interface()
112 }
113 _, ok = i.(json.Marshaler)
114 }
115 return ok
116 }
117 118 // callMarshalJSON will call MarshalJSON() method on the value or a pointer to this value.
119 // This will panic if the method is not defined.
120 func callMarshalJSON(v reflect.Value) ([]byte, error) {
121 if marsh, ok := v.Interface().(json.Marshaler); ok {
122 return marsh.MarshalJSON()
123 }
124 125 if v.Kind() == reflect.Ptr {
126 if marsh, ok := v.Elem().Interface().(json.Marshaler); ok {
127 return marsh.MarshalJSON()
128 }
129 } else {
130 if v.CanAddr() {
131 if marsh, ok := v.Addr().Interface().(json.Marshaler); ok {
132 return marsh.MarshalJSON()
133 }
134 }
135 }
136 137 panic(fmt.Sprintf("callMarshalJSON called on type %T that does not have MarshalJSON defined", v.Interface()))
138 }
139 140 // hasUnmarshalJSON will determine if the value or a pointer to this value has
141 // the UnmarshalJSON method.
142 func hasUnmarshalJSON(v reflect.Value) bool {
143 // You can't unmarshal on a non-pointer type.
144 if v.Kind() != reflect.Ptr {
145 if !v.CanAddr() {
146 return false
147 }
148 v = v.Addr()
149 }
150 151 _, ok := v.Interface().(json.Unmarshaler)
152 return ok
153 }
154 155 // hasOmitEmpty indicates if the field has instructed us to not output
156 // the field if omitempty is set on the tag. tag is the string
157 // returned by reflect.StructField.Tag().Get().
158 func hasOmitEmpty(tag string) bool {
159 sl := strings.Split(tag, ",")
160 for _, str := range sl {
161 if str == "omitempty" {
162 return true
163 }
164 }
165 return false
166 }
167