blob: 839c7d1df139838246a5a6c7ab7d05dce91f3991 [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.
23func Marshal(m proto.Message) ([]byte, error) {
24 return MarshalOptions{}.Marshal(m)
25}
26
27// MarshalOptions is a configurable JSON format marshaler.
28type MarshalOptions struct {
29 pragma.NoUnkeyedLiterals
30
Herbie Ong329be5b2019-03-27 14:47:59 -070031 // AllowPartial allows messages that have missing required fields to marshal
32 // without returning an error. If AllowPartial is false (the default),
33 // Marshal will return error if there are any missing required fields.
34 AllowPartial bool
35
Herbie Ong0b0f4032019-03-18 19:06:15 -070036 // If Indent is a non-empty string, it causes entries for an Array or Object
37 // to be preceded by the indent and trailed by a newline. Indent can only be
38 // composed of space or tab characters.
39 Indent string
40
Joe Tsai1c283042019-05-14 14:28:19 -070041 // Resolver is used for looking up types when expanding google.protobuf.Any
42 // messages. If nil, this defaults to using protoregistry.GlobalTypes.
43 Resolver interface {
Damien Neil95faac22019-06-19 10:03:37 -070044 protoregistry.ExtensionTypeResolver
Joe Tsai1c283042019-05-14 14:28:19 -070045 protoregistry.MessageTypeResolver
46 }
Herbie Ong822de2d2019-03-27 13:16:23 -070047
48 encoder *json.Encoder
Herbie Ong7b828bc2019-02-08 19:56:24 -080049}
50
Herbie Ong0b0f4032019-03-18 19:06:15 -070051// Marshal marshals the given proto.Message in the JSON format using options in
52// MarshalOptions.
Herbie Ong7b828bc2019-02-08 19:56:24 -080053func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
Herbie Ong822de2d2019-03-27 13:16:23 -070054 var err error
55 o.encoder, err = json.NewEncoder(o.Indent)
Herbie Ong87608a72019-03-06 14:32:24 -080056 if err != nil {
57 return nil, err
58 }
Herbie Ong822de2d2019-03-27 13:16:23 -070059 if o.Resolver == nil {
60 o.Resolver = protoregistry.GlobalTypes
61 }
Herbie Ong87608a72019-03-06 14:32:24 -080062
Herbie Ong822de2d2019-03-27 13:16:23 -070063 err = o.marshalMessage(m.ProtoReflect())
Damien Neil8c86fc52019-06-19 09:28:29 -070064 if err != nil {
Herbie Ong7b828bc2019-02-08 19:56:24 -080065 return nil, err
66 }
Damien Neil8c86fc52019-06-19 09:28:29 -070067 if o.AllowPartial {
68 return o.encoder.Bytes(), nil
Damien Neil4686e232019-04-05 13:31:40 -070069 }
Damien Neil8c86fc52019-06-19 09:28:29 -070070 return o.encoder.Bytes(), proto.IsInitialized(m)
Herbie Ong87608a72019-03-06 14:32:24 -080071}
72
73// marshalMessage marshals the given protoreflect.Message.
Herbie Ong822de2d2019-03-27 13:16:23 -070074func (o MarshalOptions) marshalMessage(m pref.Message) error {
Joe Tsai0fc49f82019-05-01 12:29:25 -070075 if isCustomType(m.Descriptor().FullName()) {
Herbie Ong822de2d2019-03-27 13:16:23 -070076 return o.marshalCustomType(m)
Herbie Ong0b0f4032019-03-18 19:06:15 -070077 }
78
Herbie Ong822de2d2019-03-27 13:16:23 -070079 o.encoder.StartObject()
80 defer o.encoder.EndObject()
Damien Neil8c86fc52019-06-19 09:28:29 -070081 if err := o.marshalFields(m); err != nil {
Herbie Ong0b0f4032019-03-18 19:06:15 -070082 return err
83 }
Herbie Ong87608a72019-03-06 14:32:24 -080084
Damien Neil8c86fc52019-06-19 09:28:29 -070085 return nil
Herbie Ong0b0f4032019-03-18 19:06:15 -070086}
87
88// marshalFields marshals the fields in the given protoreflect.Message.
Herbie Ong822de2d2019-03-27 13:16:23 -070089func (o MarshalOptions) marshalFields(m pref.Message) error {
Joe Tsai5ae10aa2019-07-11 18:23:08 -070090 messageDesc := m.Descriptor()
Joe Tsai1799d112019-08-08 13:31:59 -070091 if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
Joe Tsai5ae10aa2019-07-11 18:23:08 -070092 return errors.New("no support for proto1 MessageSets")
93 }
94
Herbie Ongf83d5bb2019-03-14 00:01:27 -070095 // Marshal out known fields.
Joe Tsai5ae10aa2019-07-11 18:23:08 -070096 fieldDescs := messageDesc.Fields()
Herbie Ong87608a72019-03-06 14:32:24 -080097 for i := 0; i < fieldDescs.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -080098 fd := fieldDescs.Get(i)
Joe Tsai378c1322019-04-25 23:48:08 -070099 if !m.Has(fd) {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800100 continue
101 }
102
Herbie Ong87608a72019-03-06 14:32:24 -0800103 name := fd.JSONName()
Joe Tsai378c1322019-04-25 23:48:08 -0700104 val := m.Get(fd)
Damien Neil8c86fc52019-06-19 09:28:29 -0700105 if err := o.encoder.WriteName(name); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800106 return err
107 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700108 if err := o.marshalValue(val, fd); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800109 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800110 }
111 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700112
113 // Marshal out extensions.
Damien Neil8c86fc52019-06-19 09:28:29 -0700114 if err := o.marshalExtensions(m); err != nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700115 return err
116 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700117 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800118}
119
Herbie Ong87608a72019-03-06 14:32:24 -0800120// marshalValue marshals the given protoreflect.Value.
Herbie Ong822de2d2019-03-27 13:16:23 -0700121func (o MarshalOptions) marshalValue(val pref.Value, fd pref.FieldDescriptor) error {
Joe Tsaiac31a352019-05-13 14:32:56 -0700122 switch {
123 case fd.IsList():
124 return o.marshalList(val.List(), fd)
125 case fd.IsMap():
126 return o.marshalMap(val.Map(), fd)
127 default:
128 return o.marshalSingular(val, fd)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800129 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800130}
131
Herbie Ong87608a72019-03-06 14:32:24 -0800132// marshalSingular marshals the given non-repeated field value. This includes
133// all scalar types, enums, messages, and groups.
Herbie Ong822de2d2019-03-27 13:16:23 -0700134func (o MarshalOptions) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
Herbie Ong87608a72019-03-06 14:32:24 -0800135 switch kind := fd.Kind(); kind {
136 case pref.BoolKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700137 o.encoder.WriteBool(val.Bool())
Herbie Ong87608a72019-03-06 14:32:24 -0800138
139 case pref.StringKind:
Damien Neil8c86fc52019-06-19 09:28:29 -0700140 if err := o.encoder.WriteString(val.String()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800141 return err
142 }
143
144 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700145 o.encoder.WriteInt(val.Int())
Herbie Ong87608a72019-03-06 14:32:24 -0800146
147 case pref.Uint32Kind, pref.Fixed32Kind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700148 o.encoder.WriteUint(val.Uint())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800149
150 case pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind,
151 pref.Sfixed64Kind, pref.Fixed64Kind:
Herbie Ong87608a72019-03-06 14:32:24 -0800152 // 64-bit integers are written out as JSON string.
Herbie Ong822de2d2019-03-27 13:16:23 -0700153 o.encoder.WriteString(val.String())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800154
Herbie Ong87608a72019-03-06 14:32:24 -0800155 case pref.FloatKind:
156 // Encoder.WriteFloat handles the special numbers NaN and infinites.
Herbie Ong822de2d2019-03-27 13:16:23 -0700157 o.encoder.WriteFloat(val.Float(), 32)
Herbie Ong87608a72019-03-06 14:32:24 -0800158
159 case pref.DoubleKind:
160 // Encoder.WriteFloat handles the special numbers NaN and infinites.
Herbie Ong822de2d2019-03-27 13:16:23 -0700161 o.encoder.WriteFloat(val.Float(), 64)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800162
163 case pref.BytesKind:
Herbie Ong822de2d2019-03-27 13:16:23 -0700164 err := o.encoder.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
Damien Neil8c86fc52019-06-19 09:28:29 -0700165 if err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800166 return err
167 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800168
169 case pref.EnumKind:
Joe Tsaid24bc722019-04-15 23:39:09 -0700170 if fd.Enum().FullName() == "google.protobuf.NullValue" {
Herbie Ong822de2d2019-03-27 13:16:23 -0700171 o.encoder.WriteNull()
Joe Tsaid24bc722019-04-15 23:39:09 -0700172 } else if desc := fd.Enum().Values().ByNumber(val.Enum()); desc != nil {
Herbie Ong822de2d2019-03-27 13:16:23 -0700173 err := o.encoder.WriteString(string(desc.Name()))
Damien Neil8c86fc52019-06-19 09:28:29 -0700174 if err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800175 return err
176 }
177 } else {
178 // Use numeric value if there is no enum value descriptor.
Joe Tsaid24bc722019-04-15 23:39:09 -0700179 o.encoder.WriteInt(int64(val.Enum()))
Herbie Ong7b828bc2019-02-08 19:56:24 -0800180 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800181
182 case pref.MessageKind, pref.GroupKind:
Damien Neil8c86fc52019-06-19 09:28:29 -0700183 if err := o.marshalMessage(val.Message()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800184 return err
185 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800186
Herbie Ong87608a72019-03-06 14:32:24 -0800187 default:
Herbie Ong0b0f4032019-03-18 19:06:15 -0700188 panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
Herbie Ong87608a72019-03-06 14:32:24 -0800189 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700190 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800191}
192
Herbie Ong87608a72019-03-06 14:32:24 -0800193// marshalList marshals the given protoreflect.List.
Herbie Ong822de2d2019-03-27 13:16:23 -0700194func (o MarshalOptions) marshalList(list pref.List, fd pref.FieldDescriptor) error {
195 o.encoder.StartArray()
196 defer o.encoder.EndArray()
Herbie Ong87608a72019-03-06 14:32:24 -0800197
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)
Damien Neil8c86fc52019-06-19 09:28:29 -0700200 if err := o.marshalSingular(item, fd); err != nil {
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 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700204 return nil
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 for _, entry := range entries {
Damien Neil8c86fc52019-06-19 09:28:29 -0700227 if err := o.encoder.WriteName(entry.key.String()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800228 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800229 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700230 if err := o.marshalSingular(entry.value, fd.MapValue()); err != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800231 return err
232 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800233 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700234 return nil
Herbie Ong7b828bc2019-02-08 19:56:24 -0800235}
236
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700237// sortMap orders list based on value of key field for deterministic ordering.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800238func sortMap(keyKind pref.Kind, values []mapEntry) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700239 sort.Slice(values, func(i, j int) bool {
240 switch keyKind {
241 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind,
242 pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800243 return values[i].key.Int() < values[j].key.Int()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700244
245 case pref.Uint32Kind, pref.Fixed32Kind,
246 pref.Uint64Kind, pref.Fixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800247 return values[i].key.Uint() < values[j].key.Uint()
248 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700249 return values[i].key.String() < values[j].key.String()
250 })
251}
252
253// marshalExtensions marshals extension fields.
Joe Tsai378c1322019-04-25 23:48:08 -0700254func (o MarshalOptions) marshalExtensions(m pref.Message) error {
255 type entry struct {
256 key string
257 value pref.Value
258 desc pref.FieldDescriptor
Herbie Ong7b828bc2019-02-08 19:56:24 -0800259 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700260
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700261 // Get a sorted list based on field key first.
Joe Tsai378c1322019-04-25 23:48:08 -0700262 var entries []entry
263 m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
264 if !fd.IsExtension() {
265 return true
266 }
Joe Tsai378c1322019-04-25 23:48:08 -0700267
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700268 // For MessageSet extensions, the name used is the parent message.
Joe Tsaid4211502019-07-02 14:58:02 -0700269 name := fd.FullName()
Joe Tsai5ae10aa2019-07-11 18:23:08 -0700270 if messageset.IsMessageSetExtension(fd) {
271 name = name.Parent()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700272 }
273
Joe Tsai378c1322019-04-25 23:48:08 -0700274 // Use [name] format for JSON field name.
275 entries = append(entries, entry{
276 key: string(name),
277 value: v,
278 desc: fd,
279 })
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700280 return true
281 })
282
283 // Sort extensions lexicographically.
284 sort.Slice(entries, func(i, j int) bool {
285 return entries[i].key < entries[j].key
286 })
287
288 // Write out sorted list.
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700289 for _, entry := range entries {
290 // JSON field name is the proto field name enclosed in [], similar to
291 // textproto. This is consistent with Go v1 lib. C++ lib v3.7.0 does not
292 // marshal out extension fields.
Damien Neil8c86fc52019-06-19 09:28:29 -0700293 if err := o.encoder.WriteName("[" + entry.key + "]"); err != nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700294 return err
295 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700296 if err := o.marshalValue(entry.value, entry.desc); err != nil {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700297 return err
298 }
299 }
Damien Neil8c86fc52019-06-19 09:28:29 -0700300 return nil
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700301}