json.go 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package json
  14. import (
  15. "encoding/json"
  16. "io"
  17. "strconv"
  18. "unsafe"
  19. jsoniter "github.com/json-iterator/go"
  20. "github.com/modern-go/reflect2"
  21. "sigs.k8s.io/yaml"
  22. "k8s.io/apimachinery/pkg/runtime"
  23. "k8s.io/apimachinery/pkg/runtime/schema"
  24. "k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
  25. "k8s.io/apimachinery/pkg/util/framer"
  26. utilyaml "k8s.io/apimachinery/pkg/util/yaml"
  27. )
  28. // NewSerializer creates a JSON serializer that handles encoding versioned objects into the proper JSON form. If typer
  29. // is not nil, the object has the group, version, and kind fields set.
  30. func NewSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper, pretty bool) *Serializer {
  31. return &Serializer{
  32. meta: meta,
  33. creater: creater,
  34. typer: typer,
  35. yaml: false,
  36. pretty: pretty,
  37. }
  38. }
  39. // NewYAMLSerializer creates a YAML serializer that handles encoding versioned objects into the proper YAML form. If typer
  40. // is not nil, the object has the group, version, and kind fields set. This serializer supports only the subset of YAML that
  41. // matches JSON, and will error if constructs are used that do not serialize to JSON.
  42. func NewYAMLSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper) *Serializer {
  43. return &Serializer{
  44. meta: meta,
  45. creater: creater,
  46. typer: typer,
  47. yaml: true,
  48. }
  49. }
  50. type Serializer struct {
  51. meta MetaFactory
  52. creater runtime.ObjectCreater
  53. typer runtime.ObjectTyper
  54. yaml bool
  55. pretty bool
  56. }
  57. // Serializer implements Serializer
  58. var _ runtime.Serializer = &Serializer{}
  59. var _ recognizer.RecognizingDecoder = &Serializer{}
  60. type customNumberExtension struct {
  61. jsoniter.DummyExtension
  62. }
  63. func (cne *customNumberExtension) CreateDecoder(typ reflect2.Type) jsoniter.ValDecoder {
  64. if typ.String() == "interface {}" {
  65. return customNumberDecoder{}
  66. }
  67. return nil
  68. }
  69. type customNumberDecoder struct {
  70. }
  71. func (customNumberDecoder) Decode(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
  72. switch iter.WhatIsNext() {
  73. case jsoniter.NumberValue:
  74. var number jsoniter.Number
  75. iter.ReadVal(&number)
  76. i64, err := strconv.ParseInt(string(number), 10, 64)
  77. if err == nil {
  78. *(*interface{})(ptr) = i64
  79. return
  80. }
  81. f64, err := strconv.ParseFloat(string(number), 64)
  82. if err == nil {
  83. *(*interface{})(ptr) = f64
  84. return
  85. }
  86. iter.ReportError("DecodeNumber", err.Error())
  87. default:
  88. *(*interface{})(ptr) = iter.Read()
  89. }
  90. }
  91. // CaseSensitiveJsonIterator returns a jsoniterator API that's configured to be
  92. // case-sensitive when unmarshalling, and otherwise compatible with
  93. // the encoding/json standard library.
  94. func CaseSensitiveJsonIterator() jsoniter.API {
  95. config := jsoniter.Config{
  96. EscapeHTML: true,
  97. SortMapKeys: true,
  98. ValidateJsonRawMessage: true,
  99. CaseSensitive: true,
  100. }.Froze()
  101. // Force jsoniter to decode number to interface{} via int64/float64, if possible.
  102. config.RegisterExtension(&customNumberExtension{})
  103. return config
  104. }
  105. // Private copy of jsoniter to try to shield against possible mutations
  106. // from outside. Still does not protect from package level jsoniter.Register*() functions - someone calling them
  107. // in some other library will mess with every usage of the jsoniter library in the whole program.
  108. // See https://github.com/json-iterator/go/issues/265
  109. var caseSensitiveJsonIterator = CaseSensitiveJsonIterator()
  110. // gvkWithDefaults returns group kind and version defaulting from provided default
  111. func gvkWithDefaults(actual, defaultGVK schema.GroupVersionKind) schema.GroupVersionKind {
  112. if len(actual.Kind) == 0 {
  113. actual.Kind = defaultGVK.Kind
  114. }
  115. if len(actual.Version) == 0 && len(actual.Group) == 0 {
  116. actual.Group = defaultGVK.Group
  117. actual.Version = defaultGVK.Version
  118. }
  119. if len(actual.Version) == 0 && actual.Group == defaultGVK.Group {
  120. actual.Version = defaultGVK.Version
  121. }
  122. return actual
  123. }
  124. // Decode attempts to convert the provided data into YAML or JSON, extract the stored schema kind, apply the provided default gvk, and then
  125. // load that data into an object matching the desired schema kind or the provided into.
  126. // If into is *runtime.Unknown, the raw data will be extracted and no decoding will be performed.
  127. // If into is not registered with the typer, then the object will be straight decoded using normal JSON/YAML unmarshalling.
  128. // If into is provided and the original data is not fully qualified with kind/version/group, the type of the into will be used to alter the returned gvk.
  129. // If into is nil or data's gvk different from into's gvk, it will generate a new Object with ObjectCreater.New(gvk)
  130. // On success or most errors, the method will return the calculated schema kind.
  131. // The gvk calculate priority will be originalData > default gvk > into
  132. func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
  133. if versioned, ok := into.(*runtime.VersionedObjects); ok {
  134. into = versioned.Last()
  135. obj, actual, err := s.Decode(originalData, gvk, into)
  136. if err != nil {
  137. return nil, actual, err
  138. }
  139. versioned.Objects = []runtime.Object{obj}
  140. return versioned, actual, nil
  141. }
  142. data := originalData
  143. if s.yaml {
  144. altered, err := yaml.YAMLToJSON(data)
  145. if err != nil {
  146. return nil, nil, err
  147. }
  148. data = altered
  149. }
  150. actual, err := s.meta.Interpret(data)
  151. if err != nil {
  152. return nil, nil, err
  153. }
  154. if gvk != nil {
  155. *actual = gvkWithDefaults(*actual, *gvk)
  156. }
  157. if unk, ok := into.(*runtime.Unknown); ok && unk != nil {
  158. unk.Raw = originalData
  159. unk.ContentType = runtime.ContentTypeJSON
  160. unk.GetObjectKind().SetGroupVersionKind(*actual)
  161. return unk, actual, nil
  162. }
  163. if into != nil {
  164. _, isUnstructured := into.(runtime.Unstructured)
  165. types, _, err := s.typer.ObjectKinds(into)
  166. switch {
  167. case runtime.IsNotRegisteredError(err), isUnstructured:
  168. if err := caseSensitiveJsonIterator.Unmarshal(data, into); err != nil {
  169. return nil, actual, err
  170. }
  171. return into, actual, nil
  172. case err != nil:
  173. return nil, actual, err
  174. default:
  175. *actual = gvkWithDefaults(*actual, types[0])
  176. }
  177. }
  178. if len(actual.Kind) == 0 {
  179. return nil, actual, runtime.NewMissingKindErr(string(originalData))
  180. }
  181. if len(actual.Version) == 0 {
  182. return nil, actual, runtime.NewMissingVersionErr(string(originalData))
  183. }
  184. // use the target if necessary
  185. obj, err := runtime.UseOrCreateObject(s.typer, s.creater, *actual, into)
  186. if err != nil {
  187. return nil, actual, err
  188. }
  189. if err := caseSensitiveJsonIterator.Unmarshal(data, obj); err != nil {
  190. return nil, actual, err
  191. }
  192. return obj, actual, nil
  193. }
  194. // Encode serializes the provided object to the given writer.
  195. func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
  196. if s.yaml {
  197. json, err := caseSensitiveJsonIterator.Marshal(obj)
  198. if err != nil {
  199. return err
  200. }
  201. data, err := yaml.JSONToYAML(json)
  202. if err != nil {
  203. return err
  204. }
  205. _, err = w.Write(data)
  206. return err
  207. }
  208. if s.pretty {
  209. data, err := caseSensitiveJsonIterator.MarshalIndent(obj, "", " ")
  210. if err != nil {
  211. return err
  212. }
  213. _, err = w.Write(data)
  214. return err
  215. }
  216. encoder := json.NewEncoder(w)
  217. return encoder.Encode(obj)
  218. }
  219. // RecognizesData implements the RecognizingDecoder interface.
  220. func (s *Serializer) RecognizesData(peek io.Reader) (ok, unknown bool, err error) {
  221. if s.yaml {
  222. // we could potentially look for '---'
  223. return false, true, nil
  224. }
  225. _, _, ok = utilyaml.GuessJSONStream(peek, 2048)
  226. return ok, false, nil
  227. }
  228. // Framer is the default JSON framing behavior, with newlines delimiting individual objects.
  229. var Framer = jsonFramer{}
  230. type jsonFramer struct{}
  231. // NewFrameWriter implements stream framing for this serializer
  232. func (jsonFramer) NewFrameWriter(w io.Writer) io.Writer {
  233. // we can write JSON objects directly to the writer, because they are self-framing
  234. return w
  235. }
  236. // NewFrameReader implements stream framing for this serializer
  237. func (jsonFramer) NewFrameReader(r io.ReadCloser) io.ReadCloser {
  238. // we need to extract the JSON chunks of data to pass to Decode()
  239. return framer.NewJSONFramedReader(r)
  240. }
  241. // YAMLFramer is the default JSON framing behavior, with newlines delimiting individual objects.
  242. var YAMLFramer = yamlFramer{}
  243. type yamlFramer struct{}
  244. // NewFrameWriter implements stream framing for this serializer
  245. func (yamlFramer) NewFrameWriter(w io.Writer) io.Writer {
  246. return yamlFrameWriter{w}
  247. }
  248. // NewFrameReader implements stream framing for this serializer
  249. func (yamlFramer) NewFrameReader(r io.ReadCloser) io.ReadCloser {
  250. // extract the YAML document chunks directly
  251. return utilyaml.NewDocumentDecoder(r)
  252. }
  253. type yamlFrameWriter struct {
  254. w io.Writer
  255. }
  256. // Write separates each document with the YAML document separator (`---` followed by line
  257. // break). Writers must write well formed YAML documents (include a final line break).
  258. func (w yamlFrameWriter) Write(data []byte) (n int, err error) {
  259. if _, err := w.w.Write([]byte("---\n")); err != nil {
  260. return 0, err
  261. }
  262. return w.w.Write(data)
  263. }