// marshalObject writes a struct to the Writer. func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent string) error { // Prefer specialized marshalers if available if mlr, ok := v.(json.Marshaler); ok { bs, err := mlr.MarshalJSON() if err != nil { return err } if out.err != nil { return out.err } _, out.err = out.writer.Write(bs) return out.err } out.write("{") if m.Indent != "" { out.write("\n") } s := reflect.ValueOf(v).Elem() writeBeforeField := "" for i := 0; i < s.NumField(); i++ { value := s.Field(i) valueField := s.Type().Field(i) if strings.HasPrefix(valueField.Name, "XXX_") { continue } fieldName := jsonFieldName(valueField) // TODO: proto3 objects should have default values omitted. // IsNil will panic on most value kinds. switch value.Kind() { case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: if value.IsNil() { continue } } // Oneof fields need special handling. if valueField.Tag.Get("protobuf_oneof") != "" { // value is an interface containing &T{real_value}. sv := value.Elem().Elem() // interface -> *T -> T value = sv.Field(0) valueField = sv.Type().Field(0) var p proto.Properties p.Parse(sv.Type().Field(0).Tag.Get("protobuf")) fieldName = p.OrigName } out.write(writeBeforeField) if m.Indent != "" { out.write(indent) out.write(m.Indent) } out.write(`"`) out.write(fieldName) out.write(`":`) if m.Indent != "" { out.write(" ") } if err := m.marshalValue(out, value, valueField, indent); err != nil { return err } if m.Indent != "" { writeBeforeField = ",\n" } else { writeBeforeField = "," } } if m.Indent != "" { out.write("\n") out.write(indent) } out.write("}") return out.err }
// jsonFieldName returns the field name to use. func jsonFieldName(f reflect.StructField) string { var prop proto.Properties prop.Init(f.Type, f.Name, f.Tag.Get("protobuf"), &f) return prop.OrigName }