Reputation: 629
I'm trying to construct parser by the proto at runtime. I create dynamic message pointer by DynamicMessageFactory
, and I want to cast the pointer to the exact type so that I can get access to some fields directly (instead of by reflection).
Here is my code, the ShortDebugString()
output seems fine. But I didn't get the right value of field id
. Why?
#include "MyData.pb.h" // I use generated pb codes at the same time.
/*
file: MyData.proto
message MyData {
int32 id = 1;
};
*/
static const std::string message_type = "MyData";
std::ifstream proto_ifs("MyData.proto");
std::string proto_content((std::istreambuf_iterator<char>(proto_ifs)),
std::istreambuf_iterator<char>());
ArrayInputStream raw_input(proto_content.c_str(), proto_content.size());
Tokenizer input(&raw_input, NULL);
FileDescriptorProto file_desc_proto;
Parser parser;
if (!parser.Parse(&input, &file_desc_proto)) {
std::cerr << "Failed to parse .proto definition:" << proto_content;
return -1;
}
if (!file_desc_proto.has_name()) {
file_desc_proto.set_name(message_type);
}
google::protobuf::DescriptorPool pool;
const google::protobuf::FileDescriptor* file_desc = pool.BuildFile(file_desc_proto);
const auto* message_desc = file_desc->FindMessageTypeByName(message_type);
google::protobuf::DynamicMessageFactory factory;
factory.SetDelegateToGeneratedFactory(true);
const google::protobuf::Message* prototype_msg;
prototype_msg = factory.GetPrototype(message_desc);
google::protobuf::Message* mutable_msg = prototype_msg->New();
MyData tmp;
tmp.set_id(111);
int32_t msg_len;
const char* msg_data = tmp.SerializeToArray(msg_data, msg_len);
mutable_msg->ParseFromArray(msg_data, msg_len);
const MyData& my_data = static_cast<const MyData&>(*mutable_msg);
std::cout << mutable_msg->ShortDebugString() << "\n";
std::cout << my_data.ShortDebugString() << "\n";
std::cout << my_data.id() << "\n";
outputs:
id: 111
id: 111
0
Upvotes: 2
Views: 2077
Reputation: 1400
Basically, you can't. There isn't an inheritance dependency between MyData
and the generic Message
that you have.
What you can do, though, is serialize the message and deserialize it again:
MyData my_data;
my_data.ParseFromString(mutable_msg->SerializeAsString());
Of course, this will copy all the data over, and the parsed message wouldn't benefit from any newer versions of the schema, such as new enum values.
Upvotes: 1