...

Source file src/github.com/golang/protobuf/jsonpb/encode.go

Documentation: github.com/golang/protobuf/jsonpb

     1  // Copyright 2015 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 jsonpb
     6  
     7  import (
     8  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"math"
    13  	"reflect"
    14  	"sort"
    15  	"strconv"
    16  	"strings"
    17  	"time"
    18  
    19  	"github.com/golang/protobuf/proto"
    20  	"google.golang.org/protobuf/encoding/protojson"
    21  	protoV2 "google.golang.org/protobuf/proto"
    22  	"google.golang.org/protobuf/reflect/protoreflect"
    23  	"google.golang.org/protobuf/reflect/protoregistry"
    24  )
    25  
    26  const wrapJSONMarshalV2 = false
    27  
    28  // Marshaler is a configurable object for marshaling protocol buffer messages
    29  // to the specified JSON representation.
    30  type Marshaler struct {
    31  	// OrigName specifies whether to use the original protobuf name for fields.
    32  	OrigName bool
    33  
    34  	// EnumsAsInts specifies whether to render enum values as integers,
    35  	// as opposed to string values.
    36  	EnumsAsInts bool
    37  
    38  	// EmitDefaults specifies whether to render fields with zero values.
    39  	EmitDefaults bool
    40  
    41  	// Indent controls whether the output is compact or not.
    42  	// If empty, the output is compact JSON. Otherwise, every JSON object
    43  	// entry and JSON array value will be on its own line.
    44  	// Each line will be preceded by repeated copies of Indent, where the
    45  	// number of copies is the current indentation depth.
    46  	Indent string
    47  
    48  	// AnyResolver is used to resolve the google.protobuf.Any well-known type.
    49  	// If unset, the global registry is used by default.
    50  	AnyResolver AnyResolver
    51  }
    52  
    53  // JSONPBMarshaler is implemented by protobuf messages that customize the
    54  // way they are marshaled to JSON. Messages that implement this should also
    55  // implement JSONPBUnmarshaler so that the custom format can be parsed.
    56  //
    57  // The JSON marshaling must follow the proto to JSON specification:
    58  //
    59  //	https://developers.google.com/protocol-buffers/docs/proto3#json
    60  //
    61  // Deprecated: Custom types should implement protobuf reflection instead.
    62  type JSONPBMarshaler interface {
    63  	MarshalJSONPB(*Marshaler) ([]byte, error)
    64  }
    65  
    66  // Marshal serializes a protobuf message as JSON into w.
    67  func (jm *Marshaler) Marshal(w io.Writer, m proto.Message) error {
    68  	b, err := jm.marshal(m)
    69  	if len(b) > 0 {
    70  		if _, err := w.Write(b); err != nil {
    71  			return err
    72  		}
    73  	}
    74  	return err
    75  }
    76  
    77  // MarshalToString serializes a protobuf message as JSON in string form.
    78  func (jm *Marshaler) MarshalToString(m proto.Message) (string, error) {
    79  	b, err := jm.marshal(m)
    80  	if err != nil {
    81  		return "", err
    82  	}
    83  	return string(b), nil
    84  }
    85  
    86  func (jm *Marshaler) marshal(m proto.Message) ([]byte, error) {
    87  	v := reflect.ValueOf(m)
    88  	if m == nil || (v.Kind() == reflect.Ptr && v.IsNil()) {
    89  		return nil, errors.New("Marshal called with nil")
    90  	}
    91  
    92  	// Check for custom marshalers first since they may not properly
    93  	// implement protobuf reflection that the logic below relies on.
    94  	if jsm, ok := m.(JSONPBMarshaler); ok {
    95  		return jsm.MarshalJSONPB(jm)
    96  	}
    97  
    98  	if wrapJSONMarshalV2 {
    99  		opts := protojson.MarshalOptions{
   100  			UseProtoNames:   jm.OrigName,
   101  			UseEnumNumbers:  jm.EnumsAsInts,
   102  			EmitUnpopulated: jm.EmitDefaults,
   103  			Indent:          jm.Indent,
   104  		}
   105  		if jm.AnyResolver != nil {
   106  			opts.Resolver = anyResolver{jm.AnyResolver}
   107  		}
   108  		return opts.Marshal(proto.MessageReflect(m).Interface())
   109  	} else {
   110  		// Check for unpopulated required fields first.
   111  		m2 := proto.MessageReflect(m)
   112  		if err := protoV2.CheckInitialized(m2.Interface()); err != nil {
   113  			return nil, err
   114  		}
   115  
   116  		w := jsonWriter{Marshaler: jm}
   117  		err := w.marshalMessage(m2, "", "")
   118  		return w.buf, err
   119  	}
   120  }
   121  
   122  type jsonWriter struct {
   123  	*Marshaler
   124  	buf []byte
   125  }
   126  
   127  func (w *jsonWriter) write(s string) {
   128  	w.buf = append(w.buf, s...)
   129  }
   130  
   131  func (w *jsonWriter) marshalMessage(m protoreflect.Message, indent, typeURL string) error {
   132  	if jsm, ok := proto.MessageV1(m.Interface()).(JSONPBMarshaler); ok {
   133  		b, err := jsm.MarshalJSONPB(w.Marshaler)
   134  		if err != nil {
   135  			return err
   136  		}
   137  		if typeURL != "" {
   138  			// we are marshaling this object to an Any type
   139  			var js map[string]*json.RawMessage
   140  			if err = json.Unmarshal(b, &js); err != nil {
   141  				return fmt.Errorf("type %T produced invalid JSON: %v", m.Interface(), err)
   142  			}
   143  			turl, err := json.Marshal(typeURL)
   144  			if err != nil {
   145  				return fmt.Errorf("failed to marshal type URL %q to JSON: %v", typeURL, err)
   146  			}
   147  			js["@type"] = (*json.RawMessage)(&turl)
   148  			if b, err = json.Marshal(js); err != nil {
   149  				return err
   150  			}
   151  		}
   152  		w.write(string(b))
   153  		return nil
   154  	}
   155  
   156  	md := m.Descriptor()
   157  	fds := md.Fields()
   158  
   159  	// Handle well-known types.
   160  	const secondInNanos = int64(time.Second / time.Nanosecond)
   161  	switch wellKnownType(md.FullName()) {
   162  	case "Any":
   163  		return w.marshalAny(m, indent)
   164  	case "BoolValue", "BytesValue", "StringValue",
   165  		"Int32Value", "UInt32Value", "FloatValue",
   166  		"Int64Value", "UInt64Value", "DoubleValue":
   167  		fd := fds.ByNumber(1)
   168  		return w.marshalValue(fd, m.Get(fd), indent)
   169  	case "Duration":
   170  		const maxSecondsInDuration = 315576000000
   171  		// "Generated output always contains 0, 3, 6, or 9 fractional digits,
   172  		//  depending on required precision."
   173  		s := m.Get(fds.ByNumber(1)).Int()
   174  		ns := m.Get(fds.ByNumber(2)).Int()
   175  		if s < -maxSecondsInDuration || s > maxSecondsInDuration {
   176  			return fmt.Errorf("seconds out of range %v", s)
   177  		}
   178  		if ns <= -secondInNanos || ns >= secondInNanos {
   179  			return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos)
   180  		}
   181  		if (s > 0 && ns < 0) || (s < 0 && ns > 0) {
   182  			return errors.New("signs of seconds and nanos do not match")
   183  		}
   184  		var sign string
   185  		if s < 0 || ns < 0 {
   186  			sign, s, ns = "-", -1*s, -1*ns
   187  		}
   188  		x := fmt.Sprintf("%s%d.%09d", sign, s, ns)
   189  		x = strings.TrimSuffix(x, "000")
   190  		x = strings.TrimSuffix(x, "000")
   191  		x = strings.TrimSuffix(x, ".000")
   192  		w.write(fmt.Sprintf(`"%vs"`, x))
   193  		return nil
   194  	case "Timestamp":
   195  		// "RFC 3339, where generated output will always be Z-normalized
   196  		//  and uses 0, 3, 6 or 9 fractional digits."
   197  		s := m.Get(fds.ByNumber(1)).Int()
   198  		ns := m.Get(fds.ByNumber(2)).Int()
   199  		if ns < 0 || ns >= secondInNanos {
   200  			return fmt.Errorf("ns out of range [0, %v)", secondInNanos)
   201  		}
   202  		t := time.Unix(s, ns).UTC()
   203  		// time.RFC3339Nano isn't exactly right (we need to get 3/6/9 fractional digits).
   204  		x := t.Format("2006-01-02T15:04:05.000000000")
   205  		x = strings.TrimSuffix(x, "000")
   206  		x = strings.TrimSuffix(x, "000")
   207  		x = strings.TrimSuffix(x, ".000")
   208  		w.write(fmt.Sprintf(`"%vZ"`, x))
   209  		return nil
   210  	case "Value":
   211  		// JSON value; which is a null, number, string, bool, object, or array.
   212  		od := md.Oneofs().Get(0)
   213  		fd := m.WhichOneof(od)
   214  		if fd == nil {
   215  			return errors.New("nil Value")
   216  		}
   217  		return w.marshalValue(fd, m.Get(fd), indent)
   218  	case "Struct", "ListValue":
   219  		// JSON object or array.
   220  		fd := fds.ByNumber(1)
   221  		return w.marshalValue(fd, m.Get(fd), indent)
   222  	}
   223  
   224  	w.write("{")
   225  	if w.Indent != "" {
   226  		w.write("\n")
   227  	}
   228  
   229  	firstField := true
   230  	if typeURL != "" {
   231  		if err := w.marshalTypeURL(indent, typeURL); err != nil {
   232  			return err
   233  		}
   234  		firstField = false
   235  	}
   236  
   237  	for i := 0; i < fds.Len(); {
   238  		fd := fds.Get(i)
   239  		if od := fd.ContainingOneof(); od != nil {
   240  			fd = m.WhichOneof(od)
   241  			i += od.Fields().Len()
   242  			if fd == nil {
   243  				continue
   244  			}
   245  		} else {
   246  			i++
   247  		}
   248  
   249  		v := m.Get(fd)
   250  
   251  		if !m.Has(fd) {
   252  			if !w.EmitDefaults || fd.ContainingOneof() != nil {
   253  				continue
   254  			}
   255  			if fd.Cardinality() != protoreflect.Repeated && (fd.Message() != nil || fd.Syntax() == protoreflect.Proto2) {
   256  				v = protoreflect.Value{} // use "null" for singular messages or proto2 scalars
   257  			}
   258  		}
   259  
   260  		if !firstField {
   261  			w.writeComma()
   262  		}
   263  		if err := w.marshalField(fd, v, indent); err != nil {
   264  			return err
   265  		}
   266  		firstField = false
   267  	}
   268  
   269  	// Handle proto2 extensions.
   270  	if md.ExtensionRanges().Len() > 0 {
   271  		// Collect a sorted list of all extension descriptor and values.
   272  		type ext struct {
   273  			desc protoreflect.FieldDescriptor
   274  			val  protoreflect.Value
   275  		}
   276  		var exts []ext
   277  		m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
   278  			if fd.IsExtension() {
   279  				exts = append(exts, ext{fd, v})
   280  			}
   281  			return true
   282  		})
   283  		sort.Slice(exts, func(i, j int) bool {
   284  			return exts[i].desc.Number() < exts[j].desc.Number()
   285  		})
   286  
   287  		for _, ext := range exts {
   288  			if !firstField {
   289  				w.writeComma()
   290  			}
   291  			if err := w.marshalField(ext.desc, ext.val, indent); err != nil {
   292  				return err
   293  			}
   294  			firstField = false
   295  		}
   296  	}
   297  
   298  	if w.Indent != "" {
   299  		w.write("\n")
   300  		w.write(indent)
   301  	}
   302  	w.write("}")
   303  	return nil
   304  }
   305  
   306  func (w *jsonWriter) writeComma() {
   307  	if w.Indent != "" {
   308  		w.write(",\n")
   309  	} else {
   310  		w.write(",")
   311  	}
   312  }
   313  
   314  func (w *jsonWriter) marshalAny(m protoreflect.Message, indent string) error {
   315  	// "If the Any contains a value that has a special JSON mapping,
   316  	//  it will be converted as follows: {"@type": xxx, "value": yyy}.
   317  	//  Otherwise, the value will be converted into a JSON object,
   318  	//  and the "@type" field will be inserted to indicate the actual data type."
   319  	md := m.Descriptor()
   320  	typeURL := m.Get(md.Fields().ByNumber(1)).String()
   321  	rawVal := m.Get(md.Fields().ByNumber(2)).Bytes()
   322  
   323  	var m2 protoreflect.Message
   324  	if w.AnyResolver != nil {
   325  		mi, err := w.AnyResolver.Resolve(typeURL)
   326  		if err != nil {
   327  			return err
   328  		}
   329  		m2 = proto.MessageReflect(mi)
   330  	} else {
   331  		mt, err := protoregistry.GlobalTypes.FindMessageByURL(typeURL)
   332  		if err != nil {
   333  			return err
   334  		}
   335  		m2 = mt.New()
   336  	}
   337  
   338  	if err := protoV2.Unmarshal(rawVal, m2.Interface()); err != nil {
   339  		return err
   340  	}
   341  
   342  	if wellKnownType(m2.Descriptor().FullName()) == "" {
   343  		return w.marshalMessage(m2, indent, typeURL)
   344  	}
   345  
   346  	w.write("{")
   347  	if w.Indent != "" {
   348  		w.write("\n")
   349  	}
   350  	if err := w.marshalTypeURL(indent, typeURL); err != nil {
   351  		return err
   352  	}
   353  	w.writeComma()
   354  	if w.Indent != "" {
   355  		w.write(indent)
   356  		w.write(w.Indent)
   357  		w.write(`"value": `)
   358  	} else {
   359  		w.write(`"value":`)
   360  	}
   361  	if err := w.marshalMessage(m2, indent+w.Indent, ""); err != nil {
   362  		return err
   363  	}
   364  	if w.Indent != "" {
   365  		w.write("\n")
   366  		w.write(indent)
   367  	}
   368  	w.write("}")
   369  	return nil
   370  }
   371  
   372  func (w *jsonWriter) marshalTypeURL(indent, typeURL string) error {
   373  	if w.Indent != "" {
   374  		w.write(indent)
   375  		w.write(w.Indent)
   376  	}
   377  	w.write(`"@type":`)
   378  	if w.Indent != "" {
   379  		w.write(" ")
   380  	}
   381  	b, err := json.Marshal(typeURL)
   382  	if err != nil {
   383  		return err
   384  	}
   385  	w.write(string(b))
   386  	return nil
   387  }
   388  
   389  // marshalField writes field description and value to the Writer.
   390  func (w *jsonWriter) marshalField(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
   391  	if w.Indent != "" {
   392  		w.write(indent)
   393  		w.write(w.Indent)
   394  	}
   395  	w.write(`"`)
   396  	switch {
   397  	case fd.IsExtension():
   398  		// For message set, use the fname of the message as the extension name.
   399  		name := string(fd.FullName())
   400  		if isMessageSet(fd.ContainingMessage()) {
   401  			name = strings.TrimSuffix(name, ".message_set_extension")
   402  		}
   403  
   404  		w.write("[" + name + "]")
   405  	case w.OrigName:
   406  		name := string(fd.Name())
   407  		if fd.Kind() == protoreflect.GroupKind {
   408  			name = string(fd.Message().Name())
   409  		}
   410  		w.write(name)
   411  	default:
   412  		w.write(string(fd.JSONName()))
   413  	}
   414  	w.write(`":`)
   415  	if w.Indent != "" {
   416  		w.write(" ")
   417  	}
   418  	return w.marshalValue(fd, v, indent)
   419  }
   420  
   421  func (w *jsonWriter) marshalValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
   422  	switch {
   423  	case fd.IsList():
   424  		w.write("[")
   425  		comma := ""
   426  		lv := v.List()
   427  		for i := 0; i < lv.Len(); i++ {
   428  			w.write(comma)
   429  			if w.Indent != "" {
   430  				w.write("\n")
   431  				w.write(indent)
   432  				w.write(w.Indent)
   433  				w.write(w.Indent)
   434  			}
   435  			if err := w.marshalSingularValue(fd, lv.Get(i), indent+w.Indent); err != nil {
   436  				return err
   437  			}
   438  			comma = ","
   439  		}
   440  		if w.Indent != "" {
   441  			w.write("\n")
   442  			w.write(indent)
   443  			w.write(w.Indent)
   444  		}
   445  		w.write("]")
   446  		return nil
   447  	case fd.IsMap():
   448  		kfd := fd.MapKey()
   449  		vfd := fd.MapValue()
   450  		mv := v.Map()
   451  
   452  		// Collect a sorted list of all map keys and values.
   453  		type entry struct{ key, val protoreflect.Value }
   454  		var entries []entry
   455  		mv.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
   456  			entries = append(entries, entry{k.Value(), v})
   457  			return true
   458  		})
   459  		sort.Slice(entries, func(i, j int) bool {
   460  			switch kfd.Kind() {
   461  			case protoreflect.BoolKind:
   462  				return !entries[i].key.Bool() && entries[j].key.Bool()
   463  			case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
   464  				return entries[i].key.Int() < entries[j].key.Int()
   465  			case protoreflect.Uint32Kind, protoreflect.Fixed32Kind, protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
   466  				return entries[i].key.Uint() < entries[j].key.Uint()
   467  			case protoreflect.StringKind:
   468  				return entries[i].key.String() < entries[j].key.String()
   469  			default:
   470  				panic("invalid kind")
   471  			}
   472  		})
   473  
   474  		w.write(`{`)
   475  		comma := ""
   476  		for _, entry := range entries {
   477  			w.write(comma)
   478  			if w.Indent != "" {
   479  				w.write("\n")
   480  				w.write(indent)
   481  				w.write(w.Indent)
   482  				w.write(w.Indent)
   483  			}
   484  
   485  			s := fmt.Sprint(entry.key.Interface())
   486  			b, err := json.Marshal(s)
   487  			if err != nil {
   488  				return err
   489  			}
   490  			w.write(string(b))
   491  
   492  			w.write(`:`)
   493  			if w.Indent != "" {
   494  				w.write(` `)
   495  			}
   496  
   497  			if err := w.marshalSingularValue(vfd, entry.val, indent+w.Indent); err != nil {
   498  				return err
   499  			}
   500  			comma = ","
   501  		}
   502  		if w.Indent != "" {
   503  			w.write("\n")
   504  			w.write(indent)
   505  			w.write(w.Indent)
   506  		}
   507  		w.write(`}`)
   508  		return nil
   509  	default:
   510  		return w.marshalSingularValue(fd, v, indent)
   511  	}
   512  }
   513  
   514  func (w *jsonWriter) marshalSingularValue(fd protoreflect.FieldDescriptor, v protoreflect.Value, indent string) error {
   515  	switch {
   516  	case !v.IsValid():
   517  		w.write("null")
   518  		return nil
   519  	case fd.Message() != nil:
   520  		return w.marshalMessage(v.Message(), indent+w.Indent, "")
   521  	case fd.Enum() != nil:
   522  		if fd.Enum().FullName() == "google.protobuf.NullValue" {
   523  			w.write("null")
   524  			return nil
   525  		}
   526  
   527  		vd := fd.Enum().Values().ByNumber(v.Enum())
   528  		if vd == nil || w.EnumsAsInts {
   529  			w.write(strconv.Itoa(int(v.Enum())))
   530  		} else {
   531  			w.write(`"` + string(vd.Name()) + `"`)
   532  		}
   533  		return nil
   534  	default:
   535  		switch v.Interface().(type) {
   536  		case float32, float64:
   537  			switch {
   538  			case math.IsInf(v.Float(), +1):
   539  				w.write(`"Infinity"`)
   540  				return nil
   541  			case math.IsInf(v.Float(), -1):
   542  				w.write(`"-Infinity"`)
   543  				return nil
   544  			case math.IsNaN(v.Float()):
   545  				w.write(`"NaN"`)
   546  				return nil
   547  			}
   548  		case int64, uint64:
   549  			w.write(fmt.Sprintf(`"%d"`, v.Interface()))
   550  			return nil
   551  		}
   552  
   553  		b, err := json.Marshal(v.Interface())
   554  		if err != nil {
   555  			return err
   556  		}
   557  		w.write(string(b))
   558  		return nil
   559  	}
   560  }
   561  

View as plain text