大量と言っても、これ書いてる時点ではまだ3つです。
(実装の共通化のための scalapb-json-common というのを除いて。逆にそれ含めれば4つ)
- https://github.com/scalapb-json/scalapb-argonaut
- https://github.com/scalapb-json/scalapb-circe
- https://github.com/scalapb-json/scalapb-playjson
以前から仕事などでScalaPB使っているわけですが、
これ書いている現在、公式にはjson4s用しかなく
https://github.com/scalapb/scalapb-json4s
play-json使ったライブラリも誰かが作っていたのですが、あまりメンテされないので、ある意味forkしてリリースしました。 "ある意味" とは、一応gitの履歴は引き継いだのですが、途中で本体のscalapb-json4sに同期させつつ結構書き換えたので、それならgitの履歴引き継ぐ必要なかったのでは? と、後から思ったので。
話を変えるというか、本題的な重要なところの説明にいくと、 そもそもprotobufのversion 3以降は公式的にjson変換の仕様が決まっています。詳細は公式や、以下の自分が書いたやつ見てください。
- https://github.com/xuwei-k/scala-protobuf-docs/blob/0961bc00baa7/src/json.md
- https://developers.google.com/protocol-buffers/docs/proto3#json
- http://xuwei-k.github.io/scala-protobuf-docs/json
それで、上記の自作のドキュメントにも書いてありますが、javaのやつ使えばそこまで困らないというか、変換規則が意外とややこしい部分があるので、javaのものを使ったほうが安心できるわけですが、(個人的に今後使うかどうか?は別にして)ScalaPBのコミュニティ的にscala-jsの需要があったり、json4sだけだとjson4s使わざるを得なくて、json4sはリフレクションの黒魔術などが理由で個人的にあまり広まってほしくないので、 やはり他のjsonライブラリのバインディングもあったほうがいいか、と思って、年末年始で作りました。
コード自体は、scalapb-json4sを改変するだけなので、わりと単純作業のほうが多く、そこまで難しいことはしてないです。 もちろん今までのScalaPBやscala-js対応の経験があるから難しくない、といえばそうですが。
scala-js部分とJVMのみの部分(シリアライズやデシリアライズ結果が公式のjavaと同じになるか?のテストなど)の切り分けが面倒でした。あとscala-jsではそのままで動かないクラスがあったので(java.util.{Date, Calendar}, java.text.SimpleDateFormat など) Java8 のtimeのものに書き換えつつ、scala-js公式以外のライブラリに依存させるなどの工夫が面倒でした
- https://github.com/cquiroz/scala-java-time
- https://github.com/scalapb-json/scalapb-json-common/blob/e3edd960d/build.sbt#L35
ScalaPB作者的には、以下のように言っており
Thanks for working on this @xuwei-k . I've been spending time on getting it to work with Circe. It would be nice to find a way to get a single core implementation that is applied to each of the many JSON libraries that are around. I looked into Jawn but it has no ScalaJS support.
たしかにそれができたらいい面もありますが、以下のような理由によりそこまで全部共通化せずに、適度に共通化しつつ、コピペして作りました
- ScalaPB作者が言うようにjawnなどは使えそうでscala-js対応の問題など、かゆいところに手が届かない可能性がある
- そういう方法だと、かなり工夫しないと、パフォーマンスのオーバーヘッド発生しそう?
- 一度作ってしまえば、protobufとjsonの変換規則は頻繁に変更されないはずなので、問題ない?
- argonaut, circe, play-json と3つ対応をやって実感したが、jsonのAST作成時はともかく、分解のインターフェイス(パターンマッチサポートするか否か?)が全然違って厳しそう
- 数値の扱いが細かいこと考えると色々違って面倒。たとえば数値の実装がBigDecimalベースなのか(play-jsonはそれだけ)、LongやIntやDoubleやFloatを保持するパターンもあるのか?(play-json以外はわりとそう)、NaNやInfinityの扱いも色々違って細かいことに対応しづらくなりそう
もしScalaPB作者が今後そういった "さらに共通化された方法" で別途ライブラリをリリースしたら、それはそれで自分のやつは別々にメンテしていくか、メンテやめるのかわかりませんが、とにかくjson4s用のライブラリしか存在しない現状よりは選択肢が増えるのはいいことだろう、と思ったのでさっさとリリースしました。
あと、他のjsonライブラリのバインディングも作るかもしれないし、まとまっていたほうが見やすいだろうし、travisのjobが別々に動かせることもあって、わざわざgithubのorganizationと、maven centralのgroupIdも申請して、発行してもらいました。 まだ正月なのに、sonatypeの人わりといつもどおりに(人力で?)すぐにチェックして発行してくれました。ありがとうございます。
argonautとcirceとplay-jsonにしたのは、それなりに知名度があり自分が知っていて、全部scala-js対応してるから、くらいな理由で、そこまで深い理由はありません。先程も書きましたが、気が向けば他のjsonライブラリの対応も、するかもしれないし、しないかもしれません。