1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package protojson 6 7import ( 8 "encoding/base64" 9 "fmt" 10 11 "google.golang.org/protobuf/internal/encoding/json" 12 "google.golang.org/protobuf/internal/encoding/messageset" 13 "google.golang.org/protobuf/internal/errors" 14 "google.golang.org/protobuf/internal/filedesc" 15 "google.golang.org/protobuf/internal/flags" 16 "google.golang.org/protobuf/internal/genid" 17 "google.golang.org/protobuf/internal/order" 18 "google.golang.org/protobuf/internal/pragma" 19 "google.golang.org/protobuf/proto" 20 "google.golang.org/protobuf/reflect/protoreflect" 21 pref "google.golang.org/protobuf/reflect/protoreflect" 22 "google.golang.org/protobuf/reflect/protoregistry" 23) 24 25const defaultIndent = " " 26 27// Format formats the message as a multiline string. 28// This function is only intended for human consumption and ignores errors. 29// Do not depend on the output being stable. It may change over time across 30// different versions of the program. 31func Format(m proto.Message) string { 32 return MarshalOptions{Multiline: true}.Format(m) 33} 34 35// Marshal writes the given proto.Message in JSON format using default options. 36// Do not depend on the output being stable. It may change over time across 37// different versions of the program. 38func Marshal(m proto.Message) ([]byte, error) { 39 return MarshalOptions{}.Marshal(m) 40} 41 42// MarshalOptions is a configurable JSON format marshaler. 43type MarshalOptions struct { 44 pragma.NoUnkeyedLiterals 45 46 // Multiline specifies whether the marshaler should format the output in 47 // indented-form with every textual element on a new line. 48 // If Indent is an empty string, then an arbitrary indent is chosen. 49 Multiline bool 50 51 // Indent specifies the set of indentation characters to use in a multiline 52 // formatted output such that every entry is preceded by Indent and 53 // terminated by a newline. If non-empty, then Multiline is treated as true. 54 // Indent can only be composed of space or tab characters. 55 Indent string 56 57 // AllowPartial allows messages that have missing required fields to marshal 58 // without returning an error. If AllowPartial is false (the default), 59 // Marshal will return error if there are any missing required fields. 60 AllowPartial bool 61 62 // UseProtoNames uses proto field name instead of lowerCamelCase name in JSON 63 // field names. 64 UseProtoNames bool 65 66 // UseEnumNumbers emits enum values as numbers. 67 UseEnumNumbers bool 68 69 // EmitUnpopulated specifies whether to emit unpopulated fields. It does not 70 // emit unpopulated oneof fields or unpopulated extension fields. 71 // The JSON value emitted for unpopulated fields are as follows: 72 // ╔═══════╤════════════════════════════╗ 73 // ║ JSON │ Protobuf field ║ 74 // ╠═══════╪════════════════════════════╣ 75 // ║ false │ proto3 boolean fields ║ 76 // ║ 0 │ proto3 numeric fields ║ 77 // ║ "" │ proto3 string/bytes fields ║ 78 // ║ null │ proto2 scalar fields ║ 79 // ║ null │ message fields ║ 80 // ║ [] │ list fields ║ 81 // ║ {} │ map fields ║ 82 // ╚═══════╧════════════════════════════╝ 83 EmitUnpopulated bool 84 85 // Resolver is used for looking up types when expanding google.protobuf.Any 86 // messages. If nil, this defaults to using protoregistry.GlobalTypes. 87 Resolver interface { 88 protoregistry.ExtensionTypeResolver 89 protoregistry.MessageTypeResolver 90 } 91} 92 93// Format formats the message as a string. 94// This method is only intended for human consumption and ignores errors. 95// Do not depend on the output being stable. It may change over time across 96// different versions of the program. 97func (o MarshalOptions) Format(m proto.Message) string { 98 if m == nil || !m.ProtoReflect().IsValid() { 99 return "<nil>" // invalid syntax, but okay since this is for debugging 100 } 101 o.AllowPartial = true 102 b, _ := o.Marshal(m) 103 return string(b) 104} 105 106// Marshal marshals the given proto.Message in the JSON format using options in 107// MarshalOptions. Do not depend on the output being stable. It may change over 108// time across different versions of the program. 109func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) { 110 return o.marshal(m) 111} 112 113// marshal is a centralized function that all marshal operations go through. 114// For profiling purposes, avoid changing the name of this function or 115// introducing other code paths for marshal that do not go through this. 116func (o MarshalOptions) marshal(m proto.Message) ([]byte, error) { 117 if o.Multiline && o.Indent == "" { 118 o.Indent = defaultIndent 119 } 120 if o.Resolver == nil { 121 o.Resolver = protoregistry.GlobalTypes 122 } 123 124 internalEnc, err := json.NewEncoder(o.Indent) 125 if err != nil { 126 return nil, err 127 } 128 129 // Treat nil message interface as an empty message, 130 // in which case the output in an empty JSON object. 131 if m == nil { 132 return []byte("{}"), nil 133 } 134 135 enc := encoder{internalEnc, o} 136 if err := enc.marshalMessage(m.ProtoReflect(), ""); err != nil { 137 return nil, err 138 } 139 if o.AllowPartial { 140 return enc.Bytes(), nil 141 } 142 return enc.Bytes(), proto.CheckInitialized(m) 143} 144 145type encoder struct { 146 *json.Encoder 147 opts MarshalOptions 148} 149 150// typeFieldDesc is a synthetic field descriptor used for the "@type" field. 151var typeFieldDesc = func() protoreflect.FieldDescriptor { 152 var fd filedesc.Field 153 fd.L0.FullName = "@type" 154 fd.L0.Index = -1 155 fd.L1.Cardinality = protoreflect.Optional 156 fd.L1.Kind = protoreflect.StringKind 157 return &fd 158}() 159 160// typeURLFieldRanger wraps a protoreflect.Message and modifies its Range method 161// to additionally iterate over a synthetic field for the type URL. 162type typeURLFieldRanger struct { 163 order.FieldRanger 164 typeURL string 165} 166 167func (m typeURLFieldRanger) Range(f func(pref.FieldDescriptor, pref.Value) bool) { 168 if !f(typeFieldDesc, pref.ValueOfString(m.typeURL)) { 169 return 170 } 171 m.FieldRanger.Range(f) 172} 173 174// unpopulatedFieldRanger wraps a protoreflect.Message and modifies its Range 175// method to additionally iterate over unpopulated fields. 176type unpopulatedFieldRanger struct{ pref.Message } 177 178func (m unpopulatedFieldRanger) Range(f func(pref.FieldDescriptor, pref.Value) bool) { 179 fds := m.Descriptor().Fields() 180 for i := 0; i < fds.Len(); i++ { 181 fd := fds.Get(i) 182 if m.Has(fd) || fd.ContainingOneof() != nil { 183 continue // ignore populated fields and fields within a oneofs 184 } 185 186 v := m.Get(fd) 187 isProto2Scalar := fd.Syntax() == pref.Proto2 && fd.Default().IsValid() 188 isSingularMessage := fd.Cardinality() != pref.Repeated && fd.Message() != nil 189 if isProto2Scalar || isSingularMessage { 190 v = pref.Value{} // use invalid value to emit null 191 } 192 if !f(fd, v) { 193 return 194 } 195 } 196 m.Message.Range(f) 197} 198 199// marshalMessage marshals the fields in the given protoreflect.Message. 200// If the typeURL is non-empty, then a synthetic "@type" field is injected 201// containing the URL as the value. 202func (e encoder) marshalMessage(m pref.Message, typeURL string) error { 203 if !flags.ProtoLegacy && messageset.IsMessageSet(m.Descriptor()) { 204 return errors.New("no support for proto1 MessageSets") 205 } 206 207 if marshal := wellKnownTypeMarshaler(m.Descriptor().FullName()); marshal != nil { 208 return marshal(e, m) 209 } 210 211 e.StartObject() 212 defer e.EndObject() 213 214 var fields order.FieldRanger = m 215 if e.opts.EmitUnpopulated { 216 fields = unpopulatedFieldRanger{m} 217 } 218 if typeURL != "" { 219 fields = typeURLFieldRanger{fields, typeURL} 220 } 221 222 var err error 223 order.RangeFields(fields, order.IndexNameFieldOrder, func(fd pref.FieldDescriptor, v pref.Value) bool { 224 name := fd.JSONName() 225 if e.opts.UseProtoNames { 226 name = fd.TextName() 227 } 228 229 if err = e.WriteName(name); err != nil { 230 return false 231 } 232 if err = e.marshalValue(v, fd); err != nil { 233 return false 234 } 235 return true 236 }) 237 return err 238} 239 240// marshalValue marshals the given protoreflect.Value. 241func (e encoder) marshalValue(val pref.Value, fd pref.FieldDescriptor) error { 242 switch { 243 case fd.IsList(): 244 return e.marshalList(val.List(), fd) 245 case fd.IsMap(): 246 return e.marshalMap(val.Map(), fd) 247 default: 248 return e.marshalSingular(val, fd) 249 } 250} 251 252// marshalSingular marshals the given non-repeated field value. This includes 253// all scalar types, enums, messages, and groups. 254func (e encoder) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error { 255 if !val.IsValid() { 256 e.WriteNull() 257 return nil 258 } 259 260 switch kind := fd.Kind(); kind { 261 case pref.BoolKind: 262 e.WriteBool(val.Bool()) 263 264 case pref.StringKind: 265 if e.WriteString(val.String()) != nil { 266 return errors.InvalidUTF8(string(fd.FullName())) 267 } 268 269 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind: 270 e.WriteInt(val.Int()) 271 272 case pref.Uint32Kind, pref.Fixed32Kind: 273 e.WriteUint(val.Uint()) 274 275 case pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind, 276 pref.Sfixed64Kind, pref.Fixed64Kind: 277 // 64-bit integers are written out as JSON string. 278 e.WriteString(val.String()) 279 280 case pref.FloatKind: 281 // Encoder.WriteFloat handles the special numbers NaN and infinites. 282 e.WriteFloat(val.Float(), 32) 283 284 case pref.DoubleKind: 285 // Encoder.WriteFloat handles the special numbers NaN and infinites. 286 e.WriteFloat(val.Float(), 64) 287 288 case pref.BytesKind: 289 e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes())) 290 291 case pref.EnumKind: 292 if fd.Enum().FullName() == genid.NullValue_enum_fullname { 293 e.WriteNull() 294 } else { 295 desc := fd.Enum().Values().ByNumber(val.Enum()) 296 if e.opts.UseEnumNumbers || desc == nil { 297 e.WriteInt(int64(val.Enum())) 298 } else { 299 e.WriteString(string(desc.Name())) 300 } 301 } 302 303 case pref.MessageKind, pref.GroupKind: 304 if err := e.marshalMessage(val.Message(), ""); err != nil { 305 return err 306 } 307 308 default: 309 panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind)) 310 } 311 return nil 312} 313 314// marshalList marshals the given protoreflect.List. 315func (e encoder) marshalList(list pref.List, fd pref.FieldDescriptor) error { 316 e.StartArray() 317 defer e.EndArray() 318 319 for i := 0; i < list.Len(); i++ { 320 item := list.Get(i) 321 if err := e.marshalSingular(item, fd); err != nil { 322 return err 323 } 324 } 325 return nil 326} 327 328// marshalMap marshals given protoreflect.Map. 329func (e encoder) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error { 330 e.StartObject() 331 defer e.EndObject() 332 333 var err error 334 order.RangeEntries(mmap, order.GenericKeyOrder, func(k pref.MapKey, v pref.Value) bool { 335 if err = e.WriteName(k.String()); err != nil { 336 return false 337 } 338 if err = e.marshalSingular(v, fd.MapValue()); err != nil { 339 return false 340 } 341 return true 342 }) 343 return err 344} 345