...

Source file src/google.golang.org/protobuf/encoding/protojson/encode.go

Documentation: google.golang.org/protobuf/encoding/protojson

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

View as plain text