使用 Scala 宏解决对象转换

背景

在 GrowingIO 服务端的开发中,我们使用 gRPC 进行微服务之间的数据通信,每个提供服务的项目,都要定义一套自己的 Protobuf 消息格式,然后利用 protoc 去生成对应语言的适配代码。在我们维护的项目中,主要使用 Scala 语言来实现各个服务,每个服务都会定义一套自己的领域模型(一般是一些 case class),而 protoc 默认生成的 JVM 平台的代码是 Java 语言的,对应的 Protobuf 消息格式与 Scala 项目中定义的领域模型会存在一些对应关系,并且他们的属性往往会高度一致。当我们需要在这两种类型做数据转换时,会出现许多 protobuf-java 和 scala case class之间的转换代码。

一般情况下,protobuf-java 和 Scala 之间都能找到对应类型,比如 java.util.List 和 Seq/List/Array,Timestamp 和 ZonedDateTime,同时一些 Scala 中 Option 类型也可以用 protobuf 是一封装类型去表示,比如 Option[String] 可以用 StringValue 去表示。因为每个类型都有自己对应的特性,类型嵌套又会增加极大地增加复杂度,我们一直在找一个通用的转换方案,使用起来类型安全,并尽可能地省掉臃肿无味的代码。

参考了
https://github.com/playframework/play-json 的 Reader、Writer 设计设计理念和 https://github.com/scalalandio/chimney用 Scala 宏对类型转换的处理方式,我们最终使用了 Scala 宏结合隐式参数 DSL 设计的思路实现了 https://github.com/changvvb/scala-protobuf-java 一套解决方案。

方案效果

我们先在这里定义一个 case class User 和 Protobuf UserPB 来对比使用该方案前后的效果。

case class User (
  id:Long,
  name:String,
  phoneNumber: Option[String],
  hobbies: Seq[String]
)
message UserPB (
    int64 id = 1,
    string name = 2,
    google.protobuf.StringValue phone_number = 3,
    repeated string hobbies = 4
)

如果我们自己手写 scala case class 到 protobuf-java 的转换,效果将是这样的:

val user = User(1,"Jack",Some("1234567890"),Seq("ping pong", "reading"))
​
val builder = UserPB.newBuilder               // 新建一个 builder
builder.setId(user.id).setName(user.Name)     // 设置 id、name 字段
if(user.phoneNumber.isDefined) {     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值