blob: a9ca5810235d867bc735a1b003ff53d0f2ba02e0 [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
5package jsonpb
6
7import (
8 "encoding/base64"
Herbie Ong0b0f4032019-03-18 19:06:15 -07009 "fmt"
Herbie Ong7b828bc2019-02-08 19:56:24 -080010 "sort"
11
Herbie Ong87608a72019-03-06 14:32:24 -080012 "github.com/golang/protobuf/v2/internal/encoding/json"
Herbie Ong7b828bc2019-02-08 19:56:24 -080013 "github.com/golang/protobuf/v2/internal/errors"
14 "github.com/golang/protobuf/v2/internal/pragma"
15 "github.com/golang/protobuf/v2/proto"
16 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Herbie Ong0b0f4032019-03-18 19:06:15 -070017 "github.com/golang/protobuf/v2/reflect/protoregistry"
Herbie Ongf83d5bb2019-03-14 00:01:27 -070018
19 descpb "github.com/golang/protobuf/v2/types/descriptor"
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 Ong0b0f4032019-03-18 19:06:15 -070031 // If Indent is a non-empty string, it causes entries for an Array or Object
32 // to be preceded by the indent and trailed by a newline. Indent can only be
33 // composed of space or tab characters.
34 Indent string
35
36 // Resolver is the registry used for type lookups when marshaling
37 // google.protobuf.Any messages. If Resolver is not set, marshaling will
38 // default to using protoregistry.GlobalTypes.
39 Resolver *protoregistry.Types
Herbie Ong7b828bc2019-02-08 19:56:24 -080040}
41
Herbie Ong0b0f4032019-03-18 19:06:15 -070042// Marshal marshals the given proto.Message in the JSON format using options in
43// MarshalOptions.
Herbie Ong7b828bc2019-02-08 19:56:24 -080044func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
Herbie Ong0b0f4032019-03-18 19:06:15 -070045 enc, err := newEncoder(o.Indent, o.Resolver)
Herbie Ong87608a72019-03-06 14:32:24 -080046 if err != nil {
47 return nil, err
48 }
49
50 var nerr errors.NonFatal
51 err = enc.marshalMessage(m.ProtoReflect())
Herbie Ong7b828bc2019-02-08 19:56:24 -080052 if !nerr.Merge(err) {
53 return nil, err
54 }
Herbie Ong87608a72019-03-06 14:32:24 -080055 return enc.Bytes(), nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -080056}
57
Herbie Ong87608a72019-03-06 14:32:24 -080058// encoder encodes protoreflect values into JSON.
59type encoder struct {
60 *json.Encoder
Herbie Ong0b0f4032019-03-18 19:06:15 -070061 resolver *protoregistry.Types
Herbie Ong87608a72019-03-06 14:32:24 -080062}
Herbie Ong7b828bc2019-02-08 19:56:24 -080063
Herbie Ong0b0f4032019-03-18 19:06:15 -070064func newEncoder(indent string, resolver *protoregistry.Types) (encoder, error) {
Herbie Ong87608a72019-03-06 14:32:24 -080065 enc, err := json.NewEncoder(indent)
66 if err != nil {
Herbie Ong0b0f4032019-03-18 19:06:15 -070067 return encoder{}, err
Herbie Ong87608a72019-03-06 14:32:24 -080068 }
Herbie Ong0b0f4032019-03-18 19:06:15 -070069 if resolver == nil {
70 resolver = protoregistry.GlobalTypes
71 }
72 return encoder{
73 Encoder: enc,
74 resolver: resolver,
75 }, nil
Herbie Ong87608a72019-03-06 14:32:24 -080076}
77
78// marshalMessage marshals the given protoreflect.Message.
79func (e encoder) marshalMessage(m pref.Message) error {
Herbie Ong0b0f4032019-03-18 19:06:15 -070080 var nerr errors.NonFatal
81
82 if isCustomType(m.Type().FullName()) {
83 return e.marshalCustomType(m)
84 }
85
Herbie Ong87608a72019-03-06 14:32:24 -080086 e.StartObject()
87 defer e.EndObject()
Herbie Ong0b0f4032019-03-18 19:06:15 -070088 if err := e.marshalFields(m); !nerr.Merge(err) {
89 return err
90 }
Herbie Ong87608a72019-03-06 14:32:24 -080091
Herbie Ong0b0f4032019-03-18 19:06:15 -070092 return nerr.E
93}
94
95// marshalFields marshals the fields in the given protoreflect.Message.
96func (e encoder) marshalFields(m pref.Message) error {
Herbie Ong87608a72019-03-06 14:32:24 -080097 var nerr errors.NonFatal
98 fieldDescs := m.Type().Fields()
Herbie Ong7b828bc2019-02-08 19:56:24 -080099 knownFields := m.KnownFields()
Herbie Ong87608a72019-03-06 14:32:24 -0800100
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700101 // Marshal out known fields.
Herbie Ong87608a72019-03-06 14:32:24 -0800102 for i := 0; i < fieldDescs.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800103 fd := fieldDescs.Get(i)
104 num := fd.Number()
105
106 if !knownFields.Has(num) {
107 if fd.Cardinality() == pref.Required {
108 // Treat unset required fields as a non-fatal error.
109 nerr.AppendRequiredNotSet(string(fd.FullName()))
110 }
111 continue
112 }
113
Herbie Ong0b0f4032019-03-18 19:06:15 -0700114 // An empty google.protobuf.Value should NOT be marshaled out.
115 // Hence need to check ahead for this.
116 val := knownFields.Get(num)
117 if isEmptyKnownValue(val, fd.MessageType()) {
118 continue
119 }
120
Herbie Ong87608a72019-03-06 14:32:24 -0800121 name := fd.JSONName()
122 if err := e.WriteName(name); !nerr.Merge(err) {
123 return err
124 }
Herbie Ong87608a72019-03-06 14:32:24 -0800125 if err := e.marshalValue(val, fd); !nerr.Merge(err) {
126 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800127 }
128 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700129
130 // Marshal out extensions.
131 if err := e.marshalExtensions(knownFields); !nerr.Merge(err) {
132 return err
133 }
Herbie Ong87608a72019-03-06 14:32:24 -0800134 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800135}
136
Herbie Ong87608a72019-03-06 14:32:24 -0800137// marshalValue marshals the given protoreflect.Value.
138func (e encoder) marshalValue(val pref.Value, fd pref.FieldDescriptor) error {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800139 var nerr errors.NonFatal
Herbie Ong7b828bc2019-02-08 19:56:24 -0800140 if fd.Cardinality() == pref.Repeated {
141 // Map or repeated fields.
142 if fd.IsMap() {
Herbie Ong87608a72019-03-06 14:32:24 -0800143 if err := e.marshalMap(val.Map(), fd); !nerr.Merge(err) {
144 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800145 }
146 } else {
Herbie Ong87608a72019-03-06 14:32:24 -0800147 if err := e.marshalList(val.List(), fd); !nerr.Merge(err) {
148 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800149 }
150 }
151 } else {
152 // Required or optional fields.
Herbie Ong87608a72019-03-06 14:32:24 -0800153 if err := e.marshalSingular(val, fd); !nerr.Merge(err) {
154 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800155 }
156 }
Herbie Ong87608a72019-03-06 14:32:24 -0800157 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800158}
159
Herbie Ong87608a72019-03-06 14:32:24 -0800160// marshalSingular marshals the given non-repeated field value. This includes
161// all scalar types, enums, messages, and groups.
162func (e encoder) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
163 var nerr errors.NonFatal
164 switch kind := fd.Kind(); kind {
165 case pref.BoolKind:
166 e.WriteBool(val.Bool())
167
168 case pref.StringKind:
169 if err := e.WriteString(val.String()); !nerr.Merge(err) {
170 return err
171 }
172
173 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
174 e.WriteInt(val.Int())
175
176 case pref.Uint32Kind, pref.Fixed32Kind:
177 e.WriteUint(val.Uint())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800178
179 case pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind,
180 pref.Sfixed64Kind, pref.Fixed64Kind:
Herbie Ong87608a72019-03-06 14:32:24 -0800181 // 64-bit integers are written out as JSON string.
182 e.WriteString(val.String())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800183
Herbie Ong87608a72019-03-06 14:32:24 -0800184 case pref.FloatKind:
185 // Encoder.WriteFloat handles the special numbers NaN and infinites.
186 e.WriteFloat(val.Float(), 32)
187
188 case pref.DoubleKind:
189 // Encoder.WriteFloat handles the special numbers NaN and infinites.
190 e.WriteFloat(val.Float(), 64)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800191
192 case pref.BytesKind:
Herbie Ong87608a72019-03-06 14:32:24 -0800193 err := e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
194 if !nerr.Merge(err) {
195 return err
196 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800197
198 case pref.EnumKind:
Herbie Ong0b0f4032019-03-18 19:06:15 -0700199 enumType := fd.EnumType()
Herbie Ong7b828bc2019-02-08 19:56:24 -0800200 num := val.Enum()
Herbie Ong0b0f4032019-03-18 19:06:15 -0700201
202 if enumType.FullName() == "google.protobuf.NullValue" {
203 e.WriteNull()
204 } else if desc := enumType.Values().ByNumber(num); desc != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800205 err := e.WriteString(string(desc.Name()))
206 if !nerr.Merge(err) {
207 return err
208 }
209 } else {
210 // Use numeric value if there is no enum value descriptor.
211 e.WriteInt(int64(num))
Herbie Ong7b828bc2019-02-08 19:56:24 -0800212 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800213
214 case pref.MessageKind, pref.GroupKind:
Herbie Ong87608a72019-03-06 14:32:24 -0800215 if err := e.marshalMessage(val.Message()); !nerr.Merge(err) {
216 return err
217 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800218
Herbie Ong87608a72019-03-06 14:32:24 -0800219 default:
Herbie Ong0b0f4032019-03-18 19:06:15 -0700220 panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
Herbie Ong87608a72019-03-06 14:32:24 -0800221 }
222 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800223}
224
Herbie Ong87608a72019-03-06 14:32:24 -0800225// marshalList marshals the given protoreflect.List.
226func (e encoder) marshalList(list pref.List, fd pref.FieldDescriptor) error {
227 e.StartArray()
228 defer e.EndArray()
229
Herbie Ong7b828bc2019-02-08 19:56:24 -0800230 var nerr errors.NonFatal
Herbie Ong87608a72019-03-06 14:32:24 -0800231 for i := 0; i < list.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800232 item := list.Get(i)
Herbie Ong87608a72019-03-06 14:32:24 -0800233 if err := e.marshalSingular(item, fd); !nerr.Merge(err) {
234 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800235 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800236 }
Herbie Ong87608a72019-03-06 14:32:24 -0800237 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800238}
239
240type mapEntry struct {
241 key pref.MapKey
242 value pref.Value
243}
244
Herbie Ong87608a72019-03-06 14:32:24 -0800245// marshalMap marshals given protoreflect.Map.
246func (e encoder) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
247 e.StartObject()
248 defer e.EndObject()
249
Herbie Ong7b828bc2019-02-08 19:56:24 -0800250 msgFields := fd.MessageType().Fields()
251 keyType := msgFields.ByNumber(1)
252 valType := msgFields.ByNumber(2)
253
254 // Get a sorted list based on keyType first.
255 entries := make([]mapEntry, 0, mmap.Len())
256 mmap.Range(func(key pref.MapKey, val pref.Value) bool {
257 entries = append(entries, mapEntry{key: key, value: val})
258 return true
259 })
260 sortMap(keyType.Kind(), entries)
261
Herbie Ong87608a72019-03-06 14:32:24 -0800262 // Write out sorted list.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800263 var nerr errors.NonFatal
Herbie Ong7b828bc2019-02-08 19:56:24 -0800264 for _, entry := range entries {
Herbie Ong87608a72019-03-06 14:32:24 -0800265 if err := e.WriteName(entry.key.String()); !nerr.Merge(err) {
266 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800267 }
Herbie Ong87608a72019-03-06 14:32:24 -0800268 if err := e.marshalSingular(entry.value, valType); !nerr.Merge(err) {
269 return err
270 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800271 }
Herbie Ong87608a72019-03-06 14:32:24 -0800272 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800273}
274
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700275// sortMap orders list based on value of key field for deterministic ordering.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800276func sortMap(keyKind pref.Kind, values []mapEntry) {
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700277 sort.Slice(values, func(i, j int) bool {
278 switch keyKind {
279 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind,
280 pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800281 return values[i].key.Int() < values[j].key.Int()
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700282
283 case pref.Uint32Kind, pref.Fixed32Kind,
284 pref.Uint64Kind, pref.Fixed64Kind:
Herbie Ong7b828bc2019-02-08 19:56:24 -0800285 return values[i].key.Uint() < values[j].key.Uint()
286 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700287 return values[i].key.String() < values[j].key.String()
288 })
289}
290
291// marshalExtensions marshals extension fields.
292func (e encoder) marshalExtensions(knownFields pref.KnownFields) error {
293 type xtEntry struct {
294 key string
295 value pref.Value
296 xtType pref.ExtensionType
Herbie Ong7b828bc2019-02-08 19:56:24 -0800297 }
Herbie Ongf83d5bb2019-03-14 00:01:27 -0700298
299 xtTypes := knownFields.ExtensionTypes()
300
301 // Get a sorted list based on field key first.
302 entries := make([]xtEntry, 0, xtTypes.Len())
303 xtTypes.Range(func(xt pref.ExtensionType) bool {
304 name := xt.FullName()
305 // If extended type is a MessageSet, set field name to be the message type name.
306 if isMessageSetExtension(xt) {
307 name = xt.MessageType().FullName()
308 }
309
310 num := xt.Number()
311 if knownFields.Has(num) {
312 // Use [name] format for JSON field name.
313 pval := knownFields.Get(num)
314 entries = append(entries, xtEntry{
315 key: string(name),
316 value: pval,
317 xtType: xt,
318 })
319 }
320 return true
321 })
322
323 // Sort extensions lexicographically.
324 sort.Slice(entries, func(i, j int) bool {
325 return entries[i].key < entries[j].key
326 })
327
328 // Write out sorted list.
329 var nerr errors.NonFatal
330 for _, entry := range entries {
331 // JSON field name is the proto field name enclosed in [], similar to
332 // textproto. This is consistent with Go v1 lib. C++ lib v3.7.0 does not
333 // marshal out extension fields.
334 if err := e.WriteName("[" + entry.key + "]"); !nerr.Merge(err) {
335 return err
336 }
337 if err := e.marshalValue(entry.value, entry.xtType); !nerr.Merge(err) {
338 return err
339 }
340 }
341 return nerr.E
342}
343
344// isMessageSetExtension reports whether extension extends a message set.
345func isMessageSetExtension(xt pref.ExtensionType) bool {
346 if xt.Name() != "message_set_extension" {
347 return false
348 }
349 mt := xt.MessageType()
350 if mt == nil {
351 return false
352 }
353 if xt.FullName().Parent() != mt.FullName() {
354 return false
355 }
356 xmt := xt.ExtendedType()
357 if xmt.Fields().Len() != 0 {
358 return false
359 }
360 opt := xmt.Options().(*descpb.MessageOptions)
361 if opt == nil {
362 return false
363 }
364 return opt.GetMessageSetWireFormat()
Herbie Ong7b828bc2019-02-08 19:56:24 -0800365}