2 Copyright 2014 The Kubernetes Authors.
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
20 "k8s.io/apimachinery/pkg/runtime"
21 "k8s.io/apimachinery/pkg/runtime/schema"
22 "k8s.io/apimachinery/pkg/runtime/serializer/json"
23 "k8s.io/apimachinery/pkg/runtime/serializer/recognizer"
24 "k8s.io/apimachinery/pkg/runtime/serializer/versioning"
27 // serializerExtensions are for serializers that are conditionally compiled in
28 var serializerExtensions = []func(*runtime.Scheme) (serializerType, bool){}
30 type serializerType struct {
31 AcceptContentTypes []string
33 FileExtensions []string
34 // EncodesAsText should be true if this content type can be represented safely in UTF-8
37 Serializer runtime.Serializer
38 PrettySerializer runtime.Serializer
40 AcceptStreamContentTypes []string
41 StreamContentType string
44 StreamSerializer runtime.Serializer
47 func newSerializersForScheme(scheme *runtime.Scheme, mf json.MetaFactory) []serializerType {
48 jsonSerializer := json.NewSerializer(mf, scheme, scheme, false)
49 jsonPrettySerializer := json.NewSerializer(mf, scheme, scheme, true)
50 yamlSerializer := json.NewYAMLSerializer(mf, scheme, scheme)
52 serializers := []serializerType{
54 AcceptContentTypes: []string{"application/json"},
55 ContentType: "application/json",
56 FileExtensions: []string{"json"},
58 Serializer: jsonSerializer,
59 PrettySerializer: jsonPrettySerializer,
62 StreamSerializer: jsonSerializer,
65 AcceptContentTypes: []string{"application/yaml"},
66 ContentType: "application/yaml",
67 FileExtensions: []string{"yaml"},
69 Serializer: yamlSerializer,
73 for _, fn := range serializerExtensions {
74 if serializer, ok := fn(scheme); ok {
75 serializers = append(serializers, serializer)
81 // CodecFactory provides methods for retrieving codecs and serializers for specific
82 // versions and content types.
83 type CodecFactory struct {
84 scheme *runtime.Scheme
85 serializers []serializerType
86 universal runtime.Decoder
87 accepts []runtime.SerializerInfo
89 legacySerializer runtime.Serializer
92 // NewCodecFactory provides methods for retrieving serializers for the supported wire formats
93 // and conversion wrappers to define preferred internal and external versions. In the future,
94 // as the internal version is used less, callers may instead use a defaulting serializer and
95 // only convert objects which are shared internally (Status, common API machinery).
96 // TODO: allow other codecs to be compiled in?
97 // TODO: accept a scheme interface
98 func NewCodecFactory(scheme *runtime.Scheme) CodecFactory {
99 serializers := newSerializersForScheme(scheme, json.DefaultMetaFactory)
100 return newCodecFactory(scheme, serializers)
103 // newCodecFactory is a helper for testing that allows a different metafactory to be specified.
104 func newCodecFactory(scheme *runtime.Scheme, serializers []serializerType) CodecFactory {
105 decoders := make([]runtime.Decoder, 0, len(serializers))
106 var accepts []runtime.SerializerInfo
107 alreadyAccepted := make(map[string]struct{})
109 var legacySerializer runtime.Serializer
110 for _, d := range serializers {
111 decoders = append(decoders, d.Serializer)
112 for _, mediaType := range d.AcceptContentTypes {
113 if _, ok := alreadyAccepted[mediaType]; ok {
116 alreadyAccepted[mediaType] = struct{}{}
117 info := runtime.SerializerInfo{
118 MediaType: d.ContentType,
119 EncodesAsText: d.EncodesAsText,
120 Serializer: d.Serializer,
121 PrettySerializer: d.PrettySerializer,
123 if d.StreamSerializer != nil {
124 info.StreamSerializer = &runtime.StreamSerializerInfo{
125 Serializer: d.StreamSerializer,
126 EncodesAsText: d.EncodesAsText,
130 accepts = append(accepts, info)
131 if mediaType == runtime.ContentTypeJSON {
132 legacySerializer = d.Serializer
136 if legacySerializer == nil {
137 legacySerializer = serializers[0].Serializer
142 serializers: serializers,
143 universal: recognizer.NewDecoder(decoders...),
147 legacySerializer: legacySerializer,
151 // SupportedMediaTypes returns the RFC2046 media types that this factory has serializers for.
152 func (f CodecFactory) SupportedMediaTypes() []runtime.SerializerInfo {
156 // LegacyCodec encodes output to a given API versions, and decodes output into the internal form from
157 // any recognized source. The returned codec will always encode output to JSON. If a type is not
158 // found in the list of versions an error will be returned.
160 // This method is deprecated - clients and servers should negotiate a serializer by mime-type and
161 // invoke CodecForVersions. Callers that need only to read data should use UniversalDecoder().
163 // TODO: make this call exist only in pkg/api, and initialize it with the set of default versions.
164 // All other callers will be forced to request a Codec directly.
165 func (f CodecFactory) LegacyCodec(version ...schema.GroupVersion) runtime.Codec {
166 return versioning.NewDefaultingCodecForScheme(f.scheme, f.legacySerializer, f.universal, schema.GroupVersions(version), runtime.InternalGroupVersioner)
169 // UniversalDeserializer can convert any stored data recognized by this factory into a Go object that satisfies
170 // runtime.Object. It does not perform conversion. It does not perform defaulting.
171 func (f CodecFactory) UniversalDeserializer() runtime.Decoder {
175 // UniversalDecoder returns a runtime.Decoder capable of decoding all known API objects in all known formats. Used
176 // by clients that do not need to encode objects but want to deserialize API objects stored on disk. Only decodes
177 // objects in groups registered with the scheme. The GroupVersions passed may be used to select alternate
178 // versions of objects to return - by default, runtime.APIVersionInternal is used. If any versions are specified,
179 // unrecognized groups will be returned in the version they are encoded as (no conversion). This decoder performs
182 // TODO: the decoder will eventually be removed in favor of dealing with objects in their versioned form
183 // TODO: only accept a group versioner
184 func (f CodecFactory) UniversalDecoder(versions ...schema.GroupVersion) runtime.Decoder {
185 var versioner runtime.GroupVersioner
186 if len(versions) == 0 {
187 versioner = runtime.InternalGroupVersioner
189 versioner = schema.GroupVersions(versions)
191 return f.CodecForVersions(nil, f.universal, nil, versioner)
194 // CodecForVersions creates a codec with the provided serializer. If an object is decoded and its group is not in the list,
195 // it will default to runtime.APIVersionInternal. If encode is not specified for an object's group, the object is not
196 // converted. If encode or decode are nil, no conversion is performed.
197 func (f CodecFactory) CodecForVersions(encoder runtime.Encoder, decoder runtime.Decoder, encode runtime.GroupVersioner, decode runtime.GroupVersioner) runtime.Codec {
198 // TODO: these are for backcompat, remove them in the future
200 encode = runtime.DisabledGroupVersioner
203 decode = runtime.InternalGroupVersioner
205 return versioning.NewDefaultingCodecForScheme(f.scheme, encoder, decoder, encode, decode)
208 // DecoderToVersion returns a decoder that targets the provided group version.
209 func (f CodecFactory) DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
210 return f.CodecForVersions(nil, decoder, nil, gv)
213 // EncoderForVersion returns an encoder that targets the provided group version.
214 func (f CodecFactory) EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
215 return f.CodecForVersions(encoder, nil, gv, nil)
218 // DirectCodecFactory provides methods for retrieving "DirectCodec"s, which do not do conversion.
219 type DirectCodecFactory struct {
223 // EncoderForVersion returns an encoder that does not do conversion.
224 func (f DirectCodecFactory) EncoderForVersion(serializer runtime.Encoder, version runtime.GroupVersioner) runtime.Encoder {
225 return versioning.DirectEncoder{
228 ObjectTyper: f.CodecFactory.scheme,
232 // DecoderToVersion returns an decoder that does not do conversion. gv is ignored.
233 func (f DirectCodecFactory) DecoderToVersion(serializer runtime.Decoder, _ runtime.GroupVersioner) runtime.Decoder {
234 return versioning.DirectDecoder{