marshal.go

  1// Copyright (c) Microsoft Corporation.
  2// Licensed under the MIT license.
  3
  4package json
  5
  6import (
  7	"bytes"
  8	"encoding/json"
  9	"fmt"
 10	"reflect"
 11	"unicode"
 12)
 13
 14// marshalStruct takes in i, which must be a *struct or struct and marshals its content
 15// as JSON into buff (sometimes with writes to buff directly, sometimes via enc).
 16// This call is recursive for all fields of *struct or struct type.
 17func marshalStruct(v reflect.Value, buff *bytes.Buffer, enc *json.Encoder) error {
 18	if v.Kind() == reflect.Ptr {
 19		v = v.Elem()
 20	}
 21	// We only care about custom Marshalling a struct.
 22	if v.Kind() != reflect.Struct {
 23		return fmt.Errorf("bug: marshal() received a non *struct or struct, received type %T", v.Interface())
 24	}
 25
 26	if hasMarshalJSON(v) {
 27		b, err := callMarshalJSON(v)
 28		if err != nil {
 29			return err
 30		}
 31		buff.Write(b)
 32		return nil
 33	}
 34
 35	t := v.Type()
 36
 37	// If it has an AdditionalFields field make sure its the right type.
 38	f := v.FieldByName(addField)
 39	if f.Kind() != reflect.Invalid {
 40		if f.Kind() != reflect.Map {
 41			return fmt.Errorf("type %T has field 'AdditionalFields' that is not a map[string]interface{}", v.Interface())
 42		}
 43		if !f.Type().AssignableTo(mapStrInterType) {
 44			return fmt.Errorf("type %T has field 'AdditionalFields' that is not a map[string]interface{}", v.Interface())
 45		}
 46	}
 47
 48	translator, err := findFields(v)
 49	if err != nil {
 50		return err
 51	}
 52
 53	buff.WriteByte(leftBrace)
 54	for x := 0; x < v.NumField(); x++ {
 55		field := v.Field(x)
 56
 57		// We don't access private fields.
 58		if unicode.IsLower(rune(t.Field(x).Name[0])) {
 59			continue
 60		}
 61
 62		if t.Field(x).Name == addField {
 63			if v.Field(x).Len() > 0 {
 64				if err := writeAddFields(field.Interface(), buff, enc); err != nil {
 65					return err
 66				}
 67				buff.WriteByte(comma)
 68			}
 69			continue
 70		}
 71
 72		// If they have omitempty set, we don't write out the field if
 73		// it is the zero value.
 74		if hasOmitEmpty(t.Field(x).Tag.Get("json")) {
 75			if v.Field(x).IsZero() {
 76				continue
 77			}
 78		}
 79
 80		// Write out the field name part.
 81		jsonName := translator.jsonName(t.Field(x).Name)
 82		buff.WriteString(fmt.Sprintf("%q:", jsonName))
 83
 84		if field.Kind() == reflect.Ptr {
 85			field = field.Elem()
 86		}
 87
 88		if err := marshalStructField(field, buff, enc); err != nil {
 89			return err
 90		}
 91	}
 92
 93	buff.Truncate(buff.Len() - 1) // Remove final comma
 94	buff.WriteByte(rightBrace)
 95
 96	return nil
 97}
 98
 99func marshalStructField(field reflect.Value, buff *bytes.Buffer, enc *json.Encoder) error {
100	// Determine if we need a trailing comma.
101	defer buff.WriteByte(comma)
102
103	switch field.Kind() {
104	// If it was a *struct or struct, we need to recursively all marshal().
105	case reflect.Struct:
106		if field.CanAddr() {
107			field = field.Addr()
108		}
109		return marshalStruct(field, buff, enc)
110	case reflect.Map:
111		return marshalMap(field, buff, enc)
112	case reflect.Slice:
113		return marshalSlice(field, buff, enc)
114	}
115
116	// It is just a basic type, so encode it.
117	if err := enc.Encode(field.Interface()); err != nil {
118		return err
119	}
120	buff.Truncate(buff.Len() - 1) // Remove Encode() added \n
121
122	return nil
123}
124
125func marshalMap(v reflect.Value, buff *bytes.Buffer, enc *json.Encoder) error {
126	if v.Kind() != reflect.Map {
127		return fmt.Errorf("bug: marshalMap() called on %T", v.Interface())
128	}
129	if v.Len() == 0 {
130		buff.WriteByte(leftBrace)
131		buff.WriteByte(rightBrace)
132		return nil
133	}
134	encoder := mapEncode{m: v, buff: buff, enc: enc}
135	return encoder.run()
136}
137
138type mapEncode struct {
139	m    reflect.Value
140	buff *bytes.Buffer
141	enc  *json.Encoder
142
143	valueBaseType reflect.Type
144}
145
146// run runs our encoder state machine.
147func (m *mapEncode) run() error {
148	var state = m.start
149	var err error
150	for {
151		state, err = state()
152		if err != nil {
153			return err
154		}
155		if state == nil {
156			return nil
157		}
158	}
159}
160
161func (m *mapEncode) start() (stateFn, error) {
162	if hasMarshalJSON(m.m) {
163		b, err := callMarshalJSON(m.m)
164		if err != nil {
165			return nil, err
166		}
167		m.buff.Write(b)
168		return nil, nil
169	}
170
171	valueBaseType := m.m.Type().Elem()
172	if valueBaseType.Kind() == reflect.Ptr {
173		valueBaseType = valueBaseType.Elem()
174	}
175	m.valueBaseType = valueBaseType
176
177	switch valueBaseType.Kind() {
178	case reflect.Ptr:
179		return nil, fmt.Errorf("Marshal does not support **<type> or *<reference>")
180	case reflect.Struct, reflect.Map, reflect.Slice:
181		return m.encode, nil
182	}
183
184	// If the map value doesn't have a struct/map/slice, just Encode() it.
185	if err := m.enc.Encode(m.m.Interface()); err != nil {
186		return nil, err
187	}
188	m.buff.Truncate(m.buff.Len() - 1) // Remove Encode() added \n
189	return nil, nil
190}
191
192func (m *mapEncode) encode() (stateFn, error) {
193	m.buff.WriteByte(leftBrace)
194
195	iter := m.m.MapRange()
196	for iter.Next() {
197		// Write the key.
198		k := iter.Key()
199		m.buff.WriteString(fmt.Sprintf("%q:", k.String()))
200
201		v := iter.Value()
202		switch m.valueBaseType.Kind() {
203		case reflect.Struct:
204			if v.CanAddr() {
205				v = v.Addr()
206			}
207			if err := marshalStruct(v, m.buff, m.enc); err != nil {
208				return nil, err
209			}
210		case reflect.Map:
211			if err := marshalMap(v, m.buff, m.enc); err != nil {
212				return nil, err
213			}
214		case reflect.Slice:
215			if err := marshalSlice(v, m.buff, m.enc); err != nil {
216				return nil, err
217			}
218		default:
219			panic(fmt.Sprintf("critical bug: mapEncode.encode() called with value base type: %v", m.valueBaseType.Kind()))
220		}
221		m.buff.WriteByte(comma)
222	}
223	m.buff.Truncate(m.buff.Len() - 1) // Remove final comma
224	m.buff.WriteByte(rightBrace)
225
226	return nil, nil
227}
228
229func marshalSlice(v reflect.Value, buff *bytes.Buffer, enc *json.Encoder) error {
230	if v.Kind() != reflect.Slice {
231		return fmt.Errorf("bug: marshalSlice() called on %T", v.Interface())
232	}
233	if v.Len() == 0 {
234		buff.WriteByte(leftParen)
235		buff.WriteByte(rightParen)
236		return nil
237	}
238	encoder := sliceEncode{s: v, buff: buff, enc: enc}
239	return encoder.run()
240}
241
242type sliceEncode struct {
243	s    reflect.Value
244	buff *bytes.Buffer
245	enc  *json.Encoder
246
247	valueBaseType reflect.Type
248}
249
250// run runs our encoder state machine.
251func (s *sliceEncode) run() error {
252	var state = s.start
253	var err error
254	for {
255		state, err = state()
256		if err != nil {
257			return err
258		}
259		if state == nil {
260			return nil
261		}
262	}
263}
264
265func (s *sliceEncode) start() (stateFn, error) {
266	if hasMarshalJSON(s.s) {
267		b, err := callMarshalJSON(s.s)
268		if err != nil {
269			return nil, err
270		}
271		s.buff.Write(b)
272		return nil, nil
273	}
274
275	valueBaseType := s.s.Type().Elem()
276	if valueBaseType.Kind() == reflect.Ptr {
277		valueBaseType = valueBaseType.Elem()
278	}
279	s.valueBaseType = valueBaseType
280
281	switch valueBaseType.Kind() {
282	case reflect.Ptr:
283		return nil, fmt.Errorf("Marshal does not support **<type> or *<reference>")
284	case reflect.Struct, reflect.Map, reflect.Slice:
285		return s.encode, nil
286	}
287
288	// If the map value doesn't have a struct/map/slice, just Encode() it.
289	if err := s.enc.Encode(s.s.Interface()); err != nil {
290		return nil, err
291	}
292	s.buff.Truncate(s.buff.Len() - 1) // Remove Encode added \n
293
294	return nil, nil
295}
296
297func (s *sliceEncode) encode() (stateFn, error) {
298	s.buff.WriteByte(leftParen)
299	for i := 0; i < s.s.Len(); i++ {
300		v := s.s.Index(i)
301		switch s.valueBaseType.Kind() {
302		case reflect.Struct:
303			if v.CanAddr() {
304				v = v.Addr()
305			}
306			if err := marshalStruct(v, s.buff, s.enc); err != nil {
307				return nil, err
308			}
309		case reflect.Map:
310			if err := marshalMap(v, s.buff, s.enc); err != nil {
311				return nil, err
312			}
313		case reflect.Slice:
314			if err := marshalSlice(v, s.buff, s.enc); err != nil {
315				return nil, err
316			}
317		default:
318			panic(fmt.Sprintf("critical bug: mapEncode.encode() called with value base type: %v", s.valueBaseType.Kind()))
319		}
320		s.buff.WriteByte(comma)
321	}
322	s.buff.Truncate(s.buff.Len() - 1) // Remove final comma
323	s.buff.WriteByte(rightParen)
324	return nil, nil
325}
326
327// writeAddFields writes the AdditionalFields struct field out to JSON as field
328// values. i must be a map[string]interface{} or this will panic.
329func writeAddFields(i interface{}, buff *bytes.Buffer, enc *json.Encoder) error {
330	m := i.(map[string]interface{})
331
332	x := 0
333	for k, v := range m {
334		buff.WriteString(fmt.Sprintf("%q:", k))
335		if err := enc.Encode(v); err != nil {
336			return err
337		}
338		buff.Truncate(buff.Len() - 1) // Remove Encode() added \n
339
340		if x+1 != len(m) {
341			buff.WriteByte(comma)
342		}
343		x++
344	}
345	return nil
346}