はじめに
ライブラリや共通で使われる処理を作っていると諸事情によりAPIをDeprecatedしたくなることがあると思います。
KotlinでもJavaと同じくDeprecated
アノテーションが使えるのですが、Kotlinでは代替のAPIへの置換をユーザにサジェストすることが出来ます。
今回、実際にDeprecatedを書いてみて非常に便利だったので紹介します。
実際の例
拙作のKotlin製ライブラリKotprefで、Kotpref
というobjectのbulk
をDeprecatedして、拡張関数bulk
に置き換える例で見てみます。
object Kotpref {
// 省略…
fun <T : KotprefModel> bulk(receiver: T, f: T.() -> Unit) {
// 省略…
}
}
inline fun <T : KotprefModel> T.bulk(block: T.() -> Unit) {
// 省略…
}
このbulk
は利用側では以下のようになっています。
Deprecatedアノテーションを使うことで、このソースに対して置換を行う方法について考えていきます。
object UserInfo : KotprefModel() {
var name: String by stringPrefVar()
}
class Example {
fun deprecateExample() {
Kotpref.bulk(UserInfo) {
name = "chibatching"
}
}
}
Deprecatedアノテーション
KotlinのDeprecatedアノテーションは最大3つの引数を取ります。
引数 | 意味 |
---|---|
message | 必須。ユーザに表示するメッセージ、空にしてもDeprecatedである旨は表示される。 |
replaceWith | 今回の肝、置換の方法を指定する。次で説明。 |
level | Deprecatedのレベルを指定する。デフォルトWARN 。HIDDEN を指定すると単純にAPIが見えなくなってしまい置換のサジェストもできないので注意。 |
ReplaceWith
今回の肝となるReplaceWith
アノテーションは次のように定義されています。
public annotation class ReplaceWith(val expression: String, vararg val imports: String)
このReplaceWith
アノテーションの一つ目の引数expression
で置換の方法を指定することが出来ます。
利用側では下のように置換できればDeprecatedされたAPIの移行を完了できるので、この置換ができるようなexpressionを考えてみます。
Kotpref.bulk(UserInfo) {
name = "chibatching"
}
// いい感じに↓のように置換したい
UserInfo.bulk {
name = "chibatching"
}
expressionを考える
ところで、あるAPIをDeprecatedして新しいAPIに移行したい時、DeprecatedしたAPIの実装はどうしてますか?
そのままというパターンもあると思いますが、新しいAPIを呼び出す実装にしていることが多いのではないでしょうか?
例えば、今回の場合だと↓こんな具合で。
fun <T : KotprefModel> bulk(receiver: T, f: T.() -> Unit) {
receiver.bulk(f) // 廃止するAPIでは新設するAPIを実行する
}
inline fun <T : KotprefModel> T.bulk(block: T.() -> Unit) {
// 省略…
}
なぜ突然こんなことを言い出したかというと、この新しいAPIを呼び出す部分。これがそのままexpressionとして使えるんです!
なので、DeprecatedしたいAPIの宣言はこうなります。
@Deprecated(
message = "",
replaceWith = ReplaceWith("receiver.bulk(f)")
)
fun <T : KotprefModel> bulk(receiver: T, f: T.() -> Unit) {
receiver.bulk(f)
}
これだけで、IDE上でDeprecatedの警告と一緒に新しいAPIへの置換をサジェスト&自動置換ができるようになってしまいます。
実際に置換を行ってみるとAndroidStudio上では↓のようになります。
このようにメソッドの引数やブロックをいい感じに展開して置換してくれていることがわかります。
また、明示的にimportを追加したい場合にもReplaceWith
の第2引数で指定することが可能です。
公式ドキュメントだけではどのような書き方が出来るのかほとんどわからないので、他にどんな書き方ができるかはKotlinのソースを見てみるのがいいと思います。
Search Results
さいごに
引数が増える場合など、今回の例のように綺麗に置換できないパターンも多いとは思いますが、うまく一発で置換できると気持ちいいです。
また、一括置換もできるのでReplaceWith
がしっかりと機能するようにしておけば、ユーザ側の新APIへの移行もスムーズに行えるのではないでしょうか。