build.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // Package jsonutil provides JSON serialization of AWS requests and responses.
  2. package jsonutil
  3. import (
  4. "bytes"
  5. "encoding/base64"
  6. "fmt"
  7. "reflect"
  8. "sort"
  9. "strconv"
  10. "time"
  11. "github.com/aws/aws-sdk-go/private/protocol"
  12. )
  13. var timeType = reflect.ValueOf(time.Time{}).Type()
  14. var byteSliceType = reflect.ValueOf([]byte{}).Type()
  15. // BuildJSON builds a JSON string for a given object v.
  16. func BuildJSON(v interface{}) ([]byte, error) {
  17. var buf bytes.Buffer
  18. err := buildAny(reflect.ValueOf(v), &buf, "")
  19. return buf.Bytes(), err
  20. }
  21. func buildAny(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
  22. value = reflect.Indirect(value)
  23. if !value.IsValid() {
  24. return nil
  25. }
  26. vtype := value.Type()
  27. t := tag.Get("type")
  28. if t == "" {
  29. switch vtype.Kind() {
  30. case reflect.Struct:
  31. // also it can't be a time object
  32. if value.Type() != timeType {
  33. t = "structure"
  34. }
  35. case reflect.Slice:
  36. // also it can't be a byte slice
  37. if _, ok := value.Interface().([]byte); !ok {
  38. t = "list"
  39. }
  40. case reflect.Map:
  41. t = "map"
  42. }
  43. }
  44. switch t {
  45. case "structure":
  46. if field, ok := vtype.FieldByName("_"); ok {
  47. tag = field.Tag
  48. }
  49. return buildStruct(value, buf, tag)
  50. case "list":
  51. return buildList(value, buf, tag)
  52. case "map":
  53. return buildMap(value, buf, tag)
  54. default:
  55. return buildScalar(value, buf, tag)
  56. }
  57. }
  58. func buildStruct(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
  59. if !value.IsValid() {
  60. return nil
  61. }
  62. // unwrap payloads
  63. if payload := tag.Get("payload"); payload != "" {
  64. field, _ := value.Type().FieldByName(payload)
  65. tag = field.Tag
  66. value = elemOf(value.FieldByName(payload))
  67. if !value.IsValid() {
  68. return nil
  69. }
  70. }
  71. buf.WriteByte('{')
  72. t := value.Type()
  73. first := true
  74. for i := 0; i < t.NumField(); i++ {
  75. member := value.Field(i)
  76. field := t.Field(i)
  77. if field.PkgPath != "" {
  78. continue // ignore unexported fields
  79. }
  80. if field.Tag.Get("json") == "-" {
  81. continue
  82. }
  83. if field.Tag.Get("location") != "" {
  84. continue // ignore non-body elements
  85. }
  86. if protocol.CanSetIdempotencyToken(member, field) {
  87. token := protocol.GetIdempotencyToken()
  88. member = reflect.ValueOf(&token)
  89. }
  90. if (member.Kind() == reflect.Ptr || member.Kind() == reflect.Slice || member.Kind() == reflect.Map) && member.IsNil() {
  91. continue // ignore unset fields
  92. }
  93. if first {
  94. first = false
  95. } else {
  96. buf.WriteByte(',')
  97. }
  98. // figure out what this field is called
  99. name := field.Name
  100. if locName := field.Tag.Get("locationName"); locName != "" {
  101. name = locName
  102. }
  103. writeString(name, buf)
  104. buf.WriteString(`:`)
  105. err := buildAny(member, buf, field.Tag)
  106. if err != nil {
  107. return err
  108. }
  109. }
  110. buf.WriteString("}")
  111. return nil
  112. }
  113. func buildList(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
  114. buf.WriteString("[")
  115. for i := 0; i < value.Len(); i++ {
  116. buildAny(value.Index(i), buf, "")
  117. if i < value.Len()-1 {
  118. buf.WriteString(",")
  119. }
  120. }
  121. buf.WriteString("]")
  122. return nil
  123. }
  124. type sortedValues []reflect.Value
  125. func (sv sortedValues) Len() int { return len(sv) }
  126. func (sv sortedValues) Swap(i, j int) { sv[i], sv[j] = sv[j], sv[i] }
  127. func (sv sortedValues) Less(i, j int) bool { return sv[i].String() < sv[j].String() }
  128. func buildMap(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
  129. buf.WriteString("{")
  130. sv := sortedValues(value.MapKeys())
  131. sort.Sort(sv)
  132. for i, k := range sv {
  133. if i > 0 {
  134. buf.WriteByte(',')
  135. }
  136. writeString(k.String(), buf)
  137. buf.WriteString(`:`)
  138. buildAny(value.MapIndex(k), buf, "")
  139. }
  140. buf.WriteString("}")
  141. return nil
  142. }
  143. func buildScalar(value reflect.Value, buf *bytes.Buffer, tag reflect.StructTag) error {
  144. switch value.Kind() {
  145. case reflect.String:
  146. writeString(value.String(), buf)
  147. case reflect.Bool:
  148. buf.WriteString(strconv.FormatBool(value.Bool()))
  149. case reflect.Int64:
  150. buf.WriteString(strconv.FormatInt(value.Int(), 10))
  151. case reflect.Float64:
  152. buf.WriteString(strconv.FormatFloat(value.Float(), 'f', -1, 64))
  153. default:
  154. switch value.Type() {
  155. case timeType:
  156. converted := value.Interface().(time.Time)
  157. buf.WriteString(strconv.FormatInt(converted.UTC().Unix(), 10))
  158. case byteSliceType:
  159. if !value.IsNil() {
  160. converted := value.Interface().([]byte)
  161. buf.WriteByte('"')
  162. if len(converted) < 1024 {
  163. // for small buffers, using Encode directly is much faster.
  164. dst := make([]byte, base64.StdEncoding.EncodedLen(len(converted)))
  165. base64.StdEncoding.Encode(dst, converted)
  166. buf.Write(dst)
  167. } else {
  168. // for large buffers, avoid unnecessary extra temporary
  169. // buffer space.
  170. enc := base64.NewEncoder(base64.StdEncoding, buf)
  171. enc.Write(converted)
  172. enc.Close()
  173. }
  174. buf.WriteByte('"')
  175. }
  176. default:
  177. return fmt.Errorf("unsupported JSON value %v (%s)", value.Interface(), value.Type())
  178. }
  179. }
  180. return nil
  181. }
  182. func writeString(s string, buf *bytes.Buffer) {
  183. buf.WriteByte('"')
  184. for _, r := range s {
  185. if r == '"' {
  186. buf.WriteString(`\"`)
  187. } else if r == '\\' {
  188. buf.WriteString(`\\`)
  189. } else if r == '\b' {
  190. buf.WriteString(`\b`)
  191. } else if r == '\f' {
  192. buf.WriteString(`\f`)
  193. } else if r == '\r' {
  194. buf.WriteString(`\r`)
  195. } else if r == '\t' {
  196. buf.WriteString(`\t`)
  197. } else if r == '\n' {
  198. buf.WriteString(`\n`)
  199. } else if r < 32 {
  200. fmt.Fprintf(buf, "\\u%0.4x", r)
  201. } else {
  202. buf.WriteRune(r)
  203. }
  204. }
  205. buf.WriteByte('"')
  206. }
  207. // Returns the reflection element of a value, if it is a pointer.
  208. func elemOf(value reflect.Value) reflect.Value {
  209. for value.Kind() == reflect.Ptr {
  210. value = value.Elem()
  211. }
  212. return value
  213. }