You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 00:01:07