Groovy(Spock)からKotlinのCompanion Objectを呼び出す #groovy #spock #kotlin
概要
最近はJavaではなくKotlinを書いていますが、Spockが好きすぎるのでテストはGroovyで書いたりします。
KotlinのCompanion Objectをテストするときに、Groovy側から呼び出す方法です。
Companion Object
Kotlinではクラスに静的なメソッドを定義する時はCompanion Objectを使います。
Javaのstaticみたいなものと自分は理解しています。
class Sample { companion object { // 大文字にするメソッド fun toUpper(s: String): String = s.toUpperCase() } }
こうするとKotlin側では Sample.toUpper("hoge")
のように呼び出せるようになります。
Groovy側での呼び出し方
GroovyではCompanionのメソッドを呼び出すには Direct field access operator
を使います。
class SampleSpec extends Specification { def 'hogeが大文字HOGEになる'() { when: def actual = Sample.@Companion.toUpper('hoge') then: actual == 'HOGE' } }
Groovyからの呼び出しにはCompanionオブジェクトを経由する必要があり、なおかつダイレクトアクセスである必要があります。
ダイレクトアクセスする方法は、アクセスするフィールドの前に @
を付けるだけです。
Companionを経由しない Sample.toUpper('hoge')
や、通常のフィールドアクセス Sample.Companion.toUpper('hoge')
では MissingMethodException
が発生します。
ダイレクトアクセスと通常のフィールドアクセスの違いですが、Groovyのフィールドアクセスは暗黙的にGetterが呼ばれるのに対し、ダイレクトアクセスの場合Getterは呼ばれずフィールドの直アクセスになります。
CompanionオブジェクトにはGetterがないので、直アクセスする必要があるのかなと想像しています。
JvmStatic
JvmStaticアノテーションを使えば、Groovyからでも直接メソッドを呼び出せるようになります。
@JvmStatic fun toUpper(s: String): String = s.toUpperCase()
ただ、テストコードのためにプロダクションコードに手を入れることになるので今回のようなケースではおすすめしません。
参考
Problems about accessing Kotlin companion object in Groovy? - Stack Overflow The Apache Groovy programming language - Operators