掲題の件について、若干詰まったのでブログに残す。
…
やりたいこと
以下のようなinternal classを
@Service
internal class SubService { /* .. */ }
以下のようなclassにconstructor injectionさせたい
@Service
class MainService(private val subService: SubService) { /* .. */ }
SubServiceとMainServiceは同じパッケージとする。
え?普通にできないんだっけ?
上記例はコンパイルエラーになる。
なぜなら、publicなclassのprimaryコンストラクタはpublicスコープであり、
そこにintenalスコープのclassのインスタンスを引数に取れないから。
解決策① constructor injectionを諦める
これが一番簡単。だが、そもそも掲題の前提条件を満たしていないように思う。
@Service
class MainService {
@Autowired
private val subService: SubService
/* .. */
}
解決策② MainServiceもinternalスコープにしちゃう
MainServiceもinternalスコープにしてしまえば、primaryコンストラクタもinternalスコープになるので
コンパイルエラーにならなくなる。
ただ、パッケージ外のMainServiceに依存するクラスがMainServiceをみれなくなるので、
MainServiceをpublicなinterfaceにして、実装クラスをinternalスコープにする。
interface MainService { /* .. */ }
@Service
internal class MainServiceImpl(private val subService: SubService): MainService {
/* .. */
}
一瞬SpringがちゃんとMainServiceImplをInjectionしてくれるのかなと不安になったけど、問題なく動作した。
Spring以外のフレームワークを使っていて、internalスコープのclassを他パッケージにinjectさせたい場合は、
publicなMainServiceFactoryを作れば解決できそう。
以上