json.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. // Copyright 2015 go-swagger maintainers
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package swag
  15. import (
  16. "bytes"
  17. "encoding/json"
  18. "reflect"
  19. "strings"
  20. "sync"
  21. "github.com/mailru/easyjson/jlexer"
  22. "github.com/mailru/easyjson/jwriter"
  23. )
  24. // DefaultJSONNameProvider the default cache for types
  25. var DefaultJSONNameProvider = NewNameProvider()
  26. const comma = byte(',')
  27. var closers = map[byte]byte{
  28. '{': '}',
  29. '[': ']',
  30. }
  31. type ejMarshaler interface {
  32. MarshalEasyJSON(w *jwriter.Writer)
  33. }
  34. type ejUnmarshaler interface {
  35. UnmarshalEasyJSON(w *jlexer.Lexer)
  36. }
  37. // WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaller
  38. // so it takes the fastest option available.
  39. func WriteJSON(data interface{}) ([]byte, error) {
  40. if d, ok := data.(ejMarshaler); ok {
  41. jw := new(jwriter.Writer)
  42. d.MarshalEasyJSON(jw)
  43. return jw.BuildBytes()
  44. }
  45. if d, ok := data.(json.Marshaler); ok {
  46. return d.MarshalJSON()
  47. }
  48. return json.Marshal(data)
  49. }
  50. // ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaller
  51. // so it takes the fastes option available
  52. func ReadJSON(data []byte, value interface{}) error {
  53. if d, ok := value.(ejUnmarshaler); ok {
  54. jl := &jlexer.Lexer{Data: data}
  55. d.UnmarshalEasyJSON(jl)
  56. return jl.Error()
  57. }
  58. if d, ok := value.(json.Unmarshaler); ok {
  59. return d.UnmarshalJSON(data)
  60. }
  61. return json.Unmarshal(data, value)
  62. }
  63. // DynamicJSONToStruct converts an untyped json structure into a struct
  64. func DynamicJSONToStruct(data interface{}, target interface{}) error {
  65. // TODO: convert straight to a json typed map (mergo + iterate?)
  66. b, err := WriteJSON(data)
  67. if err != nil {
  68. return err
  69. }
  70. if err := ReadJSON(b, target); err != nil {
  71. return err
  72. }
  73. return nil
  74. }
  75. // ConcatJSON concatenates multiple json objects efficiently
  76. func ConcatJSON(blobs ...[]byte) []byte {
  77. if len(blobs) == 0 {
  78. return nil
  79. }
  80. if len(blobs) == 1 {
  81. return blobs[0]
  82. }
  83. last := len(blobs) - 1
  84. var opening, closing byte
  85. a := 0
  86. idx := 0
  87. buf := bytes.NewBuffer(nil)
  88. for i, b := range blobs {
  89. if len(b) > 0 && opening == 0 { // is this an array or an object?
  90. opening, closing = b[0], closers[b[0]]
  91. }
  92. if opening != '{' && opening != '[' {
  93. continue // don't know how to concatenate non container objects
  94. }
  95. if len(b) < 3 { // yep empty but also the last one, so closing this thing
  96. if i == last && a > 0 {
  97. buf.WriteByte(closing)
  98. }
  99. continue
  100. }
  101. idx = 0
  102. if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
  103. buf.WriteByte(comma)
  104. idx = 1 // this is not the first or the last so we want to drop the leading bracket
  105. }
  106. if i != last { // not the last one, strip brackets
  107. buf.Write(b[idx : len(b)-1])
  108. } else { // last one, strip only the leading bracket
  109. buf.Write(b[idx:])
  110. }
  111. a++
  112. }
  113. // somehow it ended up being empty, so provide a default value
  114. if buf.Len() == 0 {
  115. buf.WriteByte(opening)
  116. buf.WriteByte(closing)
  117. }
  118. return buf.Bytes()
  119. }
  120. // ToDynamicJSON turns an object into a properly JSON typed structure
  121. func ToDynamicJSON(data interface{}) interface{} {
  122. // TODO: convert straight to a json typed map (mergo + iterate?)
  123. b, _ := json.Marshal(data)
  124. var res interface{}
  125. json.Unmarshal(b, &res)
  126. return res
  127. }
  128. // FromDynamicJSON turns an object into a properly JSON typed structure
  129. func FromDynamicJSON(data, target interface{}) error {
  130. b, _ := json.Marshal(data)
  131. return json.Unmarshal(b, target)
  132. }
  133. // NameProvider represents an object capabale of translating from go property names
  134. // to json property names
  135. // This type is thread-safe.
  136. type NameProvider struct {
  137. lock *sync.Mutex
  138. index map[reflect.Type]nameIndex
  139. }
  140. type nameIndex struct {
  141. jsonNames map[string]string
  142. goNames map[string]string
  143. }
  144. // NewNameProvider creates a new name provider
  145. func NewNameProvider() *NameProvider {
  146. return &NameProvider{
  147. lock: &sync.Mutex{},
  148. index: make(map[reflect.Type]nameIndex),
  149. }
  150. }
  151. func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
  152. for i := 0; i < tpe.NumField(); i++ {
  153. targetDes := tpe.Field(i)
  154. if targetDes.PkgPath != "" { // unexported
  155. continue
  156. }
  157. if targetDes.Anonymous { // walk embedded structures tree down first
  158. buildnameIndex(targetDes.Type, idx, reverseIdx)
  159. continue
  160. }
  161. if tag := targetDes.Tag.Get("json"); tag != "" {
  162. parts := strings.Split(tag, ",")
  163. if len(parts) == 0 {
  164. continue
  165. }
  166. nm := parts[0]
  167. if nm == "-" {
  168. continue
  169. }
  170. if nm == "" { // empty string means we want to use the Go name
  171. nm = targetDes.Name
  172. }
  173. idx[nm] = targetDes.Name
  174. reverseIdx[targetDes.Name] = nm
  175. }
  176. }
  177. }
  178. func newNameIndex(tpe reflect.Type) nameIndex {
  179. var idx = make(map[string]string, tpe.NumField())
  180. var reverseIdx = make(map[string]string, tpe.NumField())
  181. buildnameIndex(tpe, idx, reverseIdx)
  182. return nameIndex{jsonNames: idx, goNames: reverseIdx}
  183. }
  184. // GetJSONNames gets all the json property names for a type
  185. func (n *NameProvider) GetJSONNames(subject interface{}) []string {
  186. tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
  187. names, ok := n.index[tpe]
  188. if !ok {
  189. names = n.makeNameIndex(tpe)
  190. }
  191. var res []string
  192. for k := range names.jsonNames {
  193. res = append(res, k)
  194. }
  195. return res
  196. }
  197. // GetJSONName gets the json name for a go property name
  198. func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) {
  199. tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
  200. return n.GetJSONNameForType(tpe, name)
  201. }
  202. // GetJSONNameForType gets the json name for a go property name on a given type
  203. func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
  204. names, ok := n.index[tpe]
  205. if !ok {
  206. names = n.makeNameIndex(tpe)
  207. }
  208. nme, ok := names.goNames[name]
  209. return nme, ok
  210. }
  211. func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
  212. n.lock.Lock()
  213. defer n.lock.Unlock()
  214. names := newNameIndex(tpe)
  215. n.index[tpe] = names
  216. return names
  217. }
  218. // GetGoName gets the go name for a json property name
  219. func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) {
  220. tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
  221. return n.GetGoNameForType(tpe, name)
  222. }
  223. // GetGoNameForType gets the go name for a given type for a json property name
  224. func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
  225. names, ok := n.index[tpe]
  226. if !ok {
  227. names = n.makeNameIndex(tpe)
  228. }
  229. nme, ok := names.jsonNames[name]
  230. return nme, ok
  231. }