Reflection in protobuf (C++/Java)
最近工作中,需要做一些消息动态解析,因为使用的 protobuf,考虑使用protobuf的反射特性。
1 reflection in C++
在c++中使用protobuf 反射
|
|
C++和Java 不同的是: c++有一个全局的pool,管理了所有定义在 proto 文件里的消息原型, 我们可以通过消息全称,查找到对应的单例的消息原型,然后通过原型构造可变的消息。
|
|
当我们通过消息原型new一个可变的消息对象,就可以对消息进行动态赋值了,如下:
int ParseUtil::ReflectionTest() {
std::string fullname = "com.sunquan.Login";
const google::protobuf::Message* pMsgFactory = FindMsgProtoType(fullname);
if (pMsgFactory == NULL){
std::cerr << "CreateMessage() fail!" <<std::endl;
return 0;
}
//new mutable msg
google::protobuf::Message* pMsg = pMsgFactory->New();
const google::protobuf::Descriptor *pdesc = pMsgFactory->GetDescriptor();
const google::protobuf::Reflection *refl = pMsgFactory->GetReflection();
// 动态查找一个 FieldDesc
std::string fieldname = "username";
const google::protobuf::FieldDescriptor* pfield = pdesc->FindFieldByName(fieldname);
if (pfield) {
// 暂不支持 repeat 类型
if (pfield->is_repeated()) {
std::cerr << "repeat field is not support!" << fieldname << std::endl;
continue;
}
switch (pfield->cpp_type()) {
case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT32:
//if(oneRow[i].type() == QVariant::Date)
refl->SetInt32(pMsg, pfield, 100);
break;
case google::protobuf::FieldDescriptor::CppType::CPPTYPE_INT64:
refl->SetInt64(pMsg, pfield, 100LL);
break;
case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT32:
refl->SetUInt32(pMsg, pfield, 100);
break;
case google::protobuf::FieldDescriptor::CppType::CPPTYPE_UINT64:
refl->SetUInt64(pMsg, pfield, 100ULL);
break;
case google::protobuf::FieldDescriptor::CppType::CPPTYPE_DOUBLE:
refl->SetDouble(pMsg, pfield, 100.89);
break;
case google::protobuf::FieldDescriptor::CppType::CPPTYPE_FLOAT:
refl->SetFloat(pMsg, pfield, 100.98);
break;
case google::protobuf::FieldDescriptor::CppType::CPPTYPE_BOOL:
refl->SetBool(pMsg, pfield, true);
break;
case google::protobuf::FieldDescriptor::CppType::CPPTYPE_STRING:
refl->SetString(pMsg, pfield, "name");
break;
default:
//NoSupport CPPTYPE_ENUM/CPPTYPE_MESSAGE
std::cout << "UnSupport Type=" << pfield->type_name() << std::endl;
break;
}
}
//if no longer use, please remember delete "pMsg"
if (pMsg) delete pMsg;
return 0;
}
2 reflection in Java
在Java中使用的protobuf反射。 1 已知消息名称,查找到该消息类型的 Descriptor,然后根据序列化的字节码,动态构建对象。
|
|
2 预先准备好所有可能的消息,动态解析 把所有可能的消息的 Descriptor 加入到 Map,然后从Map中查找。
|
|
3 动态修改消息字段值 wait