github.com/whiteCcinn/protobuf-go@v1.0.9/encoding/protojson/encode.go (about)

     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  	"github.com/whiteCcinn/protobuf-go/internal/encoding/json"
    12  	"github.com/whiteCcinn/protobuf-go/internal/encoding/messageset"
    13  	"github.com/whiteCcinn/protobuf-go/internal/errors"
    14  	"github.com/whiteCcinn/protobuf-go/internal/filedesc"
    15  	"github.com/whiteCcinn/protobuf-go/internal/flags"
    16  	"github.com/whiteCcinn/protobuf-go/internal/genid"
    17  	"github.com/whiteCcinn/protobuf-go/internal/order"
    18  	"github.com/whiteCcinn/protobuf-go/internal/pragma"
    19  	"github.com/whiteCcinn/protobuf-go/proto"
    20  	"github.com/whiteCcinn/protobuf-go/reflect/protoreflect"
    21  	"github.com/whiteCcinn/protobuf-go/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  	// Resolver is used for looking up types when expanding google.protobuf.Any
    85  	// messages. If nil, this defaults to using protoregistry.GlobalTypes.
    86  	Resolver interface {
    87  		protoregistry.ExtensionTypeResolver
    88  		protoregistry.MessageTypeResolver
    89  	}
    90  }
    91  
    92  // Format formats the message as a string.
    93  // This method is only intended for human consumption and ignores errors.
    94  // Do not depend on the output being stable. It may change over time across
    95  // different versions of the program.
    96  func (o MarshalOptions) Format(m proto.Message) string {
    97  	if m == nil || !m.ProtoReflect().IsValid() {
    98  		return "<nil>" // invalid syntax, but okay since this is for debugging
    99  	}
   100  	o.AllowPartial = true
   101  	b, _ := o.Marshal(m)
   102  	return string(b)
   103  }
   104  
   105  // Marshal marshals the given proto.Message in the JSON format using options in
   106  // MarshalOptions. Do not depend on the output being stable. It may change over
   107  // time across different versions of the program.
   108  func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
   109  	return o.marshal(m)
   110  }
   111  
   112  // marshal is a centralized function that all marshal operations go through.
   113  // For profiling purposes, avoid changing the name of this function or
   114  // introducing other code paths for marshal that do not go through this.
   115  func (o MarshalOptions) marshal(m proto.Message) ([]byte, error) {
   116  	if o.Multiline && o.Indent == "" {
   117  		o.Indent = defaultIndent
   118  	}
   119  	if o.Resolver == nil {
   120  		o.Resolver = protoregistry.GlobalTypes
   121  	}
   122  
   123  	internalEnc, err := json.NewEncoder(o.Indent)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	// Treat nil message interface as an empty message,
   129  	// in which case the output in an empty JSON object.
   130  	if m == nil {
   131  		return []byte("{}"), nil
   132  	}
   133  
   134  	enc := encoder{internalEnc, o}
   135  	if err := enc.marshalMessage(m.ProtoReflect(), ""); err != nil {
   136  		return nil, err
   137  	}
   138  	if o.AllowPartial {
   139  		return enc.Bytes(), nil
   140  	}
   141  	return enc.Bytes(), proto.CheckInitialized(m)
   142  }
   143  
   144  type encoder struct {
   145  	*json.Encoder
   146  	opts MarshalOptions
   147  }
   148  
   149  // typeFieldDesc is a synthetic field descriptor used for the "@type" field.
   150  var typeFieldDesc = func() protoreflect.FieldDescriptor {
   151  	var fd filedesc.Field
   152  	fd.L0.FullName = "@type"
   153  	fd.L0.Index = -1
   154  	fd.L1.Cardinality = protoreflect.Optional
   155  	fd.L1.Kind = protoreflect.StringKind
   156  	return &fd
   157  }()
   158  
   159  // typeURLFieldRanger wraps a protoreflect.Message and modifies its Range method
   160  // to additionally iterate over a synthetic field for the type URL.
   161  type typeURLFieldRanger struct {
   162  	order.FieldRanger
   163  	typeURL string
   164  }
   165  
   166  func (m typeURLFieldRanger) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
   167  	if !f(typeFieldDesc, protoreflect.ValueOfString(m.typeURL)) {
   168  		return
   169  	}
   170  	m.FieldRanger.Range(f)
   171  }
   172  
   173  // unpopulatedFieldRanger wraps a protoreflect.Message and modifies its Range
   174  // method to additionally iterate over unpopulated fields.
   175  type unpopulatedFieldRanger struct{ protoreflect.Message }
   176  
   177  func (m unpopulatedFieldRanger) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
   178  	fds := m.Descriptor().Fields()
   179  	for i := 0; i < fds.Len(); i++ {
   180  		fd := fds.Get(i)
   181  		if m.Has(fd) || fd.ContainingOneof() != nil {
   182  			continue // ignore populated fields and fields within a oneofs
   183  		}
   184  
   185  		v := m.Get(fd)
   186  		isProto2Scalar := fd.Syntax() == protoreflect.Proto2 && fd.Default().IsValid()
   187  		isSingularMessage := fd.Cardinality() != protoreflect.Repeated && fd.Message() != nil
   188  		if isProto2Scalar || isSingularMessage {
   189  			v = protoreflect.Value{} // use invalid value to emit null
   190  		}
   191  		if !f(fd, v) {
   192  			return
   193  		}
   194  	}
   195  	m.Message.Range(f)
   196  }
   197  
   198  // marshalMessage marshals the fields in the given protoreflect.Message.
   199  // If the typeURL is non-empty, then a synthetic "@type" field is injected
   200  // containing the URL as the value.
   201  func (e encoder) marshalMessage(m protoreflect.Message, typeURL string) error {
   202  	if !flags.ProtoLegacy && messageset.IsMessageSet(m.Descriptor()) {
   203  		return errors.New("no support for proto1 MessageSets")
   204  	}
   205  
   206  	if marshal := wellKnownTypeMarshaler(m.Descriptor().FullName()); marshal != nil {
   207  		return marshal(e, m)
   208  	}
   209  
   210  	e.StartObject()
   211  	defer e.EndObject()
   212  
   213  	var fields order.FieldRanger = m
   214  	if e.opts.EmitUnpopulated {
   215  		fields = unpopulatedFieldRanger{m}
   216  	}
   217  	if typeURL != "" {
   218  		fields = typeURLFieldRanger{fields, typeURL}
   219  	}
   220  
   221  	var err error
   222  	order.RangeFields(fields, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
   223  		name := fd.JSONName()
   224  		if e.opts.UseProtoNames {
   225  			name = fd.TextName()
   226  		}
   227  
   228  		if err = e.WriteName(name); err != nil {
   229  			return false
   230  		}
   231  		if err = e.marshalValue(v, fd); err != nil {
   232  			return false
   233  		}
   234  		return true
   235  	})
   236  	return err
   237  }
   238  
   239  // marshalValue marshals the given protoreflect.Value.
   240  func (e encoder) marshalValue(val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
   241  	switch {
   242  	case fd.IsList():
   243  		return e.marshalList(val.List(), fd)
   244  	case fd.IsMap():
   245  		return e.marshalMap(val.Map(), fd)
   246  	default:
   247  		return e.marshalSingular(val, fd)
   248  	}
   249  }
   250  
   251  // marshalSingular marshals the given non-repeated field value. This includes
   252  // all scalar types, enums, messages, and groups.
   253  func (e encoder) marshalSingular(val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
   254  	if !val.IsValid() {
   255  		e.WriteNull()
   256  		return nil
   257  	}
   258  
   259  	switch kind := fd.Kind(); kind {
   260  	case protoreflect.BoolKind:
   261  		e.WriteBool(val.Bool())
   262  
   263  	case protoreflect.StringKind:
   264  		if e.WriteString(val.String()) != nil {
   265  			return errors.InvalidUTF8(string(fd.FullName()))
   266  		}
   267  
   268  	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
   269  		e.WriteInt(val.Int())
   270  
   271  	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
   272  		e.WriteUint(val.Uint())
   273  
   274  	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind,
   275  		protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind:
   276  		// 64-bit integers are written out as JSON string.
   277  		e.WriteString(val.String())
   278  
   279  	case protoreflect.FloatKind:
   280  		// Encoder.WriteFloat handles the special numbers NaN and infinites.
   281  		e.WriteFloat(val.Float(), 32)
   282  
   283  	case protoreflect.DoubleKind:
   284  		// Encoder.WriteFloat handles the special numbers NaN and infinites.
   285  		e.WriteFloat(val.Float(), 64)
   286  
   287  	case protoreflect.BytesKind:
   288  		e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
   289  
   290  	case protoreflect.EnumKind:
   291  		if fd.Enum().FullName() == genid.NullValue_enum_fullname {
   292  			e.WriteNull()
   293  		} else {
   294  			desc := fd.Enum().Values().ByNumber(val.Enum())
   295  			if e.opts.UseEnumNumbers || desc == nil {
   296  				e.WriteInt(int64(val.Enum()))
   297  			} else {
   298  				e.WriteString(string(desc.Name()))
   299  			}
   300  		}
   301  
   302  	case protoreflect.MessageKind, protoreflect.GroupKind:
   303  		if err := e.marshalMessage(val.Message(), ""); err != nil {
   304  			return err
   305  		}
   306  
   307  	default:
   308  		panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
   309  	}
   310  	return nil
   311  }
   312  
   313  // marshalList marshals the given protoreflect.List.
   314  func (e encoder) marshalList(list protoreflect.List, fd protoreflect.FieldDescriptor) error {
   315  	e.StartArray()
   316  	defer e.EndArray()
   317  
   318  	for i := 0; i < list.Len(); i++ {
   319  		item := list.Get(i)
   320  		if err := e.marshalSingular(item, fd); err != nil {
   321  			return err
   322  		}
   323  	}
   324  	return nil
   325  }
   326  
   327  // marshalMap marshals given protoreflect.Map.
   328  func (e encoder) marshalMap(mmap protoreflect.Map, fd protoreflect.FieldDescriptor) error {
   329  	e.StartObject()
   330  	defer e.EndObject()
   331  
   332  	var err error
   333  	order.RangeEntries(mmap, order.GenericKeyOrder, func(k protoreflect.MapKey, v protoreflect.Value) bool {
   334  		if err = e.WriteName(k.String()); err != nil {
   335  			return false
   336  		}
   337  		if err = e.marshalSingular(v, fd.MapValue()); err != nil {
   338  			return false
   339  		}
   340  		return true
   341  	})
   342  	return err
   343  }