Procházet zdrojové kódy

jsonpb: don't depend on stable struct field indexes

Fix for WKT protos generated after
https://go-review.googlesource.com/c/protobuf/+/188979

Change-Id: I679f4b83e32b22079115787cf921eb78618512a7
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/189637
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
Damien Neil před 6 roky
rodič
revize
212014e965
3 změnil soubory, kde provedl 34 přidání a 27 odebrání
  1. 1 1
      go.mod
  2. 3 0
      go.sum
  3. 30 26
      jsonpb/jsonpb.go

+ 1 - 1
go.mod

@@ -2,4 +2,4 @@ module github.com/golang/protobuf
 
 go 1.9
 
-require google.golang.org/protobuf v0.0.0-20190717230113-f647c82cc3c7
+require google.golang.org/protobuf v0.0.0-20190808204900-1799d1111a45

+ 3 - 0
go.sum

@@ -6,6 +6,7 @@ github.com/golang/protobuf v1.2.1-0.20190523175523-a1331f0b4ab4/go.mod h1:G+fNMo
 github.com/golang/protobuf v1.2.1-0.20190605195750-76c9e09470ba/go.mod h1:S1YIJXvYHGRCG2UmZsOcElkAYfvZLg2sDRr9+Xu8JXU=
 github.com/golang/protobuf v1.2.1-0.20190617175902-f94016f5239f/go.mod h1:G+HpKX7pYZAVkElkAWZkr08MToW6pTp/vs+E9osFfbg=
 github.com/golang/protobuf v1.2.1-0.20190620192300-1ee46dfd80dd/go.mod h1:+CMAsi9jpYf/wAltLUKlg++CWXqxCJyD8iLDbQONsJs=
+github.com/golang/protobuf v1.2.1-0.20190806214225-7037721e6de0/go.mod h1:tDQPRlaHYu9yt1wPgdx85inRiLvUCuJZXsYjC0mwc1c=
 github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 google.golang.org/protobuf v0.0.0-20190514172829-e89e6244e0e8/go.mod h1:791zQGC15vDqjpmPRn1uGPu5oHy/Jzw/Q1n5JsgIIcY=
@@ -18,3 +19,5 @@ google.golang.org/protobuf v0.0.0-20190617175724-bd7b7a9e0c26/go.mod h1:+FOB8T5/
 google.golang.org/protobuf v0.0.0-20190620020611-d888139e7b59/go.mod h1:of3pt14Y+dOxz2tBOHXEoapPpKFC15/0zWhPAddkfsU=
 google.golang.org/protobuf v0.0.0-20190717230113-f647c82cc3c7 h1:U6U+Hb+UKNGJB0eMAjUGk0wTmy73kduTIvdsEgA4Gf8=
 google.golang.org/protobuf v0.0.0-20190717230113-f647c82cc3c7/go.mod h1:yGm7aNHn9Bp1NIvj6+CVUkcJshu+Usshfd3A+YxEuI8=
+google.golang.org/protobuf v0.0.0-20190808204900-1799d1111a45 h1:SZXAIsI6RiG0T8bAF4dqHDHgdqJtOa6tkofjswKtU20=
+google.golang.org/protobuf v0.0.0-20190808204900-1799d1111a45/go.mod h1:tRqhEyKwbKqwt5CQZAuOtj09RfhLNklDOhndhYA9blU=

+ 30 - 26
jsonpb/jsonpb.go

@@ -196,14 +196,14 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU
 		// "Wrappers use the same representation in JSON
 		//  as the wrapped primitive type, ..."
 		sprop := proto.GetProperties(s.Type())
-		return m.marshalValue(out, sprop.Prop[1], s.Field(1), indent)
+		return m.marshalValue(out, sprop.Prop[1], s.FieldByName("Value"), indent)
 	case "Any":
 		// Any is a bit more involved.
 		return m.marshalAny(out, v, indent)
 	case "Duration":
 		// "Generated output always contains 0, 3, 6, or 9 fractional digits,
 		//  depending on required precision."
-		s, ns := s.Field(1).Int(), s.Field(2).Int()
+		s, ns := s.FieldByName("Seconds").Int(), s.FieldByName("Nanos").Int()
 		if ns <= -secondInNanos || ns >= secondInNanos {
 			return fmt.Errorf("ns out of range (%v, %v)", -secondInNanos, secondInNanos)
 		}
@@ -221,14 +221,18 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU
 		out.write(x)
 		out.write(`s"`)
 		return out.err
-	case "Struct", "ListValue":
-		// Let marshalValue handle the `Struct.fields` map or the `ListValue.values` slice.
+	case "Struct":
+		// Let marshalValue handle the `Struct.fields` map.
+		// TODO: pass the correct Properties if needed.
+		return m.marshalValue(out, &proto.Properties{}, s.FieldByName("Fields"), indent)
+	case "ListValue":
+		// Let marshalValue handle the `ListValue.values` slice.
 		// TODO: pass the correct Properties if needed.
-		return m.marshalValue(out, &proto.Properties{}, s.Field(1), indent)
+		return m.marshalValue(out, &proto.Properties{}, s.FieldByName("Values"), indent)
 	case "Timestamp":
 		// "RFC 3339, where generated output will always be Z-normalized
 		//  and uses 0, 3, 6 or 9 fractional digits."
-		s, ns := s.Field(1).Int(), s.Field(2).Int()
+		s, ns := s.FieldByName("Seconds").Int(), s.FieldByName("Nanos").Int()
 		if ns < 0 || ns >= secondInNanos {
 			return fmt.Errorf("ns out of range [0, %v)", secondInNanos)
 		}
@@ -244,7 +248,7 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU
 		return out.err
 	case "Value":
 		// Value has a single oneof.
-		kind := s.Field(1)
+		kind := s.FieldByName("Kind")
 		if kind.IsNil() {
 			// "absence of any variant indicates an error"
 			return errors.New("nil Value")
@@ -393,8 +397,8 @@ func (m *Marshaler) marshalAny(out *errWriter, any proto.Message, indent string)
 	//  Otherwise, the value will be converted into a JSON object,
 	//  and the "@type" field will be inserted to indicate the actual data type."
 	v := reflect.ValueOf(any).Elem()
-	turl := v.Field(1).String()
-	val := v.Field(2).Bytes()
+	turl := v.FieldByName("TypeUrl").String()
+	val := v.FieldByName("Value").Bytes()
 
 	var msg proto.Message
 	var err error
@@ -723,7 +727,7 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
 	switch wellKnownType(target.Addr().Interface()) {
 	case "DoubleValue", "FloatValue", "Int64Value", "UInt64Value",
 		"Int32Value", "UInt32Value", "BoolValue", "StringValue", "BytesValue":
-		return u.unmarshalValue(target.Field(1), inputValue, prop)
+		return u.unmarshalValue(target.FieldByName("Value"), inputValue, prop)
 	case "Any":
 		// Use json.RawMessage pointer type instead of value to support pre-1.8 version.
 		// 1.8 changed RawMessage.MarshalJSON from pointer type to value type, see
@@ -742,7 +746,7 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
 		if err := json.Unmarshal([]byte(*val), &turl); err != nil {
 			return fmt.Errorf("can't unmarshal Any's '@type': %q", *val)
 		}
-		target.Field(1).SetString(turl)
+		target.FieldByName("TypeUrl").SetString(turl)
 
 		var m proto.Message
 		var err error
@@ -780,7 +784,7 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
 		if err != nil {
 			return fmt.Errorf("can't marshal proto %T into Any.Value: %v", m, err)
 		}
-		target.Field(2).SetBytes(b)
+		target.FieldByName("Value").SetBytes(b)
 
 		return nil
 	case "Duration":
@@ -797,8 +801,8 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
 		ns := d.Nanoseconds()
 		s := ns / 1e9
 		ns %= 1e9
-		target.Field(1).SetInt(s)
-		target.Field(2).SetInt(ns)
+		target.FieldByName("Seconds").SetInt(s)
+		target.FieldByName("Nanos").SetInt(ns)
 		return nil
 	case "Timestamp":
 		unq, err := unquote(string(inputValue))
@@ -811,8 +815,8 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
 			return fmt.Errorf("bad Timestamp: %v", err)
 		}
 
-		target.Field(1).SetInt(t.Unix())
-		target.Field(2).SetInt(int64(t.Nanosecond()))
+		target.FieldByName("Seconds").SetInt(t.Unix())
+		target.FieldByName("Nanos").SetInt(int64(t.Nanosecond()))
 		return nil
 	case "Struct":
 		var m map[string]json.RawMessage
@@ -820,13 +824,13 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
 			return fmt.Errorf("bad StructValue: %v", err)
 		}
 
-		target.Field(1).Set(reflect.ValueOf(map[string]*stpb.Value{}))
+		target.FieldByName("Fields").Set(reflect.ValueOf(map[string]*stpb.Value{}))
 		for k, jv := range m {
 			pv := &stpb.Value{}
 			if err := u.unmarshalValue(reflect.ValueOf(pv).Elem(), jv, prop); err != nil {
 				return fmt.Errorf("bad value in StructValue for key %q: %v", k, err)
 			}
-			target.Field(1).SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(pv))
+			target.FieldByName("Fields").SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(pv))
 		}
 		return nil
 	case "ListValue":
@@ -835,9 +839,9 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
 			return fmt.Errorf("bad ListValue: %v", err)
 		}
 
-		target.Field(1).Set(reflect.ValueOf(make([]*stpb.Value, len(s))))
+		target.FieldByName("Values").Set(reflect.ValueOf(make([]*stpb.Value, len(s))))
 		for i, sv := range s {
-			if err := u.unmarshalValue(target.Field(1).Index(i), sv, prop); err != nil {
+			if err := u.unmarshalValue(target.FieldByName("Values").Index(i), sv, prop); err != nil {
 				return err
 			}
 		}
@@ -845,20 +849,20 @@ func (u *Unmarshaler) unmarshalValue(target reflect.Value, inputValue json.RawMe
 	case "Value":
 		ivStr := string(inputValue)
 		if ivStr == "null" {
-			target.Field(1).Set(reflect.ValueOf(&stpb.Value_NullValue{}))
+			target.FieldByName("Kind").Set(reflect.ValueOf(&stpb.Value_NullValue{}))
 		} else if v, err := strconv.ParseFloat(ivStr, 0); err == nil {
-			target.Field(1).Set(reflect.ValueOf(&stpb.Value_NumberValue{v}))
+			target.FieldByName("Kind").Set(reflect.ValueOf(&stpb.Value_NumberValue{v}))
 		} else if v, err := unquote(ivStr); err == nil {
-			target.Field(1).Set(reflect.ValueOf(&stpb.Value_StringValue{v}))
+			target.FieldByName("Kind").Set(reflect.ValueOf(&stpb.Value_StringValue{v}))
 		} else if v, err := strconv.ParseBool(ivStr); err == nil {
-			target.Field(1).Set(reflect.ValueOf(&stpb.Value_BoolValue{v}))
+			target.FieldByName("Kind").Set(reflect.ValueOf(&stpb.Value_BoolValue{v}))
 		} else if err := json.Unmarshal(inputValue, &[]json.RawMessage{}); err == nil {
 			lv := &stpb.ListValue{}
-			target.Field(1).Set(reflect.ValueOf(&stpb.Value_ListValue{lv}))
+			target.FieldByName("Kind").Set(reflect.ValueOf(&stpb.Value_ListValue{lv}))
 			return u.unmarshalValue(reflect.ValueOf(lv).Elem(), inputValue, prop)
 		} else if err := json.Unmarshal(inputValue, &map[string]json.RawMessage{}); err == nil {
 			sv := &stpb.Struct{}
-			target.Field(1).Set(reflect.ValueOf(&stpb.Value_StructValue{sv}))
+			target.FieldByName("Kind").Set(reflect.ValueOf(&stpb.Value_StructValue{sv}))
 			return u.unmarshalValue(reflect.ValueOf(sv).Elem(), inputValue, prop)
 		} else {
 			return fmt.Errorf("unrecognized type for Value %q", ivStr)