Allow objects to serialize their nested objects

Introduce an optional interface for callers to encode themselves.
This commit is contained in:
Clayton Coleman
2016-05-25 22:50:29 -04:00
parent 12a5eeea17
commit ce57455de6
4 changed files with 137 additions and 58 deletions

View File

@@ -88,6 +88,12 @@ func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, in
return nil, gvk, err
}
if d, ok := obj.(runtime.NestedObjectDecoder); ok {
if err := d.DecodeNestedObjects(DirectDecoder{c.decoder}); err != nil {
return nil, gvk, err
}
}
// if we specify a target, use generic conversion.
if into != nil {
if into == obj {
@@ -131,21 +137,8 @@ func (c *codec) Decode(data []byte, defaultGVK *unversioned.GroupVersionKind, in
// Encode ensures the provided object is output in the appropriate group and version, invoking
// conversion if necessary. Unversioned objects (according to the ObjectTyper) are output as is.
func (c *codec) Encode(obj runtime.Object, w io.Writer) error {
switch t := obj.(type) {
case *runtime.Unknown:
if gv, ok := runtime.PreferredGroupVersion(c.encodeVersion); ok {
t.APIVersion = gv.String()
}
return c.encoder.Encode(obj, w)
case *runtime.Unstructured:
if gv, ok := runtime.PreferredGroupVersion(c.encodeVersion); ok {
t.SetAPIVersion(gv.String())
}
return c.encoder.Encode(obj, w)
case *runtime.UnstructuredList:
if gv, ok := runtime.PreferredGroupVersion(c.encodeVersion); ok {
t.SetAPIVersion(gv.String())
}
switch obj.(type) {
case *runtime.Unknown, *runtime.Unstructured, *runtime.UnstructuredList:
return c.encoder.Encode(obj, w)
}
@@ -155,6 +148,11 @@ func (c *codec) Encode(obj runtime.Object, w io.Writer) error {
}
if c.encodeVersion == nil || isUnversioned {
if e, ok := obj.(runtime.NestedObjectEncoder); ok {
if err := e.EncodeNestedObjects(DirectEncoder{Encoder: c.encoder, ObjectTyper: c.typer}); err != nil {
return err
}
}
objectKind := obj.GetObjectKind()
old := objectKind.GroupVersionKind()
objectKind.SetGroupVersionKind(gvks[0])
@@ -170,9 +168,52 @@ func (c *codec) Encode(obj runtime.Object, w io.Writer) error {
if err != nil {
return err
}
if e, ok := out.(runtime.NestedObjectEncoder); ok {
if err := e.EncodeNestedObjects(DirectEncoder{Encoder: c.encoder, ObjectTyper: c.typer}); err != nil {
return err
}
}
// Conversion is responsible for setting the proper group, version, and kind onto the outgoing object
err = c.encoder.Encode(out, w)
// restore the old GVK, in case conversion returned the same object
objectKind.SetGroupVersionKind(old)
return err
}
// DirectEncoder serializes an object and ensures the GVK is set.
type DirectEncoder struct {
runtime.Encoder
runtime.ObjectTyper
}
// Encode does not do conversion. It sets the gvk during serialization.
func (e DirectEncoder) Encode(obj runtime.Object, stream io.Writer) error {
gvks, _, err := e.ObjectTyper.ObjectKinds(obj)
if err != nil {
return err
}
kind := obj.GetObjectKind()
oldGVK := kind.GroupVersionKind()
kind.SetGroupVersionKind(gvks[0])
err = e.Encoder.Encode(obj, stream)
kind.SetGroupVersionKind(oldGVK)
return err
}
// DirectDecoder clears the group version kind of a deserialized object.
type DirectDecoder struct {
runtime.Decoder
}
// Decode does not do conversion. It removes the gvk during deserialization.
func (d DirectDecoder) Decode(data []byte, defaults *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) {
obj, gvk, err := d.Decoder.Decode(data, defaults, into)
if obj != nil {
kind := obj.GetObjectKind()
// clearing the gvk is just a convention of a codec
kind.SetGroupVersionKind(unversioned.GroupVersionKind{})
}
return obj, gvk, err
}