diff --git a/runtime/query.go b/runtime/query.go index 69f0ba1d6a7..4b031219c1f 100644 --- a/runtime/query.go +++ b/runtime/query.go @@ -48,8 +48,11 @@ func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values [] return fmt.Errorf("non-aggregate type in the mid of path: %s", strings.Join(fieldPath, ".")) } var f reflect.Value - f, props = fieldByProtoName(m, fieldName) - if !f.IsValid() { + var err error + f, props, err = fieldByProtoName(m, fieldName) + if err != nil { + return err + } else if !f.IsValid() { grpclog.Printf("field not found in %T: %s", msg, strings.Join(fieldPath, ".")) return nil } @@ -92,14 +95,26 @@ func populateFieldValueFromPath(msg proto.Message, fieldPath []string, values [] // fieldByProtoName looks up a field whose corresponding protobuf field name is "name". // "m" must be a struct value. It returns zero reflect.Value if no such field found. -func fieldByProtoName(m reflect.Value, name string) (reflect.Value, *proto.Properties) { +func fieldByProtoName(m reflect.Value, name string) (reflect.Value, *proto.Properties, error) { props := proto.GetProperties(m.Type()) + + // look up field name in oneof map + if op, ok := props.OneofTypes[name]; ok { + v := reflect.New(op.Type.Elem()) + field := m.Field(op.Field) + if !field.IsNil() { + return reflect.Value{}, nil, fmt.Errorf("field already set for %s oneof", props.Prop[op.Field].OrigName) + } + field.Set(v) + return v.Elem().Field(0), op.Prop, nil + } + for _, p := range props.Prop { if p.OrigName == name { - return m.FieldByName(p.Name), p + return m.FieldByName(p.Name), p, nil } } - return reflect.Value{}, nil + return reflect.Value{}, nil, nil } func populateRepeatedField(f reflect.Value, values []string, props *proto.Properties) error { diff --git a/runtime/query_test.go b/runtime/query_test.go index 82026a8ed84..07262fad67f 100644 --- a/runtime/query_test.go +++ b/runtime/query_test.go @@ -161,7 +161,7 @@ func TestPopulateParameters(t *testing.T) { }, filter: utilities.NewDoubleArray(nil), want: &proto3Message{}, - wanterr: errors.New("field already set for oneof"), + wanterr: errors.New("field already set for oneof_value oneof"), }, } { msg := proto.Clone(spec.want)