如何在将Ruby Protobuf Message转为JSON时保留原proto字段大小写?
解决Ruby中Protobuf转JSON保留蛇形字段名及处理包装类型的问题
要实现Protobuf Message转JSON时保留proto定义的蛇形命名(snake_case),同时解决double等包装类型字段被序列化为嵌套Hash的问题,可以通过自定义序列化逻辑来实现:
方案1:自定义序列化方法
编写一个递归方法,遍历Protobuf消息的所有字段,使用原始蛇形字段名,并自动处理包装类型的取值:
def to_snake_case_json(message) hash = {} message.descriptor.each_field do |field| key = field.name # 直接获取proto中定义的蛇形字段名 value = message[field] next if value.nil? || (value.respond_to?(:empty?) && value.empty?) # 处理DoubleValue、Int32Value等包装类型 if value.is_a?(Google::Protobuf::Message) && value.descriptor.name.end_with?('Value') hash[key] = value.value elsif value.is_a?(Google::Protobuf::Message) # 递归处理嵌套的Protobuf消息 hash[key] = to_snake_case_json(value) elsif value.is_a?(Array) # 处理数组类型,递归处理数组内的消息对象 hash[key] = value.map { |item| item.is_a?(Google::Protobuf::Message) ? to_snake_case_json(item) : item } else # 普通类型直接赋值 hash[key] = value end end hash.to_json end
使用示例
假设你有包含double包装类型的Protobuf定义:
message Person { string name = 1; int32 id = 2; string email_address = 3; google.protobuf.DoubleValue price = 4; }
在Ruby中使用自定义方法序列化:
person = Person.new( name: "Bob", id: 1, email_address: "foo@bar.com", price: Google::Protobuf::DoubleValue.new(value: 10.0) ) puts to_snake_case_json(person) # 输出结果: # {"name":"Bob","id":1,"email_address":"foo@bar.com","price":10.0}
方案2:扩展Protobuf Message类全局使用
如果需要在所有Protobuf消息中直接调用该方法,可以扩展Google::Protobuf::Message类:
module Google module Protobuf class Message def to_snake_case_json hash = {} descriptor.each_field do |field| key = field.name value = self[field] next if value.nil? || (value.respond_to?(:empty?) && value.empty?) if value.is_a?(Google::Protobuf::Message) && value.descriptor.name.end_with?('Value') hash[key] = value.value elsif value.is_a?(Google::Protobuf::Message) hash[key] = value.to_snake_case_json elsif value.is_a?(Array) hash[key] = value.map { |item| item.is_a?(Google::Protobuf::Message) ? item.to_snake_case_json : item } else hash[key] = value end end hash.to_json end end end end
之后所有Protobuf消息实例都可以直接调用to_snake_case_json方法:
person.to_snake_case_json
内容的提问来源于stack exchange,提问作者Simon Wong
相关产品推荐
相关产品推荐

