jason135
jason135

Reputation: 189

how to use protobuf.any in golang

I'm using grpc in my go project. Below is code:

example.proto:

syntax = "proto3";

message Example {
    string message = 1;
    google.protobuf.Any details = 2;
}

main.go

func logMessage (m string, d interface{}) {
    message := & example.message{
       message: m,
       details: ??
    }    
    log(&message)
}

But I'm not sure how to deal with the details(interface{}) field. I know I can use any type for interface, but not sure how to use it here. Anyone can help? Thanks

Upvotes: 9

Views: 34603

Answers (5)

Razi Ahmad
Razi Ahmad

Reputation: 1

func ConvertInterfaceToAny(v interface{}) (*any.Any, error) {
 anyValue := &any.Any{}
 bytes, _ := json.Marshal(v)
 bytesValue := &wrappers.BytesValue{
    Value: bytes,
 }
 err := anypb.MarshalFrom(anyValue, bytesValue, proto.MarshalOptions{})
 return anyValue, err

}

Upvotes: -1

EM 790
EM 790

Reputation: 1

func interfaceToAny(v interface{}) (*anypb.Any, error) {
    bytes, err := json.Marshal(v)
    if err != nil {
        println("error json.Marshal interfaceToAny")
        return nil, err
    }
    m := api.Bytes{B: bytes}
    return anypb.New(&m)
}

message Bytes {
  bytes b = 1;
}

Upvotes: -1

wurui
wurui

Reputation: 31

func pbany(v interface{}) (*anypb.Any, error) {
pv, ok := v.(proto.Message)
if !ok {
    return &anypb.Any{}, fmt.Errorf("%v is not proto.Message", pv)
}
return anypb.New(pv)

use anypb.New api, In your code, pass d to pbany function

Upvotes: 3

igorushi
igorushi

Reputation: 1995

Since protobuf/ptypes is deprecated, it worth using anypb.UnmarshalTo

import (
    "google.golang.org/protobuf/types/known/anypb"
    "github.com/golang/protobuf/ptypes/any"
)

func Unmarshal(data *any.Any) (*YourMessage, err) {
    var m YourMessage
    err := anypb.UnmarshalTo(data, &m, proto.UnmarshalOptions{})
    return &m,err
}

Upvotes: 13

Marc
Marc

Reputation: 21035

The protobuf/ptypes package has utilities to convert to/from arbitrary proto messages to any:


MarshalAny:

func MarshalAny(m proto.Message) (*anypb.Any, error)

MarshalAny marshals the given message m into an anypb.Any message.


UnmarshalAny:

func UnmarshalAny(any *anypb.Any, m proto.Message) error

UnmarshalAny unmarshals the encoded value contained in the anypb.Any message into the provided message m. It returns an error if the target message does not match the type in the Any message or if an unmarshal error occurs.


In your example, you would use something along the lines of:

func logMessage (m string, d proto.Message) {
    details, err := ptypes.MarshalAny(d)
    if err != nil {
        panic(err)
    }
    message := & example.message{
        message: m,
        details: details
    }    
    log(&message)
}

Upvotes: 11

Related Questions