marshal.go raw

   1  // Copyright (c) Microsoft Corporation.
   2  // Licensed under the MIT license.
   3  
   4  package json
   5  
   6  import (
   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.
  17  func 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  
  99  func 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  
 125  func 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  
 138  type 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.
 147  func (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  
 161  func (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  
 192  func (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  
 229  func 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  
 242  type 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.
 251  func (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  
 265  func (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  
 297  func (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.
 329  func 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  }
 347