blob: 5f383fe1023d3c2f19a172e20ab0720c9a36fe97 [file] [log] [blame]
Herbie Ong7b828bc2019-02-08 19:56:24 -08001// 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
Damien Neil5c5b5312019-05-14 12:44:37 -07005package protojson
Herbie Ong7b828bc2019-02-08 19:56:24 -08006
7import (
8 "encoding/base64"
Herbie Ong0b0f4032019-03-18 19:06:15 -07009 "fmt"
Herbie Ong7b828bc2019-02-08 19:56:24 -080010 "sort"
11
Damien Neile89e6242019-05-13 23:55:40 -070012 "google.golang.org/protobuf/internal/encoding/json"
Joe Tsai5ae10aa2019-07-11 18:23:08 -070013 "google.golang.org/protobuf/internal/encoding/messageset"
14 "google.golang.org/protobuf/internal/errors"
15 "google.golang.org/protobuf/internal/flags"
Damien Neile89e6242019-05-13 23:55:40 -070016 "google.golang.org/protobuf/internal/pragma"
17 "google.golang.org/protobuf/proto"
18 pref "google.golang.org/protobuf/reflect/protoreflect"
19 "google.golang.org/protobuf/reflect/protoregistry"
Herbie Ong7b828bc2019-02-08 19:56:24 -080020)
21
22// Marshal writes the given proto.Message in JSON format using default options.
Herbie Ong582ab3d2019-09-06 15:56:09 -070023// Do not depend on the output of being stable. It may change over time across
24// different versions of the program.
Herbie Ong7b828bc2019-02-08 19:56:24 -080025func Marshal(m proto.Message) ([]byte, error) {
26 return MarshalOptions{}.Marshal(m)
27}
28
29// MarshalOptions is a configurable JSON format marshaler.
30type MarshalOptions struct {
31 pragma.NoUnkeyedLiterals
Herbie Ong984e5282019-09-06 00:29:48 -070032 encoder *json.Encoder
Herbie Ong7b828bc2019-02-08 19:56:24 -080033
Herbie Ong329be5b2019-03-27 14:47:59 -070034 // AllowPartial allows messages that have missing required fields to marshal
35 // without returning an error. If AllowPartial is false (the default),
36 // Marshal will return error if there are any missing required fields.
37 AllowPartial bool
38
Herbie Ong956cd6d2019-09-06 15:17:22 -070039 // UseProtoNames uses proto field name instead of lowerCamelCase name in JSON
40 // field names.
41 UseProtoNames bool
42
Herbie Ong9111f3b2019-09-06 14:35:09 -070043 // UseEnumNumbers emits enum values as numbers.
44 UseEnumNumbers bool
45
Herbie Ong984e5282019-09-06 00:29:48 -070046 // EmitUnpopulated specifies whether to emit unpopulated fields. It does not
47 // emit unpopulated oneof fields or unpopulated extension fields.
48 // The JSON value emitted for unpopulated fields are as follows:
Herbie Ong956cd6d2019-09-06 15:17:22 -070049 // ╔═══════╤════════════════════════════╗
50 // ║ JSON │ Protobuf field ║
51 // ╠═══════╪════════════════════════════╣
52 // ║ false │ proto3 boolean fields ║
53 // ║ 0 │ proto3 numeric fields ║
54 // ║ "" │ proto3 string/bytes fields ║
55 // ║ null │ proto2 scalar fields ║
56 // ║ null │ message fields ║
57 // ║ [] │ list fields ║
58 // ║ {} │ map fields ║
59 // ╚═══════╧════════════════════════════╝
Herbie Ong984e5282019-09-06 00:29:48 -070060 EmitUnpopulated bool
61
Herbie Ong0b0f4032019-03-18 19:06:15 -070062 // If Indent is a non-empty string, it causes entries for an Array or Object
63 // to be preceded by the indent and trailed by a newline. Indent can only be
64 // composed of space or tab characters.
65 Indent string
66
Joe Tsai1c283042019-05-14 14:28:19 -070067 // Resolver is used for looking up types when expanding google.protobuf.Any
68 // messages. If nil, this defaults to using protoregistry.GlobalTypes.
69 Resolver interface {
Damien Neil95faac22019-06-19 10:03:37 -070070 protoregistry.ExtensionTypeResolver
Joe Tsai1c283042019-05-14 14:28:19 -070071 protoregistry.MessageTypeResolver
72 }
Herbie Ong7b828bc2019-02-08 19:56:24 -080073}
74
Herbie Ong0b0f4032019-03-18 19:06:15 -070075// Marshal marshals the given proto.Message in the JSON format using options in
Herbie Ong582ab3d2019-09-06 15:56:09 -070076// MarshalOptions. Do not depend on the output being stable. It may change over
77// time across different versions of the program.
Herbie Ong7b828bc2019-02-08 19:56:24 -080078func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
Herbie Ong822de2d2019-03-27 13:16:23 -070079 var err error
80 o.encoder, err = json.NewEncoder(o.Indent)
Herbie Ong87608a72019-03-06 14:32:24 -080081 if err != nil {
82 return nil, err
83 }
Herbie Ong822de2d2019-03-27 13:16:23 -070084 if o.Resolver == nil {
85 o.Resolver = protoregistry.GlobalTypes
86 }
Herbie Ong87608a72019-03-06 14:32:24 -080087
Herbie Ong822de2d2019-03-27 13:16:23 -070088 err = o.marshalMessage(m.ProtoReflect())
Damien Neil8c86fc52019-06-19 09:28:29 -070089 if err != nil {
Herbie Ong7b828bc2019-02-08 19:56:24 -080090 return nil, err
91 }
Damien Neil8c86fc52019-06-19 09:28:29 -070092 if o.AllowPartial {
93 return o.encoder.Bytes(), nil
Damien Neil4686e232019-04-05 13:31:40 -070094 }
Damien Neil8c86fc52019-06-19 09:28:29 -070095 return o.encoder.Bytes(), proto.IsInitialized(m)
Herbie Ong87608a72019-03-06 14:32:24 -080096}
97
98// marshalMessage marshals the given protoreflect.Message.
Herbie Ong822de2d2019-03-27 13:16:23 -070099func (o MarshalOptions) marshalMessage(m pref.Message) error {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700100 if isCustomType(m.Descriptor().FullName()) {
Herbie Ong822de2d2019-03-27 13:16:23 -0700101 return o.marshalCustomType(m)
Herbie Ong0b0f4032019-03-18 19:06:15 -0700102 }
103
Herbie Ong822de2d2019-03-27 13:16:23 -0700104 o.encoder.StartObject()
105 defer o.encoder.EndObject()
Damien Neil8c86fc52019-06-19 09:28:29 -0700106 if err := o.marshalFields(m); err != nil {
Herbie Ong0b0f4032019-03-18 19:06:15 -0700107 return err
108 }
Herbie Ong87608a72019-03-06 14:32:24 -0800109
Damien Neil8c86fc52019-06-19 09:28:29 -0700110 return nil
Herbie Ong0b0f4032019-03-18 19:06:15 -0700111}
112
113// marshalFields marshals the fields in the given protoreflect.Message.
Herbie Ong822de2d2019-03-27 13:16:23 -0700114func (o MarshalOptions) marshalFields(m pref.Message) error {
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700115 messageDesc := m.Descriptor()
Joe Tsai1799d112019-08-08 13:31:59 -0700116 if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700117 return errors.New("no support for proto1 MessageSets")
118 }
119
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700120 // Marshal out known fields.
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700121 fieldDescs := messageDesc.Fields()
Herbie Ong87608a72019-03-06 14:32:24 -0800122 for i := 0; i < fieldDescs.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800123 fd := fieldDescs.Get(i)
Herbie Ong984e5282019-09-06 00:29:48 -0700124 val := m.Get(fd)
Joe Tsai378c1322019-04-25 23:48:08 -0700125 if !m.Has(fd) {
Herbie Ong984e5282019-09-06 00:29:48 -0700126 if !o.EmitUnpopulated || fd.ContainingOneof() != nil {
127 continue
128 }
129 isProto2Scalar := fd.Syntax() == pref.Proto2 && fd.Default().IsValid()
130 isSingularMessage := fd.Cardinality() != pref.Repeated && fd.Message() != nil
131 if isProto2Scalar || isSingularMessage {
132 // Use invalid value to emit null.
133 val = pref.Value{}
134 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800135 }
136
Herbie Ong87608a72019-03-06 14:32:24 -0800137 name := fd.JSONName()
Herbie Ong956cd6d2019-09-06 15:17:22 -0700138 if o.UseProtoNames {
139 name = string(fd.Name())
140 // Use type name for group field name.
141 if fd.Kind() == pref.GroupKind {
142 name = string(fd.Message().Name())
143 }
144 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700145 if err := o.encoder.WriteName(name); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800146 return err
147 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700148 if err := o.marshalValue(val, fd); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800149 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800150 }
151 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700152
153 // Marshal out extensions.
Damien Neil8c86fc52019-06-19 09:28:29 -0700154 if err := o.marshalExtensions(m); err != nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700155 return err
156 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700157 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800158}
159
Herbie Ong87608a72019-03-06 14:32:24 -0800160// marshalValue marshals the given protoreflect.Value.
Herbie Ong822de2d2019-03-27 13:16:23 -0700161func (o MarshalOptions) marshalValue(val pref.Value, fd pref.FieldDescriptor) error {
Joe Tsaiac31a352019-05-13 14:32:56 -0700162 switch {
163 case fd.IsList():
164 return o.marshalList(val.List(), fd)
165 case fd.IsMap():
166 return o.marshalMap(val.Map(), fd)
167 default:
168 return o.marshalSingular(val, fd)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800169 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800170}
171
Herbie Ong87608a72019-03-06 14:32:24 -0800172// marshalSingular marshals the given non-repeated field value. This includes
173// all scalar types, enums, messages, and groups.
Herbie Ong822de2d2019-03-27 13:16:23 -0700174func (o MarshalOptions) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
Herbie Ong984e5282019-09-06 00:29:48 -0700175 if !val.IsValid() {
176 o.encoder.WriteNull()
177 return nil
178 }
179
Herbie Ong87608a72019-03-06 14:32:24 -0800180 switch kind := fd.Kind(); kind {
181 case pref.BoolKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700182 o.encoder.WriteBool(val.Bool())
Herbie Ong87608a72019-03-06 14:32:24 -0800183
184 case pref.StringKind:
Damien Neil8c86fc52019-06-19 09:28:29 -0700185 if err := o.encoder.WriteString(val.String()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800186 return err
187 }
188
189 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700190 o.encoder.WriteInt(val.Int())
Herbie Ong87608a72019-03-06 14:32:24 -0800191
192 case pref.Uint32Kind, pref.Fixed32Kind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700193 o.encoder.WriteUint(val.Uint())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800194
195 case pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind,
196 pref.Sfixed64Kind, pref.Fixed64Kind:
Herbie Ong87608a72019-03-06 14:32:24 -0800197 // 64-bit integers are written out as JSON string.
Herbie Ong822de2d2019-03-27 13:16:23 -0700198 o.encoder.WriteString(val.String())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800199
Herbie Ong87608a72019-03-06 14:32:24 -0800200 case pref.FloatKind:
201 // Encoder.WriteFloat handles the special numbers NaN and infinites.
Herbie Ong822de2d2019-03-27 13:16:23 -0700202 o.encoder.WriteFloat(val.Float(), 32)
Herbie Ong87608a72019-03-06 14:32:24 -0800203
204 case pref.DoubleKind:
205 // Encoder.WriteFloat handles the special numbers NaN and infinites.
Herbie Ong822de2d2019-03-27 13:16:23 -0700206 o.encoder.WriteFloat(val.Float(), 64)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800207
208 case pref.BytesKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700209 err := o.encoder.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
Damien Neil8c86fc52019-06-19 09:28:29 -0700210 if err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800211 return err
212 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800213
214 case pref.EnumKind:
Joe Tsaid24bc722019-04-15 23:39:09 -0700215 if fd.Enum().FullName() == "google.protobuf.NullValue" {
Herbie Ong822de2d2019-03-27 13:16:23 -0700216 o.encoder.WriteNull()
Herbie Ong87608a72019-03-06 14:32:24 -0800217 } else {
Herbie Ong9111f3b2019-09-06 14:35:09 -0700218 desc := fd.Enum().Values().ByNumber(val.Enum())
219 if o.UseEnumNumbers || desc == nil {
220 o.encoder.WriteInt(int64(val.Enum()))
221 } else {
222 err := o.encoder.WriteString(string(desc.Name()))
223 if err != nil {
224 return err
225 }
226 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800227 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800228
229 case pref.MessageKind, pref.GroupKind:
Damien Neil8c86fc52019-06-19 09:28:29 -0700230 if err := o.marshalMessage(val.Message()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800231 return err
232 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800233
Herbie Ong87608a72019-03-06 14:32:24 -0800234 default:
Herbie Ong0b0f4032019-03-18 19:06:15 -0700235 panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
Herbie Ong87608a72019-03-06 14:32:24 -0800236 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700237 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800238}
239
Herbie Ong87608a72019-03-06 14:32:24 -0800240// marshalList marshals the given protoreflect.List.
Herbie Ong822de2d2019-03-27 13:16:23 -0700241func (o MarshalOptions) marshalList(list pref.List, fd pref.FieldDescriptor) error {
242 o.encoder.StartArray()
243 defer o.encoder.EndArray()
Herbie Ong87608a72019-03-06 14:32:24 -0800244
Herbie Ong87608a72019-03-06 14:32:24 -0800245 for i := 0; i < list.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800246 item := list.Get(i)
Damien Neil8c86fc52019-06-19 09:28:29 -0700247 if err := o.marshalSingular(item, fd); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800248 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800249 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800250 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700251 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800252}
253
254type mapEntry struct {
255 key pref.MapKey
256 value pref.Value
257}
258
Herbie Ong87608a72019-03-06 14:32:24 -0800259// marshalMap marshals given protoreflect.Map.
Herbie Ong822de2d2019-03-27 13:16:23 -0700260func (o MarshalOptions) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
261 o.encoder.StartObject()
262 defer o.encoder.EndObject()
Herbie Ong87608a72019-03-06 14:32:24 -0800263
Herbie Ong7b828bc2019-02-08 19:56:24 -0800264 // Get a sorted list based on keyType first.
265 entries := make([]mapEntry, 0, mmap.Len())
266 mmap.Range(func(key pref.MapKey, val pref.Value) bool {
267 entries = append(entries, mapEntry{key: key, value: val})
268 return true
269 })
Joe Tsaiac31a352019-05-13 14:32:56 -0700270 sortMap(fd.MapKey().Kind(), entries)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800271
Herbie Ong87608a72019-03-06 14:32:24 -0800272 // Write out sorted list.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800273 for _, entry := range entries {
Damien Neil8c86fc52019-06-19 09:28:29 -0700274 if err := o.encoder.WriteName(entry.key.String()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800275 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800276 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700277 if err := o.marshalSingular(entry.value, fd.MapValue()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800278 return err
279 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800280 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700281 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800282}
283
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700284// sortMap orders list based on value of key field for deterministic ordering.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800285func sortMap(keyKind pref.Kind, values []mapEntry) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700286 sort.Slice(values, func(i, j int) bool {
287 switch keyKind {
288 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind,
289 pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800290 return values[i].key.Int() < values[j].key.Int()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700291
292 case pref.Uint32Kind, pref.Fixed32Kind,
293 pref.Uint64Kind, pref.Fixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800294 return values[i].key.Uint() < values[j].key.Uint()
295 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700296 return values[i].key.String() < values[j].key.String()
297 })
298}
299
300// marshalExtensions marshals extension fields.
Joe Tsai378c1322019-04-25 23:48:08 -0700301func (o MarshalOptions) marshalExtensions(m pref.Message) error {
302 type entry struct {
303 key string
304 value pref.Value
305 desc pref.FieldDescriptor
Herbie Ong7b828bc2019-02-08 19:56:24 -0800306 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700307
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700308 // Get a sorted list based on field key first.
Joe Tsai378c1322019-04-25 23:48:08 -0700309 var entries []entry
310 m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
311 if !fd.IsExtension() {
312 return true
313 }
Joe Tsai378c1322019-04-25 23:48:08 -0700314
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700315 // For MessageSet extensions, the name used is the parent message.
Joe Tsaid4211502019-07-02 14:58:02 -0700316 name := fd.FullName()
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700317 if messageset.IsMessageSetExtension(fd) {
318 name = name.Parent()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700319 }
320
Joe Tsai378c1322019-04-25 23:48:08 -0700321 // Use [name] format for JSON field name.
322 entries = append(entries, entry{
323 key: string(name),
324 value: v,
325 desc: fd,
326 })
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700327 return true
328 })
329
330 // Sort extensions lexicographically.
331 sort.Slice(entries, func(i, j int) bool {
332 return entries[i].key < entries[j].key
333 })
334
335 // Write out sorted list.
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700336 for _, entry := range entries {
337 // JSON field name is the proto field name enclosed in [], similar to
338 // textproto. This is consistent with Go v1 lib. C++ lib v3.7.0 does not
339 // marshal out extension fields.
Damien Neil8c86fc52019-06-19 09:28:29 -0700340 if err := o.encoder.WriteName("[" + entry.key + "]"); err != nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700341 return err
342 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700343 if err := o.marshalValue(entry.value, entry.desc); err != nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700344 return err
345 }
346 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700347 return nil
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700348}