Kotlin 使用 protobuf 的正确方法(Maven)

背景

有一个后端的 Java/Kotlin 项目需要与同事的模块通信,协议是 protobuf。

这块我想用 Kotlin 来写,当然 Java 也不是不行。没想到踩了些坑,故以本文作记录。

文档

protobuf 官方是有 Kotlin 的教程的,但是并不全面,这是出现各种坑的根源。

另外,我原以为 protobuf 对 Kotlin 的专门支持是多年前就有的(指的是支持 Kotlin 的各种方便写法),然而我后来才发现是2021年才有,见 Announcing Kotlin support for protocol buffers

方法

1. 从 .proto 生成 .java .kt

首先找同事得到 .proto 文件,然后下载 protoc,解压后得到一个可执行文件。

然后按照官方教程,在命令行中执行

protoc --java_out=$DST_DIR --kotlin_out=$DST_DIR xxxxxx.proto

注意--java_out--kotlin_out都是需要的,当前版本的 protoc 对 Kotlin 的支持是在原来 Java 生成的基础上多了 Kotlin 的增强。

然后就得到了一些 .java .kt 文件。

2. Maven

把生成的文件放进项目中,可以发现编译是不能通过的,因为缺少 protobuf 相关库。我的项目是 Maven 的,所以在 pom.xml 中加上

<!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-kotlin -->
<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-kotlin</artifactId>
    <version>3.19.4</version>  <!-- version 要与之前 protoc 的版本对应 -->
</dependency>

这个 pom 的 artifactId (protobuf-kotlin) 是关键!!我看到的文档写的都是protobuf-java,就会导致生成的 .kt 里面的

@kotlin.OptIn(com.google.protobuf.kotlin.OnlyForUseByGeneratedProtoCode::class)

报找不到的错误,必须使用protobuf-kotlin

3. 使用

这里参照 Announcing Kotlin support for protocol buffers 举的例子,用了 Kotlin 之后,写法更简洁了。假设原来 Java 的是这样写:

DiceSeries series = DiceSeries.newBuilder()
    .addRoll(DiceRoll.newBuilder()
        .setValue(5))
    .addRoll(DiceRoll.newBuilder()
        .setValue(20)
        .setNickname("critical hit"))
    .build()

而 Kotlin 可以改成:

val series = diceSeries {
  rolls = listOf(
    diceRoll { value = 5 },
    diceRoll {
      value = 20
      nickname = "critical hit"
    }
  )
}

至于如何序列化和反序列化,继续用刚才的例子,序列化是这样的:

series.toByteArray()

反序列化:

DiceSeries.parseFrom(message)

发表评论