json.go 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  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. "log"
  19. "reflect"
  20. "strings"
  21. "sync"
  22. "github.com/mailru/easyjson/jlexer"
  23. "github.com/mailru/easyjson/jwriter"
  24. )
  25. // nullJSON represents a JSON object with null type
  26. var nullJSON = []byte("null")
  27. // DefaultJSONNameProvider the default cache for types
  28. var DefaultJSONNameProvider = NewNameProvider()
  29. const comma = byte(',')
  30. var closers map[byte]byte
  31. func init() {
  32. closers = map[byte]byte{
  33. '{': '}',
  34. '[': ']',
  35. }
  36. }
  37. type ejMarshaler interface {
  38. MarshalEasyJSON(w *jwriter.Writer)
  39. }
  40. type ejUnmarshaler interface {
  41. UnmarshalEasyJSON(w *jlexer.Lexer)
  42. }
  43. // WriteJSON writes json data, prefers finding an appropriate interface to short-circuit the marshaller
  44. // so it takes the fastest option available.
  45. func WriteJSON(data interface{}) ([]byte, error) {
  46. if d, ok := data.(ejMarshaler); ok {
  47. jw := new(jwriter.Writer)
  48. d.MarshalEasyJSON(jw)
  49. return jw.BuildBytes()
  50. }
  51. if d, ok := data.(json.Marshaler); ok {
  52. return d.MarshalJSON()
  53. }
  54. return json.Marshal(data)
  55. }
  56. // ReadJSON reads json data, prefers finding an appropriate interface to short-circuit the unmarshaller
  57. // so it takes the fastes option available
  58. func ReadJSON(data []byte, value interface{}) error {
  59. if d, ok := value.(ejUnmarshaler); ok {
  60. jl := &jlexer.Lexer{Data: data}
  61. d.UnmarshalEasyJSON(jl)
  62. return jl.Error()
  63. }
  64. if d, ok := value.(json.Unmarshaler); ok {
  65. return d.UnmarshalJSON(data)
  66. }
  67. return json.Unmarshal(data, value)
  68. }
  69. // DynamicJSONToStruct converts an untyped json structure into a struct
  70. func DynamicJSONToStruct(data interface{}, target interface{}) error {
  71. // TODO: convert straight to a json typed map (mergo + iterate?)
  72. b, err := WriteJSON(data)
  73. if err != nil {
  74. return err
  75. }
  76. return ReadJSON(b, target)
  77. }
  78. // ConcatJSON concatenates multiple json objects efficiently
  79. func ConcatJSON(blobs ...[]byte) []byte {
  80. if len(blobs) == 0 {
  81. return nil
  82. }
  83. last := len(blobs) - 1
  84. for blobs[last] == nil || bytes.Equal(blobs[last], nullJSON) {
  85. // strips trailing null objects
  86. last = last - 1
  87. if last < 0 {
  88. // there was nothing but "null"s or nil...
  89. return nil
  90. }
  91. }
  92. if last == 0 {
  93. return blobs[0]
  94. }
  95. var opening, closing byte
  96. var idx, a int
  97. buf := bytes.NewBuffer(nil)
  98. for i, b := range blobs[:last+1] {
  99. if b == nil || bytes.Equal(b, nullJSON) {
  100. // a null object is in the list: skip it
  101. continue
  102. }
  103. if len(b) > 0 && opening == 0 { // is this an array or an object?
  104. opening, closing = b[0], closers[b[0]]
  105. }
  106. if opening != '{' && opening != '[' {
  107. continue // don't know how to concatenate non container objects
  108. }
  109. if len(b) < 3 { // yep empty but also the last one, so closing this thing
  110. if i == last && a > 0 {
  111. if err := buf.WriteByte(closing); err != nil {
  112. log.Println(err)
  113. }
  114. }
  115. continue
  116. }
  117. idx = 0
  118. if a > 0 { // we need to join with a comma for everything beyond the first non-empty item
  119. if err := buf.WriteByte(comma); err != nil {
  120. log.Println(err)
  121. }
  122. idx = 1 // this is not the first or the last so we want to drop the leading bracket
  123. }
  124. if i != last { // not the last one, strip brackets
  125. if _, err := buf.Write(b[idx : len(b)-1]); err != nil {
  126. log.Println(err)
  127. }
  128. } else { // last one, strip only the leading bracket
  129. if _, err := buf.Write(b[idx:]); err != nil {
  130. log.Println(err)
  131. }
  132. }
  133. a++
  134. }
  135. // somehow it ended up being empty, so provide a default value
  136. if buf.Len() == 0 {
  137. if err := buf.WriteByte(opening); err != nil {
  138. log.Println(err)
  139. }
  140. if err := buf.WriteByte(closing); err != nil {
  141. log.Println(err)
  142. }
  143. }
  144. return buf.Bytes()
  145. }
  146. // ToDynamicJSON turns an object into a properly JSON typed structure
  147. func ToDynamicJSON(data interface{}) interface{} {
  148. // TODO: convert straight to a json typed map (mergo + iterate?)
  149. b, err := json.Marshal(data)
  150. if err != nil {
  151. log.Println(err)
  152. }
  153. var res interface{}
  154. if err := json.Unmarshal(b, &res); err != nil {
  155. log.Println(err)
  156. }
  157. return res
  158. }
  159. // FromDynamicJSON turns an object into a properly JSON typed structure
  160. func FromDynamicJSON(data, target interface{}) error {
  161. b, err := json.Marshal(data)
  162. if err != nil {
  163. log.Println(err)
  164. }
  165. return json.Unmarshal(b, target)
  166. }
  167. // NameProvider represents an object capabale of translating from go property names
  168. // to json property names
  169. // This type is thread-safe.
  170. type NameProvider struct {
  171. lock *sync.Mutex
  172. index map[reflect.Type]nameIndex
  173. }
  174. type nameIndex struct {
  175. jsonNames map[string]string
  176. goNames map[string]string
  177. }
  178. // NewNameProvider creates a new name provider
  179. func NewNameProvider() *NameProvider {
  180. return &NameProvider{
  181. lock: &sync.Mutex{},
  182. index: make(map[reflect.Type]nameIndex),
  183. }
  184. }
  185. func buildnameIndex(tpe reflect.Type, idx, reverseIdx map[string]string) {
  186. for i := 0; i < tpe.NumField(); i++ {
  187. targetDes := tpe.Field(i)
  188. if targetDes.PkgPath != "" { // unexported
  189. continue
  190. }
  191. if targetDes.Anonymous { // walk embedded structures tree down first
  192. buildnameIndex(targetDes.Type, idx, reverseIdx)
  193. continue
  194. }
  195. if tag := targetDes.Tag.Get("json"); tag != "" {
  196. parts := strings.Split(tag, ",")
  197. if len(parts) == 0 {
  198. continue
  199. }
  200. nm := parts[0]
  201. if nm == "-" {
  202. continue
  203. }
  204. if nm == "" { // empty string means we want to use the Go name
  205. nm = targetDes.Name
  206. }
  207. idx[nm] = targetDes.Name
  208. reverseIdx[targetDes.Name] = nm
  209. }
  210. }
  211. }
  212. func newNameIndex(tpe reflect.Type) nameIndex {
  213. var idx = make(map[string]string, tpe.NumField())
  214. var reverseIdx = make(map[string]string, tpe.NumField())
  215. buildnameIndex(tpe, idx, reverseIdx)
  216. return nameIndex{jsonNames: idx, goNames: reverseIdx}
  217. }
  218. // GetJSONNames gets all the json property names for a type
  219. func (n *NameProvider) GetJSONNames(subject interface{}) []string {
  220. n.lock.Lock()
  221. defer n.lock.Unlock()
  222. tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
  223. names, ok := n.index[tpe]
  224. if !ok {
  225. names = n.makeNameIndex(tpe)
  226. }
  227. res := make([]string, 0, len(names.jsonNames))
  228. for k := range names.jsonNames {
  229. res = append(res, k)
  230. }
  231. return res
  232. }
  233. // GetJSONName gets the json name for a go property name
  234. func (n *NameProvider) GetJSONName(subject interface{}, name string) (string, bool) {
  235. tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
  236. return n.GetJSONNameForType(tpe, name)
  237. }
  238. // GetJSONNameForType gets the json name for a go property name on a given type
  239. func (n *NameProvider) GetJSONNameForType(tpe reflect.Type, name string) (string, bool) {
  240. n.lock.Lock()
  241. defer n.lock.Unlock()
  242. names, ok := n.index[tpe]
  243. if !ok {
  244. names = n.makeNameIndex(tpe)
  245. }
  246. nme, ok := names.goNames[name]
  247. return nme, ok
  248. }
  249. func (n *NameProvider) makeNameIndex(tpe reflect.Type) nameIndex {
  250. names := newNameIndex(tpe)
  251. n.index[tpe] = names
  252. return names
  253. }
  254. // GetGoName gets the go name for a json property name
  255. func (n *NameProvider) GetGoName(subject interface{}, name string) (string, bool) {
  256. tpe := reflect.Indirect(reflect.ValueOf(subject)).Type()
  257. return n.GetGoNameForType(tpe, name)
  258. }
  259. // GetGoNameForType gets the go name for a given type for a json property name
  260. func (n *NameProvider) GetGoNameForType(tpe reflect.Type, name string) (string, bool) {
  261. n.lock.Lock()
  262. defer n.lock.Unlock()
  263. names, ok := n.index[tpe]
  264. if !ok {
  265. names = n.makeNameIndex(tpe)
  266. }
  267. nme, ok := names.jsonNames[name]
  268. return nme, ok
  269. }