blob: fa288971f7c9146548f52a2b2be097b69d8373ec [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"
13 "google.golang.org/protobuf/internal/errors"
14 "google.golang.org/protobuf/internal/pragma"
15 "google.golang.org/protobuf/proto"
16 pref "google.golang.org/protobuf/reflect/protoreflect"
17 "google.golang.org/protobuf/reflect/protoregistry"
Herbie Ong7b828bc2019-02-08 19:56:24 -080018)
19
20// Marshal writes the given proto.Message in JSON format using default options.
21func Marshal(m proto.Message) ([]byte, error) {
22 return MarshalOptions{}.Marshal(m)
23}
24
25// MarshalOptions is a configurable JSON format marshaler.
26type MarshalOptions struct {
27 pragma.NoUnkeyedLiterals
28
Herbie Ong329be5b2019-03-27 14:47:59 -070029 // AllowPartial allows messages that have missing required fields to marshal
30 // without returning an error. If AllowPartial is false (the default),
31 // Marshal will return error if there are any missing required fields.
32 AllowPartial bool
33
Herbie Ong0b0f4032019-03-18 19:06:15 -070034 // If Indent is a non-empty string, it causes entries for an Array or Object
35 // to be preceded by the indent and trailed by a newline. Indent can only be
36 // composed of space or tab characters.
37 Indent string
38
Joe Tsai1c283042019-05-14 14:28:19 -070039 // Resolver is used for looking up types when expanding google.protobuf.Any
40 // messages. If nil, this defaults to using protoregistry.GlobalTypes.
41 Resolver interface {
Damien Neil95faac22019-06-19 10:03:37 -070042 protoregistry.ExtensionTypeResolver
Joe Tsai1c283042019-05-14 14:28:19 -070043 protoregistry.MessageTypeResolver
44 }
Herbie Ong822de2d2019-03-27 13:16:23 -070045
46 encoder *json.Encoder
Herbie Ong7b828bc2019-02-08 19:56:24 -080047}
48
Herbie Ong0b0f4032019-03-18 19:06:15 -070049// Marshal marshals the given proto.Message in the JSON format using options in
50// MarshalOptions.
Herbie Ong7b828bc2019-02-08 19:56:24 -080051func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
Herbie Ong822de2d2019-03-27 13:16:23 -070052 var err error
53 o.encoder, err = json.NewEncoder(o.Indent)
Herbie Ong87608a72019-03-06 14:32:24 -080054 if err != nil {
55 return nil, err
56 }
Herbie Ong822de2d2019-03-27 13:16:23 -070057 if o.Resolver == nil {
58 o.Resolver = protoregistry.GlobalTypes
59 }
Herbie Ong87608a72019-03-06 14:32:24 -080060
61 var nerr errors.NonFatal
Herbie Ong822de2d2019-03-27 13:16:23 -070062 err = o.marshalMessage(m.ProtoReflect())
Herbie Ong7b828bc2019-02-08 19:56:24 -080063 if !nerr.Merge(err) {
64 return nil, err
65 }
Damien Neil4686e232019-04-05 13:31:40 -070066 if !o.AllowPartial {
67 nerr.Merge(proto.IsInitialized(m))
68 }
Herbie Ong822de2d2019-03-27 13:16:23 -070069 return o.encoder.Bytes(), nerr.E
Herbie Ong87608a72019-03-06 14:32:24 -080070}
71
72// marshalMessage marshals the given protoreflect.Message.
Herbie Ong822de2d2019-03-27 13:16:23 -070073func (o MarshalOptions) marshalMessage(m pref.Message) error {
Herbie Ong0b0f4032019-03-18 19:06:15 -070074 var nerr errors.NonFatal
75
Joe Tsai0fc49f82019-05-01 12:29:25 -070076 if isCustomType(m.Descriptor().FullName()) {
Herbie Ong822de2d2019-03-27 13:16:23 -070077 return o.marshalCustomType(m)
Herbie Ong0b0f4032019-03-18 19:06:15 -070078 }
79
Herbie Ong822de2d2019-03-27 13:16:23 -070080 o.encoder.StartObject()
81 defer o.encoder.EndObject()
82 if err := o.marshalFields(m); !nerr.Merge(err) {
Herbie Ong0b0f4032019-03-18 19:06:15 -070083 return err
84 }
Herbie Ong87608a72019-03-06 14:32:24 -080085
Herbie Ong0b0f4032019-03-18 19:06:15 -070086 return nerr.E
87}
88
89// marshalFields marshals the fields in the given protoreflect.Message.
Herbie Ong822de2d2019-03-27 13:16:23 -070090func (o MarshalOptions) marshalFields(m pref.Message) error {
Herbie Ong87608a72019-03-06 14:32:24 -080091 var nerr errors.NonFatal
Herbie Ong87608a72019-03-06 14:32:24 -080092
Herbie Ongf83d5bb2019-03-14 00:01:27 -070093 // Marshal out known fields.
Joe Tsai378c1322019-04-25 23:48:08 -070094 fieldDescs := m.Descriptor().Fields()
Herbie Ong87608a72019-03-06 14:32:24 -080095 for i := 0; i < fieldDescs.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -080096 fd := fieldDescs.Get(i)
Joe Tsai378c1322019-04-25 23:48:08 -070097 if !m.Has(fd) {
Herbie Ong7b828bc2019-02-08 19:56:24 -080098 continue
99 }
100
Herbie Ong87608a72019-03-06 14:32:24 -0800101 name := fd.JSONName()
Joe Tsai378c1322019-04-25 23:48:08 -0700102 val := m.Get(fd)
Herbie Ong822de2d2019-03-27 13:16:23 -0700103 if err := o.encoder.WriteName(name); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800104 return err
105 }
Herbie Ong822de2d2019-03-27 13:16:23 -0700106 if err := o.marshalValue(val, fd); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800107 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800108 }
109 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700110
111 // Marshal out extensions.
Joe Tsai378c1322019-04-25 23:48:08 -0700112 if err := o.marshalExtensions(m); !nerr.Merge(err) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700113 return err
114 }
Herbie Ong87608a72019-03-06 14:32:24 -0800115 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800116}
117
Herbie Ong87608a72019-03-06 14:32:24 -0800118// marshalValue marshals the given protoreflect.Value.
Herbie Ong822de2d2019-03-27 13:16:23 -0700119func (o MarshalOptions) marshalValue(val pref.Value, fd pref.FieldDescriptor) error {
Joe Tsaiac31a352019-05-13 14:32:56 -0700120 switch {
121 case fd.IsList():
122 return o.marshalList(val.List(), fd)
123 case fd.IsMap():
124 return o.marshalMap(val.Map(), fd)
125 default:
126 return o.marshalSingular(val, fd)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800127 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800128}
129
Herbie Ong87608a72019-03-06 14:32:24 -0800130// marshalSingular marshals the given non-repeated field value. This includes
131// all scalar types, enums, messages, and groups.
Herbie Ong822de2d2019-03-27 13:16:23 -0700132func (o MarshalOptions) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
Herbie Ong87608a72019-03-06 14:32:24 -0800133 var nerr errors.NonFatal
134 switch kind := fd.Kind(); kind {
135 case pref.BoolKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700136 o.encoder.WriteBool(val.Bool())
Herbie Ong87608a72019-03-06 14:32:24 -0800137
138 case pref.StringKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700139 if err := o.encoder.WriteString(val.String()); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800140 return err
141 }
142
143 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700144 o.encoder.WriteInt(val.Int())
Herbie Ong87608a72019-03-06 14:32:24 -0800145
146 case pref.Uint32Kind, pref.Fixed32Kind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700147 o.encoder.WriteUint(val.Uint())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800148
149 case pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind,
150 pref.Sfixed64Kind, pref.Fixed64Kind:
Herbie Ong87608a72019-03-06 14:32:24 -0800151 // 64-bit integers are written out as JSON string.
Herbie Ong822de2d2019-03-27 13:16:23 -0700152 o.encoder.WriteString(val.String())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800153
Herbie Ong87608a72019-03-06 14:32:24 -0800154 case pref.FloatKind:
155 // Encoder.WriteFloat handles the special numbers NaN and infinites.
Herbie Ong822de2d2019-03-27 13:16:23 -0700156 o.encoder.WriteFloat(val.Float(), 32)
Herbie Ong87608a72019-03-06 14:32:24 -0800157
158 case pref.DoubleKind:
159 // Encoder.WriteFloat handles the special numbers NaN and infinites.
Herbie Ong822de2d2019-03-27 13:16:23 -0700160 o.encoder.WriteFloat(val.Float(), 64)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800161
162 case pref.BytesKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700163 err := o.encoder.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
Herbie Ong87608a72019-03-06 14:32:24 -0800164 if !nerr.Merge(err) {
165 return err
166 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800167
168 case pref.EnumKind:
Joe Tsaid24bc722019-04-15 23:39:09 -0700169 if fd.Enum().FullName() == "google.protobuf.NullValue" {
Herbie Ong822de2d2019-03-27 13:16:23 -0700170 o.encoder.WriteNull()
Joe Tsaid24bc722019-04-15 23:39:09 -0700171 } else if desc := fd.Enum().Values().ByNumber(val.Enum()); desc != nil {
Herbie Ong822de2d2019-03-27 13:16:23 -0700172 err := o.encoder.WriteString(string(desc.Name()))
Herbie Ong87608a72019-03-06 14:32:24 -0800173 if !nerr.Merge(err) {
174 return err
175 }
176 } else {
177 // Use numeric value if there is no enum value descriptor.
Joe Tsaid24bc722019-04-15 23:39:09 -0700178 o.encoder.WriteInt(int64(val.Enum()))
Herbie Ong7b828bc2019-02-08 19:56:24 -0800179 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800180
181 case pref.MessageKind, pref.GroupKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700182 if err := o.marshalMessage(val.Message()); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800183 return err
184 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800185
Herbie Ong87608a72019-03-06 14:32:24 -0800186 default:
Herbie Ong0b0f4032019-03-18 19:06:15 -0700187 panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
Herbie Ong87608a72019-03-06 14:32:24 -0800188 }
189 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800190}
191
Herbie Ong87608a72019-03-06 14:32:24 -0800192// marshalList marshals the given protoreflect.List.
Herbie Ong822de2d2019-03-27 13:16:23 -0700193func (o MarshalOptions) marshalList(list pref.List, fd pref.FieldDescriptor) error {
194 o.encoder.StartArray()
195 defer o.encoder.EndArray()
Herbie Ong87608a72019-03-06 14:32:24 -0800196
Herbie Ong7b828bc2019-02-08 19:56:24 -0800197 var nerr errors.NonFatal
Herbie Ong87608a72019-03-06 14:32:24 -0800198 for i := 0; i < list.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800199 item := list.Get(i)
Herbie Ong822de2d2019-03-27 13:16:23 -0700200 if err := o.marshalSingular(item, fd); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800201 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800202 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800203 }
Herbie Ong87608a72019-03-06 14:32:24 -0800204 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800205}
206
207type mapEntry struct {
208 key pref.MapKey
209 value pref.Value
210}
211
Herbie Ong87608a72019-03-06 14:32:24 -0800212// marshalMap marshals given protoreflect.Map.
Herbie Ong822de2d2019-03-27 13:16:23 -0700213func (o MarshalOptions) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
214 o.encoder.StartObject()
215 defer o.encoder.EndObject()
Herbie Ong87608a72019-03-06 14:32:24 -0800216
Herbie Ong7b828bc2019-02-08 19:56:24 -0800217 // Get a sorted list based on keyType first.
218 entries := make([]mapEntry, 0, mmap.Len())
219 mmap.Range(func(key pref.MapKey, val pref.Value) bool {
220 entries = append(entries, mapEntry{key: key, value: val})
221 return true
222 })
Joe Tsaiac31a352019-05-13 14:32:56 -0700223 sortMap(fd.MapKey().Kind(), entries)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800224
Herbie Ong87608a72019-03-06 14:32:24 -0800225 // Write out sorted list.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800226 var nerr errors.NonFatal
Herbie Ong7b828bc2019-02-08 19:56:24 -0800227 for _, entry := range entries {
Herbie Ong822de2d2019-03-27 13:16:23 -0700228 if err := o.encoder.WriteName(entry.key.String()); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800229 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800230 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700231 if err := o.marshalSingular(entry.value, fd.MapValue()); !nerr.Merge(err) {
Herbie Ong87608a72019-03-06 14:32:24 -0800232 return err
233 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800234 }
Herbie Ong87608a72019-03-06 14:32:24 -0800235 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800236}
237
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700238// sortMap orders list based on value of key field for deterministic ordering.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800239func sortMap(keyKind pref.Kind, values []mapEntry) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700240 sort.Slice(values, func(i, j int) bool {
241 switch keyKind {
242 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind,
243 pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800244 return values[i].key.Int() < values[j].key.Int()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700245
246 case pref.Uint32Kind, pref.Fixed32Kind,
247 pref.Uint64Kind, pref.Fixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800248 return values[i].key.Uint() < values[j].key.Uint()
249 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700250 return values[i].key.String() < values[j].key.String()
251 })
252}
253
254// marshalExtensions marshals extension fields.
Joe Tsai378c1322019-04-25 23:48:08 -0700255func (o MarshalOptions) marshalExtensions(m pref.Message) error {
256 type entry struct {
257 key string
258 value pref.Value
259 desc pref.FieldDescriptor
Herbie Ong7b828bc2019-02-08 19:56:24 -0800260 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700261
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700262 // Get a sorted list based on field key first.
Joe Tsai378c1322019-04-25 23:48:08 -0700263 var entries []entry
264 m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
265 if !fd.IsExtension() {
266 return true
267 }
268 xt := fd.(pref.ExtensionType)
269
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700270 // If extended type is a MessageSet, set field name to be the message type name.
Joe Tsai378c1322019-04-25 23:48:08 -0700271 name := xt.Descriptor().FullName()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700272 if isMessageSetExtension(xt) {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700273 name = xt.Descriptor().Message().FullName()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700274 }
275
Joe Tsai378c1322019-04-25 23:48:08 -0700276 // Use [name] format for JSON field name.
277 entries = append(entries, entry{
278 key: string(name),
279 value: v,
280 desc: fd,
281 })
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700282 return true
283 })
284
285 // Sort extensions lexicographically.
286 sort.Slice(entries, func(i, j int) bool {
287 return entries[i].key < entries[j].key
288 })
289
290 // Write out sorted list.
291 var nerr errors.NonFatal
292 for _, entry := range entries {
293 // JSON field name is the proto field name enclosed in [], similar to
294 // textproto. This is consistent with Go v1 lib. C++ lib v3.7.0 does not
295 // marshal out extension fields.
Herbie Ong822de2d2019-03-27 13:16:23 -0700296 if err := o.encoder.WriteName("[" + entry.key + "]"); !nerr.Merge(err) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700297 return err
298 }
Joe Tsai378c1322019-04-25 23:48:08 -0700299 if err := o.marshalValue(entry.value, entry.desc); !nerr.Merge(err) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700300 return err
301 }
302 }
303 return nerr.E
304}
305
306// isMessageSetExtension reports whether extension extends a message set.
307func isMessageSetExtension(xt pref.ExtensionType) bool {
Joe Tsai0fc49f82019-05-01 12:29:25 -0700308 xd := xt.Descriptor()
309 if xd.Name() != "message_set_extension" {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700310 return false
311 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700312 md := xd.Message()
Joe Tsaid24bc722019-04-15 23:39:09 -0700313 if md == nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700314 return false
315 }
Joe Tsai0fc49f82019-05-01 12:29:25 -0700316 if xd.FullName().Parent() != md.FullName() {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700317 return false
318 }
Joe Tsaiac31a352019-05-13 14:32:56 -0700319 xmd, ok := xd.ContainingMessage().(interface{ IsMessageSet() bool })
Joe Tsaid24bc722019-04-15 23:39:09 -0700320 return ok && xmd.IsMessageSet()
Herbie Ong7b828bc2019-02-08 19:56:24 -0800321}