作りました。
実際に最初に作ったのは1年以上前で、仕事のコードの一部に入れていたのですが、いろいろ整理したり機能加えて、OSSにして公開しました。
以下関連コミット
- https://github.com/scalapb-json/scalapb-json-common/commit/2fe22d44722bbe91eac8fd1fcdb1c51d52346d0f
- https://github.com/scalapb-json/scalapb-circe/commit/16e9de81c9af398dfe860b86b365dde9a7b357cd
- https://github.com/scalapb-json/scalapb-argonaut/commit/d005682626cf363083ca6871bfc2d1c42be385db
- https://github.com/scalapb-json/scalapb-playjson/commit/b00606a7c8d6c0808645550f4e167705a6a5b0dd
リポジトリ自体は、以前書いたこれ
を使い、別のartifactとして追加しました。(つまりsbtのマルチプロジェクトに変えた)
マクロでコンパイル時にjsonリテラルや、protobufのtextformatのリテラルをparseして、コンパイル時チェック(不正だったらコンパイルエラー)にしてくれる機能があります。コンパイル時にparseするやつは、完全なリテラルのStringしか対応してません。
また、protobufにはstructやvalueという、json用の型もあるのですが、それらをマクロでコンパイル時にparseして組み立てる機能も入れました。
また、コンパイル時にはチェックしないけど、Javaのclassに一旦変換する関係上、(Java <=> Scalaのclass名の規則が特殊な場合もあって面倒なので)、"コンパイル時リフレクション"を使って、いい感じに一発で変換する機能もつけました。
以下のようなことに悩んでいたけれど、
コンパイル時はマクロ内で呼び出すためにJVM用の
— Kenji Yoshida (@xuwei_k) December 29, 2018
foo_2.12
に依存し使用するが、
実行時にマクロが生成したコード内では
foo_sjs0.6_2.12
に依存したい、みたいなことやろうと格闘していたのだけど、これ原理的に可能なのだろうか
マクロ実行時にはJVMの方を呼び出したいが、その後マクロが生成したコードを展開した後のリンク時にはsjsの方にリンクされてほしいが、JVMの方にリンクされて、実行時の依存だけsjsの方に変えてもリンクが正しくないので(かつsjsとjvmで依存ライブラリの中身が微妙に違うせいで?)エラーになる、難しい
— Kenji Yoshida (@xuwei_k) 2018年12月29日
やりたいのは"json"→"protobufから生成したcase class"への変換なのだが(jvmならすでに動いている。コンパイル時に正当性チェックするからマクロ使う)
— Kenji Yoshida (@xuwei_k) 2018年12月29日
1. 適当なwrapper作ってjvmとjsでclass名変えて呼び出してみる(本当にうまくいくか謎)
2. 1と似てるが同じライブラリ使うの諦めてコンパイル時と実行時で別のjsonライブラリ使う(ひとまず一番簡単で現実的?)
— Kenji Yoshida (@xuwei_k) 2018年12月29日
3. 任意のprotobufのcase classに関するLiftableのインスタンスをコンパイル時に生成する仕組み作り、すべてをコンパイル時に組み立てることで実行時の依存を消す(可能なのか?)
一部のモジュールは結局scala-jsやscala-nativeでも動いた気がします。単純な設定ミスだったのか、たまたま動いてるだけで実は潜在的に問題があるのか?は、よくわかってません。
使い方の例とかドキュメント全然ないけど、まぁテストコード見てください・・・。 気が向いたらもう少し書くかもしれません or pull reqください