- (詳細な経緯や、理由、今も本当に必要なのか?は、あまり知らないけれど) playframeworkでは
javax.inject.Named
を継承してplay.inject.NamedImpl
というclassをJavaで 定義している - JavaのアノテーションをJavaで継承しているだけで、なぜScalaが関係してくるのか、というと、おそらく以下の2つの観点
以下それぞれの解決方法の例
Scala 3側で「Javaのアノテーションを継承したclass」を、直接型として扱える
か?
- 現状扱えない?ので、とりあえず、Scala側では親のアノテーションの型で扱えばよい
- そのためだけに Javaで 以下のようなコードを書いて、Scalaから見えないようにする(見えた瞬間にScala 3 compilerが死ぬ?ので)
public static Named named(String value) { return new play.inject.NamedImpl(value); }
JavaとScalaのコードを混ぜて同時にコンパイルする機能
- 同時にコンパイルすると、これは、結局Scala 3のcompilerがJavaにおける「アノテーション継承したclass」を参照することになってしまい、エラーが発生する
- よって「分割コンパイル」すればよい
- sbtは、sub projectに分けるなどして「ソースコードがJavaファイルしかない」ならば、javacを直接呼び、Scala compilerを経由しない
- あるいは、Javaファイル全てを先にjavacでcompileさせたいならば、sbt自体にcompileOrderというkeyがあるため、それで
compileOrder := CompileOrder.JavaThenScala
と設定すればよい - しかし、playのcore部分のJavaコードは、Scala部分と相互依存しているので、単純に全てのJavaコードを先にコンパイルするcompileOrderの手法は不可能である
- よって、sub projectに分けたpull reqを当初出したが、微妙な反応だった https://github.com/playframework/playframework/pull/11310
- よって、buildを複雑にして、1つのsub project内部でconfigを分けて、compile単位は分けるが、成果物としては1つになる、という複雑なことをした(イマココ
- https://github.com/playframework/playframework/pull/11337
- pull reqの説明に書いたが、slickで使われているテクニックである(他にあったっけ?)
- slickの場合はScala 2のmacroがコンパイル単位を、定義側と呼び出し側で分ける必要があるが、でもproject(成果物のjar)は、1つにしたい、みたいなお気持ちのはず?