Cloud Firestore で ServerTimestamp が null になる問題

AndroidでCloud Firestoreを使っていて、
データをCollectionに追加する際に、ServerTimestampを使って日時を設定していました。
以下のようなコードでもFirestoreには問題なく作成日時(createdAt)は保存されます。

/**
 * メッセージ
 *
 * @property id メッセージID
 * @property content メッセージの内容
 */
data class Message(
    val id: String,
    val content: String
) {
    @ServerTimestamp
    val createdAt: Date? = null
}

しかし、これと同時に購読処理を行なっている場合は注意が必要です。
例えば、チャット画面などで購読処理 & 送信(Collection追加) が同時に行われるケース。

FirebaseFirestore.getInstance()
  .collection("messages")
  .addSnapshotListener(MetadataChanges.INCLUDE) { snapshot, exception ->
      // 購読処理
      // ...
      val messages = snapshot.toObjects(Message::class.java)
  }

あれ、購読処理でうけとった createdAt が null になるぞ、、
これでだいぶハマりましたが、どうやらFirestoreの仕様のようです。

理想:Collection追加→ServerTimestampでcreatedAtを設定→購読処理
現実:Collection追加→購読処理→ServerTimestampでcreatedAtを設定

となるようです。

解決策として、toObject() の第二引数に、ServerTimestampの振る舞いを設定してあげてください。
今回は、ESTIMATE(おおよその時間)を設定しました。

firebase.google.com

FirebaseFirestore.getInstance()
  .collection("messages")
  .addSnapshotListener(MetadataChanges.INCLUDE) { snapshot, exception ->
     // 購読処理
     // ...
     val messages = snapshot.toObjects(Message::class.java, DocumentSnapshot.ServerTimestampBehavior.ESTIMATE)
  }

こうすることで、 createdAt は null ではなくなります^^