本站源代码
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

313 行
7.8KB

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