JSpecify と Kotlin

Jetpack のライブラリでは、JSpecify を使うようになっている。

https://developer.android.com/jetpack/androidx/releases/compose-ui?hl=ja#1.8.0-alpha07

This library now uses JSpecify nullness annotations, which are type-use. Kotlin developers should use the following compiler arguments to enforce correct usage: -Xjspecify-annotations=strict, -Xtype-enhancement-improvements-strict-mode (Idfef8, b/326456246)

これは何を言っているのかというと、java コードに書くアノテーションの話で、java は Nullable な世界なので、そこに NonNull やら Nullable やらを持ち込む時に使うアノテーション。すると NonNull のコードかどうかエディタで書いている段階で判明させることができる。

Kotlin からしても java のコードを呼び出すときにこのアノテーションは重要で、java でこのアノテーションによって NonNull とされていたなら 、NonNull と、Nulllable と書かれていたなら Nullable として解析できる。

import androidx.annotation.Nullable;

public class SampleJavaLib {
    @Nullable
    public String createTextWithInteger(int integer) {
        if (integer > 0) {
            return "createdTextWithInteger: " + integer;
        } else {
            return null;
        }
    }
}

class SampleKotlinLib {
    private val sampleJavaLib = SampleJavaLib()

    init {
       // Initializer type mismatch: expected 'kotlin.String', actual 'kotlin.String?'. と出て、コンパイルすらできない。
        val createdTextWithInteger: String = sampleJavaLib.createTextWithInteger(0)
    }
}

ところでこのアノテーションだけどさまざまな出所があって、現状カオスな状態なので、標準的なものを定義しようという動きがあって、今回 Kotlin もそれに乗っかっている。それが JSpecify であり、つまり Jetpack もその流れに乗って今回の状況になっている。

jspecify.dev


ただし、現状だとコンパイルを防ぐことまでの挙動にはなっていない。JSpecify のアノテーションによって型の不一致を検知したとしても警告にとどまる。

これをコンパイルエラーにしよう、というのが今回の話で、つまり jetBrains の Nullable アノテーションとかと同じ挙動になる。コンパイルエラー扱いにするためのビルドオプションとして紹介されているのが to enforce correct usage: -Xjspecify-annotations=strict, -Xtype-enhancement-improvements-strict-mode ということ。

現時点での Android Studio の雛形ではこれを考慮したビルドオプションは付与されていないので、これを有効にしたいなら自力でつける必要はある。つまり、gradle に以下のような記述をすることになる。

    kotlinOptions {
        freeCompilerArgs = listOf(
            "-Xjspecify-annotations=strict",
            "-Xtype-enhancement-improvements-strict-mode"
        )
    }

一方で、Kotlin の時期バージョンとして 2.1.0 があるが、ここになるとこのようなビルドオプションは不要で、不要というかデフォルトの動作になり、警告ではなく、コンパイルエラーとして扱われる。

kotlinlang.org

そのため 2.1.0 にしたらこのビルドオプションはまた消さないといけないとは思うが、2.1.0 が出て慌てるよりも今の段階で有効にしてチェックした方が良いと思うので有効にしておくと良いと思う。