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