http urls monitor.

json.go 7.8KB

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