工作中经常用到protobuf的场景,但是由于protobuf不是明文信息,在调试和检查时不是很直观,于是就有转换为json的需求,方便排查。
json使用的jsoncpp库,自行补上头文件等。
void _field2json(const Message& msg, const FieldDescriptor *field, size_t index, Json::Value &jsonValue) { const Reflection *ref = msg.GetReflection(); const bool repeated = field->is_repeated(); switch (field->cpp_type()) { #define _CONVERT(type, ctype, sfunc, afunc) \ case FieldDescriptor::type: { \ const ctype value = (repeated)? \ ref->afunc(msg, field, index): \ ref->sfunc(msg, field); \ jsonValue = value; \ break; \ } _CONVERT(CPPTYPE_DOUBLE, double, GetDouble, GetRepeatedDouble); _CONVERT(CPPTYPE_FLOAT, double, GetFloat, GetRepeatedFloat); _CONVERT(CPPTYPE_INT64, INT64, GetInt64, GetRepeatedInt64); _CONVERT(CPPTYPE_UINT64, UINT64, GetUInt64, GetRepeatedUInt64); _CONVERT(CPPTYPE_INT32, INT32, GetInt32, GetRepeatedInt32); _CONVERT(CPPTYPE_UINT32, UINT32, GetUInt32, GetRepeatedUInt32); _CONVERT(CPPTYPE_BOOL, bool, GetBool, GetRepeatedBool); #undef _CONVERT case FieldDescriptor::CPPTYPE_STRING: { std::string scratch; const std::string &value = (repeated) ? ref->GetRepeatedStringReference(msg, field, index, &scratch) : ref->GetStringReference(msg, field, &scratch); if (field->type() == FieldDescriptor::TYPE_BYTES) jsonValue = base64_encode((const unsigned char *)value.c_str(), value.length()); else jsonValue = value.c_str(); break; } case FieldDescriptor::CPPTYPE_MESSAGE: { const Message& mf = (repeated) ? ref->GetRepeatedMessage(msg, field, index) : ref->GetMessage(msg, field); jsonValue = Protobuf2Json(mf); break; } case FieldDescriptor::CPPTYPE_ENUM: { const EnumValueDescriptor* ef = (repeated) ? ref->GetRepeatedEnum(msg, field, index) : ref->GetEnum(msg, field); jsonValue = ef->number(); break; } default: break; } //if (!jf) throw j2pb_error(field, "Fail to convert to json"); //return jsonRet; } Json::Value Protobuf2Json(const Message &msg) { Json::Value jsonRet; const Descriptor *d = msg.GetDescriptor(); const Reflection *ref = msg.GetReflection(); if (!d || !ref) return jsonRet; std::vector<const FieldDescriptor *> fields; ref->ListFields(msg, &fields); for (size_t i = 0; i != fields.size(); i++) { const FieldDescriptor *field = fields[i]; const std::string &name = (field->is_extension()) ? field->full_name() : field->name(); if (field->is_repeated()) { size_t count = ref->FieldSize(msg, field); if (!count) continue; for (size_t j = 0; j < count; j++) _field2json(msg, field, j, jsonRet[name][j]); } else if (ref->HasField(msg, field)) _field2json(msg, field, 0, jsonRet[name]); else continue; } return jsonRet; }