encode.go raw

   1  // 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  
   5  package protojson
   6  
   7  import (
   8  	"encoding/base64"
   9  	"fmt"
  10  
  11  	"google.golang.org/protobuf/internal/encoding/json"
  12  	"google.golang.org/protobuf/internal/encoding/messageset"
  13  	"google.golang.org/protobuf/internal/errors"
  14  	"google.golang.org/protobuf/internal/filedesc"
  15  	"google.golang.org/protobuf/internal/flags"
  16  	"google.golang.org/protobuf/internal/genid"
  17  	"google.golang.org/protobuf/internal/order"
  18  	"google.golang.org/protobuf/internal/pragma"
  19  	"google.golang.org/protobuf/proto"
  20  	"google.golang.org/protobuf/reflect/protoreflect"
  21  	"google.golang.org/protobuf/reflect/protoregistry"
  22  )
  23  
  24  const defaultIndent = "  "
  25  
  26  // Format formats the message as a multiline string.
  27  // This function is only intended for human consumption and ignores errors.
  28  // Do not depend on the output being stable. Its output will change across
  29  // different builds of your program, even when using the same version of the
  30  // protobuf module.
  31  func Format(m proto.Message) string {
  32  	return MarshalOptions{Multiline: true}.Format(m)
  33  }
  34  
  35  // Marshal writes the given [proto.Message] in JSON format using default options.
  36  // Do not depend on the output being stable. Its output will change across
  37  // different builds of your program, even when using the same version of the
  38  // protobuf module.
  39  func Marshal(m proto.Message) ([]byte, error) {
  40  	return MarshalOptions{}.Marshal(m)
  41  }
  42  
  43  // MarshalOptions is a configurable JSON format marshaler.
  44  type MarshalOptions struct {
  45  	pragma.NoUnkeyedLiterals
  46  
  47  	// Multiline specifies whether the marshaler should format the output in
  48  	// indented-form with every textual element on a new line.
  49  	// If Indent is an empty string, then an arbitrary indent is chosen.
  50  	Multiline bool
  51  
  52  	// Indent specifies the set of indentation characters to use in a multiline
  53  	// formatted output such that every entry is preceded by Indent and
  54  	// terminated by a newline. If non-empty, then Multiline is treated as true.
  55  	// Indent can only be composed of space or tab characters.
  56  	Indent string
  57  
  58  	// AllowPartial allows messages that have missing required fields to marshal
  59  	// without returning an error. If AllowPartial is false (the default),
  60  	// Marshal will return error if there are any missing required fields.
  61  	AllowPartial bool
  62  
  63  	// UseProtoNames uses proto field name instead of lowerCamelCase name in JSON
  64  	// field names.
  65  	UseProtoNames bool
  66  
  67  	// UseEnumNumbers emits enum values as numbers.
  68  	UseEnumNumbers bool
  69  
  70  	// EmitUnpopulated specifies whether to emit unpopulated fields. It does not
  71  	// emit unpopulated oneof fields or unpopulated extension fields.
  72  	// The JSON value emitted for unpopulated fields are as follows:
  73  	//  ╔═══════╤════════════════════════════╗
  74  	//  ║ JSON  │ Protobuf field             ║
  75  	//  ╠═══════╪════════════════════════════╣
  76  	//  ║ false │ proto3 boolean fields      ║
  77  	//  ║ 0     │ proto3 numeric fields      ║
  78  	//  ║ ""    │ proto3 string/bytes fields ║
  79  	//  ║ null  │ proto2 scalar fields       ║
  80  	//  ║ null  │ message fields             ║
  81  	//  ║ []    │ list fields                ║
  82  	//  ║ {}    │ map fields                 ║
  83  	//  ╚═══════╧════════════════════════════╝
  84  	EmitUnpopulated bool
  85  
  86  	// EmitDefaultValues specifies whether to emit default-valued primitive fields,
  87  	// empty lists, and empty maps. The fields affected are as follows:
  88  	//  ╔═══════╤════════════════════════════════════════╗
  89  	//  ║ JSON  │ Protobuf field                         ║
  90  	//  ╠═══════╪════════════════════════════════════════╣
  91  	//  ║ false │ non-optional scalar boolean fields     ║
  92  	//  ║ 0     │ non-optional scalar numeric fields     ║
  93  	//  ║ ""    │ non-optional scalar string/byte fields ║
  94  	//  ║ []    │ empty repeated fields                  ║
  95  	//  ║ {}    │ empty map fields                       ║
  96  	//  ╚═══════╧════════════════════════════════════════╝
  97  	//
  98  	// Behaves similarly to EmitUnpopulated, but does not emit "null"-value fields,
  99  	// i.e. presence-sensing fields that are omitted will remain omitted to preserve
 100  	// presence-sensing.
 101  	// EmitUnpopulated takes precedence over EmitDefaultValues since the former generates
 102  	// a strict superset of the latter.
 103  	EmitDefaultValues bool
 104  
 105  	// Resolver is used for looking up types when expanding google.protobuf.Any
 106  	// messages. If nil, this defaults to using protoregistry.GlobalTypes.
 107  	Resolver interface {
 108  		protoregistry.ExtensionTypeResolver
 109  		protoregistry.MessageTypeResolver
 110  	}
 111  }
 112  
 113  // Format formats the message as a string.
 114  // This method is only intended for human consumption and ignores errors.
 115  // Do not depend on the output being stable. Its output will change across
 116  // different builds of your program, even when using the same version of the
 117  // protobuf module.
 118  func (o MarshalOptions) Format(m proto.Message) string {
 119  	if m == nil || !m.ProtoReflect().IsValid() {
 120  		return "<nil>" // invalid syntax, but okay since this is for debugging
 121  	}
 122  	o.AllowPartial = true
 123  	b, _ := o.Marshal(m)
 124  	return string(b)
 125  }
 126  
 127  // Marshal marshals the given [proto.Message] in the JSON format using options in
 128  // Do not depend on the output being stable. Its output will change across
 129  // different builds of your program, even when using the same version of the
 130  // protobuf module.
 131  func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
 132  	return o.marshal(nil, m)
 133  }
 134  
 135  // MarshalAppend appends the JSON format encoding of m to b,
 136  // returning the result.
 137  func (o MarshalOptions) MarshalAppend(b []byte, m proto.Message) ([]byte, error) {
 138  	return o.marshal(b, m)
 139  }
 140  
 141  // marshal is a centralized function that all marshal operations go through.
 142  // For profiling purposes, avoid changing the name of this function or
 143  // introducing other code paths for marshal that do not go through this.
 144  func (o MarshalOptions) marshal(b []byte, m proto.Message) ([]byte, error) {
 145  	if o.Multiline && o.Indent == "" {
 146  		o.Indent = defaultIndent
 147  	}
 148  	if o.Resolver == nil {
 149  		o.Resolver = protoregistry.GlobalTypes
 150  	}
 151  
 152  	internalEnc, err := json.NewEncoder(b, o.Indent)
 153  	if err != nil {
 154  		return nil, err
 155  	}
 156  
 157  	// Treat nil message interface as an empty message,
 158  	// in which case the output in an empty JSON object.
 159  	if m == nil {
 160  		return append(b, '{', '}'), nil
 161  	}
 162  
 163  	enc := encoder{internalEnc, o}
 164  	if err := enc.marshalMessage(m.ProtoReflect(), ""); err != nil {
 165  		return nil, err
 166  	}
 167  	if o.AllowPartial {
 168  		return enc.Bytes(), nil
 169  	}
 170  	return enc.Bytes(), proto.CheckInitialized(m)
 171  }
 172  
 173  type encoder struct {
 174  	*json.Encoder
 175  	opts MarshalOptions
 176  }
 177  
 178  // typeFieldDesc is a synthetic field descriptor used for the "@type" field.
 179  var typeFieldDesc = func() protoreflect.FieldDescriptor {
 180  	var fd filedesc.Field
 181  	fd.L0.FullName = "@type"
 182  	fd.L0.Index = -1
 183  	fd.L1.Cardinality = protoreflect.Optional
 184  	fd.L1.Kind = protoreflect.StringKind
 185  	return &fd
 186  }()
 187  
 188  // typeURLFieldRanger wraps a protoreflect.Message and modifies its Range method
 189  // to additionally iterate over a synthetic field for the type URL.
 190  type typeURLFieldRanger struct {
 191  	order.FieldRanger
 192  	typeURL string
 193  }
 194  
 195  func (m typeURLFieldRanger) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
 196  	if !f(typeFieldDesc, protoreflect.ValueOfString(m.typeURL)) {
 197  		return
 198  	}
 199  	m.FieldRanger.Range(f)
 200  }
 201  
 202  // unpopulatedFieldRanger wraps a protoreflect.Message and modifies its Range
 203  // method to additionally iterate over unpopulated fields.
 204  type unpopulatedFieldRanger struct {
 205  	protoreflect.Message
 206  
 207  	skipNull bool
 208  }
 209  
 210  func (m unpopulatedFieldRanger) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
 211  	fds := m.Descriptor().Fields()
 212  	for i := 0; i < fds.Len(); i++ {
 213  		fd := fds.Get(i)
 214  		if m.Has(fd) || fd.ContainingOneof() != nil {
 215  			continue // ignore populated fields and fields within a oneofs
 216  		}
 217  
 218  		v := m.Get(fd)
 219  		if fd.HasPresence() {
 220  			if m.skipNull {
 221  				continue
 222  			}
 223  			v = protoreflect.Value{} // use invalid value to emit null
 224  		}
 225  		if !f(fd, v) {
 226  			return
 227  		}
 228  	}
 229  	m.Message.Range(f)
 230  }
 231  
 232  // marshalMessage marshals the fields in the given protoreflect.Message.
 233  // If the typeURL is non-empty, then a synthetic "@type" field is injected
 234  // containing the URL as the value.
 235  func (e encoder) marshalMessage(m protoreflect.Message, typeURL string) error {
 236  	if !flags.ProtoLegacy && messageset.IsMessageSet(m.Descriptor()) {
 237  		return errors.New("no support for proto1 MessageSets")
 238  	}
 239  
 240  	if marshal := wellKnownTypeMarshaler(m.Descriptor().FullName()); marshal != nil {
 241  		return marshal(e, m)
 242  	}
 243  
 244  	e.StartObject()
 245  	defer e.EndObject()
 246  
 247  	var fields order.FieldRanger = m
 248  	switch {
 249  	case e.opts.EmitUnpopulated:
 250  		fields = unpopulatedFieldRanger{Message: m, skipNull: false}
 251  	case e.opts.EmitDefaultValues:
 252  		fields = unpopulatedFieldRanger{Message: m, skipNull: true}
 253  	}
 254  	if typeURL != "" {
 255  		fields = typeURLFieldRanger{fields, typeURL}
 256  	}
 257  
 258  	var err error
 259  	order.RangeFields(fields, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
 260  		name := fd.JSONName()
 261  		if e.opts.UseProtoNames {
 262  			name = fd.TextName()
 263  		}
 264  
 265  		if err = e.WriteName(name); err != nil {
 266  			return false
 267  		}
 268  		if err = e.marshalValue(v, fd); err != nil {
 269  			return false
 270  		}
 271  		return true
 272  	})
 273  	return err
 274  }
 275  
 276  // marshalValue marshals the given protoreflect.Value.
 277  func (e encoder) marshalValue(val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
 278  	switch {
 279  	case fd.IsList():
 280  		return e.marshalList(val.List(), fd)
 281  	case fd.IsMap():
 282  		return e.marshalMap(val.Map(), fd)
 283  	default:
 284  		return e.marshalSingular(val, fd)
 285  	}
 286  }
 287  
 288  // marshalSingular marshals the given non-repeated field value. This includes
 289  // all scalar types, enums, messages, and groups.
 290  func (e encoder) marshalSingular(val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
 291  	if !val.IsValid() {
 292  		e.WriteNull()
 293  		return nil
 294  	}
 295  
 296  	switch kind := fd.Kind(); kind {
 297  	case protoreflect.BoolKind:
 298  		e.WriteBool(val.Bool())
 299  
 300  	case protoreflect.StringKind:
 301  		if e.WriteString(val.String()) != nil {
 302  			return errors.InvalidUTF8(string(fd.FullName()))
 303  		}
 304  
 305  	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
 306  		e.WriteInt(val.Int())
 307  
 308  	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
 309  		e.WriteUint(val.Uint())
 310  
 311  	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind,
 312  		protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind:
 313  		// 64-bit integers are written out as JSON string.
 314  		e.WriteString(val.String())
 315  
 316  	case protoreflect.FloatKind:
 317  		// Encoder.WriteFloat handles the special numbers NaN and infinites.
 318  		e.WriteFloat(val.Float(), 32)
 319  
 320  	case protoreflect.DoubleKind:
 321  		// Encoder.WriteFloat handles the special numbers NaN and infinites.
 322  		e.WriteFloat(val.Float(), 64)
 323  
 324  	case protoreflect.BytesKind:
 325  		e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
 326  
 327  	case protoreflect.EnumKind:
 328  		if fd.Enum().FullName() == genid.NullValue_enum_fullname {
 329  			e.WriteNull()
 330  		} else {
 331  			desc := fd.Enum().Values().ByNumber(val.Enum())
 332  			if e.opts.UseEnumNumbers || desc == nil {
 333  				e.WriteInt(int64(val.Enum()))
 334  			} else {
 335  				e.WriteString(string(desc.Name()))
 336  			}
 337  		}
 338  
 339  	case protoreflect.MessageKind, protoreflect.GroupKind:
 340  		if err := e.marshalMessage(val.Message(), ""); err != nil {
 341  			return err
 342  		}
 343  
 344  	default:
 345  		panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
 346  	}
 347  	return nil
 348  }
 349  
 350  // marshalList marshals the given protoreflect.List.
 351  func (e encoder) marshalList(list protoreflect.List, fd protoreflect.FieldDescriptor) error {
 352  	e.StartArray()
 353  	defer e.EndArray()
 354  
 355  	for i := 0; i < list.Len(); i++ {
 356  		item := list.Get(i)
 357  		if err := e.marshalSingular(item, fd); err != nil {
 358  			return err
 359  		}
 360  	}
 361  	return nil
 362  }
 363  
 364  // marshalMap marshals given protoreflect.Map.
 365  func (e encoder) marshalMap(mmap protoreflect.Map, fd protoreflect.FieldDescriptor) error {
 366  	e.StartObject()
 367  	defer e.EndObject()
 368  
 369  	var err error
 370  	order.RangeEntries(mmap, order.GenericKeyOrder, func(k protoreflect.MapKey, v protoreflect.Value) bool {
 371  		if err = e.WriteName(k.String()); err != nil {
 372  			return false
 373  		}
 374  		if err = e.marshalSingular(v, fd.MapValue()); err != nil {
 375  			return false
 376  		}
 377  		return true
 378  	})
 379  	return err
 380  }
 381