Protobuf 自动反射消息
根据 type name 创建 Message ,利用GetReflection()反射填充
- 用
DescriptorPool::generated_pool()
找到一个DescriptorPool对象
,它包含了程序编译的时候所链接的全部protobuf Message types
。 - 用
DescriptorPool::FindMessageTypeByName()
根据type name
查找Descriptor
。 - 再用
MessageFactory::generated_factory()
找到MessageFactory对象
,它能创建程序编译的时候所链接的全部protobuf Message types
。 - 然后,用
MessageFactory::GetPrototype()
找到具体Message Type
的default instance
。 - 最后,用
prototype->New()
创建对象。
message QueryAccount
{
// in
required string SQL = 1;
// out
optional int64 id = 2;
}
void ReflectionFill( google::protobuf::Message* Msg, const google::protobuf::Descriptor* MsgDescriptor, mysqlpp::Row& RowData )
{
using namespace google::protobuf;
// 遍历所有消息成员
for ( size_t i = 0;i < MsgDescriptor->field_count();i++ )
{
const FieldDescriptor* EachField = MsgDescriptor->field( i );
// 这里假定optinal的是返回值
if ( !EachField->is_optional() )
continue;
// sql的列
std::string FieldName = EachField->name();
// 返回的CPP类型
switch ( EachField->cpp_type() )
{
case FieldDescriptor::CPPTYPE_STRING:
{
std::string Result = RowData[FieldName.c_str()];
Msg->GetReflection()->SetString( Msg, EachField, Result );
}
break;
case FieldDescriptor::CPPTYPE_INT64:
{
// 从列取值
__int64 Result = RowData[FieldName.c_str()];
// 设置消息
Msg->GetReflection()->SetInt64( Msg, EachField, Result );
}
break;
}
}
}
void ParseMessage( mysqlpp::Connection& SQLConnection, const char* ProtoType, void* Data, size_t Size )
{
// 转载请注明来自 战魂小筑http://www.cppblog.com/sunicdavy
using namespace google::protobuf;
Message* Msg = NULL;
// 通过类型字符串查出消息类型信息
const Descriptor* MsgDescriptor = DescriptorPool::generated_pool()->FindMessageTypeByName(ProtoType);
if (MsgDescriptor == NULL )
return;
// 取消息原型
const Message* MsgPrototype = MessageFactory::generated_factory()->GetPrototype(MsgDescriptor);
if (MsgPrototype == NULL )
return;
// 不能用原型消息哦,要新的
Msg = MsgPrototype->New();
// 解析数据
Msg->ParseFromArray( Data, Size );
// 查找SQL指令
const FieldDescriptor* SQLField = MsgDescriptor->FindFieldByName("SQL");
if ( SQLField == NULL )
return;
// 使用反射查出值
std::string SQLCmd = Msg->GetReflection()->GetString( *Msg, SQLField );
// 进行SQL查询
mysqlpp::Query query = SQLConnection.query( SQLCmd.c_str() );
// 确认查询有效
mysqlpp::StoreQueryResult res = query.store();
if (!res)
return;
// 这里只取第一个消息
mysqlpp::Row RowData = *res.begin();
// 反射填充消息
ReflectionFill( Msg, MsgDescriptor, RowData );
// 测试返回数据
dbsvc::QueryAccount* qamsg = dynamic_cast<dbsvc::QueryAccount*>( Msg );
__int64 i = qamsg->id();
delete Msg;
}
int main(int argc, char* argv[])
{
mysqlpp::Connection con(false);
con.set_option(new mysqlpp::SetCharsetNameOption("gbk"));
if (!con.connect("testdb", "localhost", "root", "123"))
{
return -1;
}
else
{
dbsvc::QueryAccount Msg;
Msg.set_sql("select id from account where username = 'hello'");
std::string s;
Msg.SerializeToString( &s );
ParseMessage( con, "dbsvc.QueryAccount", (void*)s.data(), s.size() );
}
google::protobuf::ShutdownProtobufLibrary();
}
参考
1、http://www.cppblog.com/sunicdavy/archive/2011/12/14/162115.html
2、https://www.cnblogs.com/Solstice/archive/2011/04/03/2004458.html
3、https://my.oschina.net/cqcbw/blog/3048689