C++ 实用技术 - google protobuf反射技术 - 转成JSON格式

    xiaoxiao2025-01-21  6

    C++ 实用技术 - google protobuf反射技术 - 转成JSON格式

    方法思路精简代码测试的proto文件完整代码(Google Protobuf to Json)其他相关

    方法思路

    利用google protobuf的反射技术,实现对任意Message进行遍历,并将Message的各个已知属性和未知的属性,写入到JSON的结构里

    精简代码

    void serialize_message(const google::protobuf::Message& message, Json::Value& jnode) { const google::protobuf::Descriptor* descriptor = message.GetDescriptor(); const google::protobuf::Reflection* reflection = message.GetReflection(); for(int i = 0; i < descriptor->field_count(); ++i) { const google::protobuf::FieldDescriptor* field = descriptor->field(i); ... if(field->is_repeated()) { //解析repeated的字段 ... } else { //解析非repeated的字段 ... } } const auto& ufs = reflection->GetUnknownFields(message); //处理UnknownField字段 ... }

    测试的proto文件

    package test; enum Type { TYPE_INT = 0; TYPE_FLOAT = 1; } message B { optional string str = 1; repeated int32 i32 = 2; repeated float f = 3; repeated bool b = 4; optional Type t = 5; } message A { optional string name = 1; optional int32 age = 2; optional int32 sex = 3; repeated B bs = 4; } message C { optional string name = 1; }

    完整代码(Google Protobuf to Json)

    #include <google/protobuf/message.h> #include <sstream> #include <iostream> #include <stdint.h> #include <json/json.h> #include "test.pb.h" void serialize_unknowfieldset(const google::protobuf::UnknownFieldSet& ufs, Json::Value& jnode) { std::map<int, std::vector<Json::Value> > kvs; for(int i = 0; i < ufs.field_count(); ++i) { const auto& uf = ufs.field(i); switch(uf.type()) { case google::protobuf::UnknownField::TYPE_VARINT: kvs[uf.number()].push_back((Json::Int64)uf.varint()); //jnode[std::to_string(uf.number())] = (Json::Int64)uf.varint(); break; case google::protobuf::UnknownField::TYPE_FIXED32: kvs[uf.number()].push_back((Json::UInt)uf.fixed32()); //jnode[std::to_string(uf.number())] = (Json::Int)uf.fixed32(); break; case google::protobuf::UnknownField::TYPE_FIXED64: kvs[uf.number()].push_back((Json::UInt64)uf.fixed64()); //jnode[std::to_string(uf.number())] = (Json::Int64)uf.fixed64(); break; case google::protobuf::UnknownField::TYPE_LENGTH_DELIMITED: google::protobuf::UnknownFieldSet tmp; auto& v = uf.length_delimited(); if(!v.empty() && tmp.ParseFromString(v)) { Json::Value vv; serialize_unknowfieldset(tmp, vv); kvs[uf.number()].push_back(vv); //jnode[std::to_string(uf.number())] = vv; } else { //jnode[std::to_string(uf.number())] = v; kvs[uf.number()].push_back(v); } break; } } for(auto& i : kvs) { if(i.second.size() > 1) { for(auto& n : i.second) { jnode[std::to_string(i.first)].append(n); } } else { jnode[std::to_string(i.first)] = i.second[0]; } } } void serialize_message(const google::protobuf::Message& message, Json::Value& jnode) { const google::protobuf::Descriptor* descriptor = message.GetDescriptor(); const google::protobuf::Reflection* reflection = message.GetReflection(); for(int i = 0; i < descriptor->field_count(); ++i) { const google::protobuf::FieldDescriptor* field = descriptor->field(i); if(field->is_repeated()) { if(!reflection->FieldSize(message, field)) { continue; } } else { if(!reflection->HasField(message, field)) { continue; } } if(field->is_repeated()) { switch(field->cpp_type()) { #define XX(cpptype, method, valuetype, jsontype) \ case google::protobuf::FieldDescriptor::CPPTYPE_##cpptype: { \ int size = reflection->FieldSize(message, field); \ for(int n = 0; n < size; ++n) { \ jnode[field->name()].append((jsontype)reflection \ ->GetRepeated##method(message, field, n)); \ } \ break; \ } XX(INT32, Int32, int32_t, Json::Int); XX(UINT32, UInt32, uint32_t, Json::UInt); XX(FLOAT, Float, float, double); XX(DOUBLE, Double, double, double); XX(BOOL, Bool, bool, bool); XX(INT64, Int64, int64_t, Json::Int64); XX(UINT64, UInt64, uint64_t, Json::UInt64); #undef XX case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: { int size = reflection->FieldSize(message, field); for(int n = 0; n < size; ++n) { jnode[field->name()].append(reflection->GetRepeatedEnum(message, field, n)->number()); } break; } case google::protobuf::FieldDescriptor::CPPTYPE_STRING: { int size = reflection->FieldSize(message, field); for(int n = 0; n < size; ++n) { jnode[field->name()].append(reflection->GetRepeatedString(message, field, n)); } break; } case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { int size = reflection->FieldSize(message, field); for(int n = 0; n < size; ++n) { Json::Value vv; serialize_message(reflection->GetRepeatedMessage(message, field, n), vv); jnode[field->name()].append(vv); } break; } } continue; } switch(field->cpp_type()) { #define XX(cpptype, method, valuetype, jsontype) \ case google::protobuf::FieldDescriptor::CPPTYPE_##cpptype: { \ jnode[field->name()] = (jsontype)reflection->Get##method(message, field); \ break; \ } XX(INT32, Int32, int32_t, Json::Int); XX(UINT32, UInt32, uint32_t, Json::UInt); XX(FLOAT, Float, float, double); XX(DOUBLE, Double, double, double); XX(BOOL, Bool, bool, bool); XX(INT64, Int64, int64_t, Json::Int64); XX(UINT64, UInt64, uint64_t, Json::UInt64); #undef XX case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: { jnode[field->name()] = reflection->GetEnum(message, field)->number(); break; } case google::protobuf::FieldDescriptor::CPPTYPE_STRING: { jnode[field->name()] = reflection->GetString(message, field); break; } case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: { serialize_message(reflection->GetMessage(message, field), jnode[field->name()]); break; } } } const auto& ufs = reflection->GetUnknownFields(message); serialize_unknowfieldset(ufs, jnode); } std::string JsonToString(const Json::Value& json) { Json::FastWriter w; return w.write(json); } int main(int argc, char** argv) { test::A a; a.set_name("a\"'name"); a.set_age(10); a.set_sex(5); for(int i =0; i < 5; ++i) { test::B* b = a.add_bs(); b->set_str("str_" + std::to_string(i)); for(int n = 0; n < 3; ++n) { b->add_i32(rand()); b->add_f(rand()); } b->set_t(test::TYPE_INT); } Json::Value vv; serialize_message(a, vv); std::cout << JsonToString(vv) << std::endl; std::string data; a.SerializeToString(&data); test::C c; c.ParseFromString(data); Json::Value jnode; serialize_message(c, jnode); std::cout << JsonToString(jnode) << std::endl; std::cout << "DebugString: " << c.DebugString() << std::endl; return 0; }

    其他相关

    C++ Google Protobuf 反射技术基础API C++ 实用技术 - google protobuf反射技术 - 转成YAML格式

    最新回复(0)