📘

[Android]Annotation 1.4.0で追加されたアノテーションについて

2022/06/18に公開

AndroidX の Annotation 1.4.0 で以下のアノテーションが追加されました。

  • @ReturnThis
  • @OpenForTesting
  • @DeprecatedSinceApi
  • @EmptySuper

@ReturnThis

このアノテーションはクラス、もしくはメソッドに付与して使います。
メソッドの戻り値が自身のクラスだった場合、そのメソッドをオーバーライドした時に自分自身のインスタンスを返すことを目的としています。
(ビルダーなどのために使うことを想定しているようです)

例えば以下のようなクラスがあったとします。

@ReturnThis
open class Builder {
    open fun number(number: Int): Builder {
        return this
    }

    open fun text(text: String): Builder {
        return this
    }
}

上記のクラスを以下のようにオーバーライドしたとします。

class MyClass : Builder() {
    override fun number(number: Int): Builder {
        return this // ○ : 自分自身のインスタンスを返している
    }

    override fun text(text: String): Builder {
        return MyClass() // × : 自分自身のインスタンスを返していない
    }
}

この場合、number メソッドの方は自分自身のインスタンスを返しているので問題ありません。
しかし、text メソッドの方は新しく作成したインスタンスを返しているため警告が表示されます。

以下のように特定のメソッドに対してアノテーションを設定することもできます。

open class Builder {
    @ReturnThis
    open fun someMethod(arg: Int): Builder {
        return this
    }
}

class MyClass : Builder() {
    override fun someMethod(arg: Int): Builder {
        return this
    }
}

@OpenForTesting

このアノテーションはクラス、メソッド、プロパティに付与して使います。
このアノテーションが付与されている場合、テストコードからのみ継承もしくはオーバーライドをすることを目的としています。

例えば以下のようなクラスがあったとします。

@OpenForTesting
open class SomeClass {
    open fun someMethod() {
    }
}

上記のクラスをアプリケーションのコードで継承すると警告が表示されます。

// × : SomeClass1 should only be subclassed from tests という警告が表示される
class MySomeClass1 : SomeClass()

テストコードで継承すると、警告は表示されません。

// ○ : テストコードからは継承可能.
class MySomeClass2 : SomeClass() 

@DeprecatedSinceApi

このアノテーションはクラスやメソッド、プロパティなどに付与して使います。
このアノテーションには API レベルの指定が可能であり、Min SDK バージョンがアノテーションに指定された API レベルより小さい場合にこのアノテーションが付与されたメソッドなどを呼び出すと警告が表示されます。

例えばバックポートのライブラリを使用していて、特定の API レベル以降ではプラットフォームの API が使えるような場合に使えます。

例えば以下のように minSdk が 24 で設定されていたとします。

build.gradle
android {
    defaultConfig {
        minSdk 24
    }
}

そして以下のようなクラスがあったとします。

class Api {
    @DeprecatedSinceApi(api = 21)
    fun someMethod1() {}

    @DeprecatedSinceApi(api = 25)
    fun someMethod2() {}

    @DeprecatedSinceApi(api = 30, message = "Use AlarmManager.notify instead")
    fun someMethod3() {}
}

@DeprecatedSinceApi(api = 28)
class Api2 {
    fun someMethod1() {}

    @DeprecatedSinceApi(api = 30)
    fun someMethod2() {}
}

上記のメソッドを呼び出した場合、Api#someMethod1 以外は警告が表示されます。

fun test(api: Api, api2: Api2) {
    api.someMethod1() // OK
    api.someMethod2() // This method is deprecated as of API level 25 という警告が出る.
    api.someMethod3() // This method is deprecated as of API level 30; Use AlarmManager.notify instead という警告が出る.

    api2.someMethod1()  // This method is deprecated as of API level 28 という警告が出る.
    api2.someMethod2()  // This method is deprecated as of API level 30 という警告が出る.
}

@EmptySuper

このアノテーションはメソッドに付与して使います。
このアノテーションが付与されているメソッドは空であるため、メソッドをオーバーライドした時に呼ぶ必要がないことを示します。

open class ParentClass {
    @EmptySuper
    open fun someMethod(arg: Int) {
        // ...
    }
}

class ChildClass : ParentClass() {
    override fun someMethod(arg: Int) {
        // × : No need to call super.someMethod; the super method is defined to be empty という警告が表示される.
        super.someMethod(arg)
    }
}

Discussion