blob: 4152a745b8fdb8401bb69a3af4ee34f3d299e0d2 [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 Ong7b828bc2019-02-08 19:56:24 -08009 "sort"
10
Herbie Ong87608a72019-03-06 14:32:24 -080011 "github.com/golang/protobuf/v2/internal/encoding/json"
Herbie Ong7b828bc2019-02-08 19:56:24 -080012 "github.com/golang/protobuf/v2/internal/errors"
13 "github.com/golang/protobuf/v2/internal/pragma"
14 "github.com/golang/protobuf/v2/proto"
15 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
16)
17
18// Marshal writes the given proto.Message in JSON format using default options.
19func Marshal(m proto.Message) ([]byte, error) {
20 return MarshalOptions{}.Marshal(m)
21}
22
23// MarshalOptions is a configurable JSON format marshaler.
24type MarshalOptions struct {
25 pragma.NoUnkeyedLiterals
26
27 // Set Compact to true to have output in a single line with no line breaks.
28 Compact bool
29}
30
Herbie Ong87608a72019-03-06 14:32:24 -080031// Marshal returns the given proto.Message in JSON format using options in MarshalOptions object.
Herbie Ong7b828bc2019-02-08 19:56:24 -080032func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
Herbie Ong7b828bc2019-02-08 19:56:24 -080033 indent := " "
34 if o.Compact {
35 indent = ""
36 }
37
Herbie Ong87608a72019-03-06 14:32:24 -080038 enc, err := newEncoder(indent)
39 if err != nil {
40 return nil, err
41 }
42
43 var nerr errors.NonFatal
44 err = enc.marshalMessage(m.ProtoReflect())
Herbie Ong7b828bc2019-02-08 19:56:24 -080045 if !nerr.Merge(err) {
46 return nil, err
47 }
Herbie Ong87608a72019-03-06 14:32:24 -080048 return enc.Bytes(), nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -080049}
50
Herbie Ong87608a72019-03-06 14:32:24 -080051// encoder encodes protoreflect values into JSON.
52type encoder struct {
53 *json.Encoder
54}
Herbie Ong7b828bc2019-02-08 19:56:24 -080055
Herbie Ong87608a72019-03-06 14:32:24 -080056func newEncoder(indent string) (encoder, error) {
57 enc, err := json.NewEncoder(indent)
58 if err != nil {
59 return encoder{}, errors.New("error in constructing an encoder: %v", err)
60 }
61 return encoder{enc}, nil
62}
63
64// marshalMessage marshals the given protoreflect.Message.
65func (e encoder) marshalMessage(m pref.Message) error {
66 e.StartObject()
67 defer e.EndObject()
68
69 var nerr errors.NonFatal
70 fieldDescs := m.Type().Fields()
Herbie Ong7b828bc2019-02-08 19:56:24 -080071 knownFields := m.KnownFields()
Herbie Ong87608a72019-03-06 14:32:24 -080072
73 for i := 0; i < fieldDescs.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -080074 fd := fieldDescs.Get(i)
75 num := fd.Number()
76
77 if !knownFields.Has(num) {
78 if fd.Cardinality() == pref.Required {
79 // Treat unset required fields as a non-fatal error.
80 nerr.AppendRequiredNotSet(string(fd.FullName()))
81 }
82 continue
83 }
84
Herbie Ong87608a72019-03-06 14:32:24 -080085 name := fd.JSONName()
86 if err := e.WriteName(name); !nerr.Merge(err) {
87 return err
88 }
89
90 val := knownFields.Get(num)
91 if err := e.marshalValue(val, fd); !nerr.Merge(err) {
92 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -080093 }
94 }
Herbie Ong87608a72019-03-06 14:32:24 -080095 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -080096}
97
Herbie Ong87608a72019-03-06 14:32:24 -080098// marshalValue marshals the given protoreflect.Value.
99func (e encoder) marshalValue(val pref.Value, fd pref.FieldDescriptor) error {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800100 var nerr errors.NonFatal
Herbie Ong7b828bc2019-02-08 19:56:24 -0800101 if fd.Cardinality() == pref.Repeated {
102 // Map or repeated fields.
103 if fd.IsMap() {
Herbie Ong87608a72019-03-06 14:32:24 -0800104 if err := e.marshalMap(val.Map(), fd); !nerr.Merge(err) {
105 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800106 }
107 } else {
Herbie Ong87608a72019-03-06 14:32:24 -0800108 if err := e.marshalList(val.List(), fd); !nerr.Merge(err) {
109 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800110 }
111 }
112 } else {
113 // Required or optional fields.
Herbie Ong87608a72019-03-06 14:32:24 -0800114 if err := e.marshalSingular(val, fd); !nerr.Merge(err) {
115 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800116 }
117 }
Herbie Ong87608a72019-03-06 14:32:24 -0800118 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800119}
120
Herbie Ong87608a72019-03-06 14:32:24 -0800121// marshalSingular marshals the given non-repeated field value. This includes
122// all scalar types, enums, messages, and groups.
123func (e encoder) marshalSingular(val pref.Value, fd pref.FieldDescriptor) error {
124 var nerr errors.NonFatal
125 switch kind := fd.Kind(); kind {
126 case pref.BoolKind:
127 e.WriteBool(val.Bool())
128
129 case pref.StringKind:
130 if err := e.WriteString(val.String()); !nerr.Merge(err) {
131 return err
132 }
133
134 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
135 e.WriteInt(val.Int())
136
137 case pref.Uint32Kind, pref.Fixed32Kind:
138 e.WriteUint(val.Uint())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800139
140 case pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind,
141 pref.Sfixed64Kind, pref.Fixed64Kind:
Herbie Ong87608a72019-03-06 14:32:24 -0800142 // 64-bit integers are written out as JSON string.
143 e.WriteString(val.String())
Herbie Ong7b828bc2019-02-08 19:56:24 -0800144
Herbie Ong87608a72019-03-06 14:32:24 -0800145 case pref.FloatKind:
146 // Encoder.WriteFloat handles the special numbers NaN and infinites.
147 e.WriteFloat(val.Float(), 32)
148
149 case pref.DoubleKind:
150 // Encoder.WriteFloat handles the special numbers NaN and infinites.
151 e.WriteFloat(val.Float(), 64)
Herbie Ong7b828bc2019-02-08 19:56:24 -0800152
153 case pref.BytesKind:
Herbie Ong87608a72019-03-06 14:32:24 -0800154 err := e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
155 if !nerr.Merge(err) {
156 return err
157 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800158
159 case pref.EnumKind:
160 num := val.Enum()
161 if desc := fd.EnumType().Values().ByNumber(num); desc != nil {
Herbie Ong87608a72019-03-06 14:32:24 -0800162 err := e.WriteString(string(desc.Name()))
163 if !nerr.Merge(err) {
164 return err
165 }
166 } else {
167 // Use numeric value if there is no enum value descriptor.
168 e.WriteInt(int64(num))
Herbie Ong7b828bc2019-02-08 19:56:24 -0800169 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800170
171 case pref.MessageKind, pref.GroupKind:
Herbie Ong87608a72019-03-06 14:32:24 -0800172 if err := e.marshalMessage(val.Message()); !nerr.Merge(err) {
173 return err
174 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800175
Herbie Ong87608a72019-03-06 14:32:24 -0800176 default:
177 return errors.New("%v has unknown kind: %v", fd.FullName(), kind)
178 }
179 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800180}
181
Herbie Ong87608a72019-03-06 14:32:24 -0800182// marshalList marshals the given protoreflect.List.
183func (e encoder) marshalList(list pref.List, fd pref.FieldDescriptor) error {
184 e.StartArray()
185 defer e.EndArray()
186
Herbie Ong7b828bc2019-02-08 19:56:24 -0800187 var nerr errors.NonFatal
Herbie Ong87608a72019-03-06 14:32:24 -0800188 for i := 0; i < list.Len(); i++ {
Herbie Ong7b828bc2019-02-08 19:56:24 -0800189 item := list.Get(i)
Herbie Ong87608a72019-03-06 14:32:24 -0800190 if err := e.marshalSingular(item, fd); !nerr.Merge(err) {
191 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800192 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800193 }
Herbie Ong87608a72019-03-06 14:32:24 -0800194 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800195}
196
197type mapEntry struct {
198 key pref.MapKey
199 value pref.Value
200}
201
Herbie Ong87608a72019-03-06 14:32:24 -0800202// marshalMap marshals given protoreflect.Map.
203func (e encoder) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) error {
204 e.StartObject()
205 defer e.EndObject()
206
Herbie Ong7b828bc2019-02-08 19:56:24 -0800207 msgFields := fd.MessageType().Fields()
208 keyType := msgFields.ByNumber(1)
209 valType := msgFields.ByNumber(2)
210
211 // Get a sorted list based on keyType first.
212 entries := make([]mapEntry, 0, mmap.Len())
213 mmap.Range(func(key pref.MapKey, val pref.Value) bool {
214 entries = append(entries, mapEntry{key: key, value: val})
215 return true
216 })
217 sortMap(keyType.Kind(), entries)
218
Herbie Ong87608a72019-03-06 14:32:24 -0800219 // Write out sorted list.
Herbie Ong7b828bc2019-02-08 19:56:24 -0800220 var nerr errors.NonFatal
Herbie Ong7b828bc2019-02-08 19:56:24 -0800221 for _, entry := range entries {
Herbie Ong87608a72019-03-06 14:32:24 -0800222 if err := e.WriteName(entry.key.String()); !nerr.Merge(err) {
223 return err
Herbie Ong7b828bc2019-02-08 19:56:24 -0800224 }
Herbie Ong87608a72019-03-06 14:32:24 -0800225
226 if err := e.marshalSingular(entry.value, valType); !nerr.Merge(err) {
227 return err
228 }
Herbie Ong7b828bc2019-02-08 19:56:24 -0800229 }
Herbie Ong87608a72019-03-06 14:32:24 -0800230 return nerr.E
Herbie Ong7b828bc2019-02-08 19:56:24 -0800231}
232
233// sortMap orders list based on value of key field for deterministic output.
234func sortMap(keyKind pref.Kind, values []mapEntry) {
235 less := func(i, j int) bool {
236 return values[i].key.String() < values[j].key.String()
237 }
238 switch keyKind {
239 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind,
240 pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
241 less = func(i, j int) bool {
242 return values[i].key.Int() < values[j].key.Int()
243 }
244 case pref.Uint32Kind, pref.Fixed32Kind,
245 pref.Uint64Kind, pref.Fixed64Kind:
246 less = func(i, j int) bool {
247 return values[i].key.Uint() < values[j].key.Uint()
248 }
249 }
250 sort.Slice(values, less)
251}