// Decode attempts to convert the provided data into a protobuf message, extract the stored schema kind, apply the provided default // gvk, and then load that data into an object matching the desired schema kind or the provided into. If into is *runtime.Unknown, // the raw data will be extracted and no decoding will be performed. If into is not registered with the typer, then the object will // be straight decoded using normal protobuf unmarshalling (the MarshalTo interface). 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. On success or most // errors, the method will return the calculated schema kind. func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) { if versioned, ok := into.(*runtime.VersionedObjects); ok { into = versioned.Last() obj, actual, err := s.Decode(originalData, gvk, into) if err != nil { return nil, actual, err } // the last item in versioned becomes into, so if versioned was not originally empty we reset the object // array so the first position is the decoded object and the second position is the outermost object. // if there were no objects in the versioned list passed to us, only add ourselves. if into != nil && into != obj { versioned.Objects = []runtime.Object{obj, into} } else { versioned.Objects = []runtime.Object{obj} } return versioned, actual, err } prefixLen := len(s.prefix) switch { case len(originalData) == 0: // TODO: treat like decoding {} from JSON with defaulting return nil, nil, fmt.Errorf("empty data") case len(originalData) < prefixLen || !bytes.Equal(s.prefix, originalData[:prefixLen]): return nil, nil, fmt.Errorf("provided data does not appear to be a protobuf message, expected prefix %v", s.prefix) case len(originalData) == prefixLen: // TODO: treat like decoding {} from JSON with defaulting return nil, nil, fmt.Errorf("empty body") } data := originalData[prefixLen:] unk := runtime.Unknown{} if err := unk.Unmarshal(data); err != nil { return nil, nil, err } actual := unk.GroupVersionKind() copyKindDefaults(&actual, gvk) if intoUnknown, ok := into.(*runtime.Unknown); ok && intoUnknown != nil { *intoUnknown = unk if ok, _, _ := s.RecognizesData(bytes.NewBuffer(unk.Raw)); ok { intoUnknown.ContentType = s.contentType } return intoUnknown, &actual, nil } if into != nil { types, _, err := s.typer.ObjectKinds(into) switch { case runtime.IsNotRegisteredError(err): pb, ok := into.(proto.Message) if !ok { return nil, &actual, errNotMarshalable{reflect.TypeOf(into)} } if err := proto.Unmarshal(unk.Raw, pb); err != nil { return nil, &actual, err } return into, &actual, nil case err != nil: return nil, &actual, err default: copyKindDefaults(&actual, &types[0]) // if the result of defaulting did not set a version or group, ensure that at least group is set // (copyKindDefaults will not assign Group if version is already set). This guarantees that the group // of into is set if there is no better information from the caller or object. if len(actual.Version) == 0 && len(actual.Group) == 0 { actual.Group = types[0].Group } } } if len(actual.Kind) == 0 { return nil, &actual, runtime.NewMissingKindErr(fmt.Sprintf("%#v", unk.TypeMeta)) } if len(actual.Version) == 0 { return nil, &actual, runtime.NewMissingVersionErr(fmt.Sprintf("%#v", unk.TypeMeta)) } return unmarshalToObject(s.typer, s.creater, &actual, into, unk.Raw) }
// Decode attempts to convert the provided data into YAML or JSON, extract the stored schema kind, apply the provided default gvk, and then // load that data into an object matching the desired schema kind or the provided into. If into is *runtime.Unknown, the raw data will be // extracted and no decoding will be performed. If into is not registered with the typer, then the object will be straight decoded using // normal JSON/YAML unmarshalling. 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. On success or most errors, the method will return the calculated schema kind. func (s *Serializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) { if versioned, ok := into.(*runtime.VersionedObjects); ok { into = versioned.Last() obj, actual, err := s.Decode(originalData, gvk, into) if err != nil { return nil, actual, err } versioned.Objects = []runtime.Object{obj} return versioned, actual, nil } data := originalData if s.yaml { altered, err := yaml.YAMLToJSON(data) if err != nil { return nil, nil, err } data = altered } actual, err := s.meta.Interpret(data) if err != nil { return nil, nil, err } if gvk != nil { // apply kind and version defaulting from provided default if len(actual.Kind) == 0 { actual.Kind = gvk.Kind } if len(actual.Version) == 0 && len(actual.Group) == 0 { actual.Group = gvk.Group actual.Version = gvk.Version } if len(actual.Version) == 0 && actual.Group == gvk.Group { actual.Version = gvk.Version } } if unk, ok := into.(*runtime.Unknown); ok && unk != nil { unk.Raw = originalData unk.ContentType = runtime.ContentTypeJSON unk.GetObjectKind().SetGroupVersionKind(*actual) return unk, actual, nil } if into != nil { types, _, err := s.typer.ObjectKinds(into) switch { case runtime.IsNotRegisteredError(err): if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(into); err != nil { return nil, actual, err } return into, actual, nil case err != nil: return nil, actual, err default: typed := types[0] if len(actual.Kind) == 0 { actual.Kind = typed.Kind } if len(actual.Version) == 0 && len(actual.Group) == 0 { actual.Group = typed.Group actual.Version = typed.Version } if len(actual.Version) == 0 && actual.Group == typed.Group { actual.Version = typed.Version } } } if len(actual.Kind) == 0 { return nil, actual, runtime.NewMissingKindErr(string(originalData)) } if len(actual.Version) == 0 { return nil, actual, runtime.NewMissingVersionErr(string(originalData)) } // use the target if necessary obj, err := runtime.UseOrCreateObject(s.typer, s.creater, *actual, into) if err != nil { return nil, actual, err } if err := codec.NewDecoderBytes(data, new(codec.JsonHandle)).Decode(obj); err != nil { return nil, actual, err } return obj, actual, nil }
// Decode attempts to convert the provided data into a protobuf message, extract the stored schema kind, apply the provided default // gvk, and then load that data into an object matching the desired schema kind or the provided into. If into is *runtime.Unknown, // the raw data will be extracted and no decoding will be performed. If into is not registered with the typer, then the object will // be straight decoded using normal protobuf unmarshalling (the MarshalTo interface). 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. On success or most // errors, the method will return the calculated schema kind. func (s *RawSerializer) Decode(originalData []byte, gvk *unversioned.GroupVersionKind, into runtime.Object) (runtime.Object, *unversioned.GroupVersionKind, error) { if into == nil { return nil, nil, fmt.Errorf("this serializer requires an object to decode into: %#v", s) } if versioned, ok := into.(*runtime.VersionedObjects); ok { into = versioned.Last() obj, actual, err := s.Decode(originalData, gvk, into) if err != nil { return nil, actual, err } if into != nil && into != obj { versioned.Objects = []runtime.Object{obj, into} } else { versioned.Objects = []runtime.Object{obj} } return versioned, actual, err } if len(originalData) == 0 { // TODO: treat like decoding {} from JSON with defaulting return nil, nil, fmt.Errorf("empty data") } data := originalData actual := &unversioned.GroupVersionKind{} copyKindDefaults(actual, gvk) if intoUnknown, ok := into.(*runtime.Unknown); ok && intoUnknown != nil { intoUnknown.Raw = data intoUnknown.ContentEncoding = "" intoUnknown.ContentType = s.contentType intoUnknown.SetGroupVersionKind(*actual) return intoUnknown, actual, nil } types, _, err := s.typer.ObjectKinds(into) switch { case runtime.IsNotRegisteredError(err): pb, ok := into.(proto.Message) if !ok { return nil, actual, errNotMarshalable{reflect.TypeOf(into)} } if err := proto.Unmarshal(data, pb); err != nil { return nil, actual, err } return into, actual, nil case err != nil: return nil, actual, err default: copyKindDefaults(actual, &types[0]) // if the result of defaulting did not set a version or group, ensure that at least group is set // (copyKindDefaults will not assign Group if version is already set). This guarantees that the group // of into is set if there is no better information from the caller or object. if len(actual.Version) == 0 && len(actual.Group) == 0 { actual.Group = types[0].Group } } if len(actual.Kind) == 0 { return nil, actual, runtime.NewMissingKindErr("<protobuf encoded body - must provide default type>") } if len(actual.Version) == 0 { return nil, actual, runtime.NewMissingVersionErr("<protobuf encoded body - must provide default type>") } return unmarshalToObject(s.typer, s.creater, actual, into, data) }