如何使用scalapb在proto中定义Option[FiniteDuration]类型
proto3 + ScalaPB 实现FiniteDuration及Option[FiniteDuration]映射方案
1. 编写proto定义
使用谷歌官方的google.protobuf.Duration标准类型作为中间载体,同时开启proto3的optional语法实现可选字段:
syntax = "proto3"; // 导入依赖 import "google/protobuf/duration.proto"; import "scalapb/scalapb.proto"; message Message { int32 id = 1; // optional关键字默认映射为Scala Option类型,同时指定自定义映射类型 optional google.protobuf.Duration interval = 2 [ (scalapb.field).type = "scala.concurrent.duration.FiniteDuration" ]; }
2. 定义FiniteDuration类型转换器
自定义TypeMapper实现google.protobuf.Duration和Scala原生FiniteDuration的双向转换:
import com.google.protobuf.duration.Duration import scala.concurrent.duration.{FiniteDuration, SECONDS, NANOSECONDS} object ProtoTypeMappers { implicit val finiteDurationMapper: scalapb.TypeMapper[Duration, FiniteDuration] = scalapb.TypeMapper[Duration, FiniteDuration]( // proto转Scala protoDur => FiniteDuration(protoDur.seconds, SECONDS) + FiniteDuration(protoDur.nanos, NANOSECONDS) )( // Scala转proto scalaDur => Duration( seconds = scalaDur.toSeconds, nanos = (scalaDur.toNanos % 1000_000_000).toInt ) ) }
3. 配置ScalaPB编译参数
在build.sbt中添加配置,让生成的代码自动导入你定义的转换器隐式值:
Compile / PB.targets += scalapb.gen( // 替换为你实际的ProtoTypeMappers所在包路径 scalapbImports = Seq("your.project.package.ProtoTypeMappers._") ) -> (Compile / sourceManaged).value / "scalapb"
效果验证
完成上述配置后,ScalaPB自动生成的样例类就和需求完全一致:
case class Message(id: Int, interval: Option[FiniteDuration])
注意事项
- 需使用proto3 3.12及以上版本支持optional语法,若版本过低可将interval字段包裹在oneof中实现可选效果
- 转换时注意纳秒精度处理,避免丢数
- 转换器的包路径要和build.sbt中配置的导入路径一致,否则编译会报缺失TypeMapper的错误
内容的提问来源于stack exchange,提问作者coder25
相关产品推荐
相关产品推荐

