Android
Kotlin
architecture-components

RoomのTypeConverterを拡張関数で書く

Android Architecture ComponentsのRoomでは、直接SQLiteに格納できない型を格納する場合、変換するためのTypeConverterを実装してEntityやDaoなどで指定する必要があります。

TypeConverter | Android Developers

変換するためのメソッドに@TypeConverterアノテーションを付加するのですが、このアノテーションのドキュメントにはこう書いています。

Each converter method should receive 1 parameter and have non-void return type.

変換対象を唯一のパラメータとして受け取り、void以外の型を返せばいいようです。

拡張関数で書かれた関数をjavaにデコンパイルしたものを見たことがある方ならご存知かもですが、Kotlinの拡張関数はJavaから見ると拡張元の型を第1引数に持つメソッドになります。

class Sample {
    fun List<Int>.doubleSize() = this.size * 2
}

例えば、上記の拡張関数をデコンパイルすると

public final class Sample {
   public final int doubleSize(@NotNull List $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      return $receiver.size() * 2;
   }
}

のようになります。

したがって、TypeConverterをKotlinで書く際は次のように拡張関数で書くことが可能です。

class ListTypeConverter {
    @TypeConverter
    fun List<Int>.toCsvString(): String = joinToString(",")

    @TypeConverter
    fun String.toIntList(): List<Int> = split(",").map { it.toInt() }
}

クラスではなくobjectにしたい場合は一工夫 -> @JvmStaticが必要

object ListTypeConverter {
    @TypeConverter
    @JvmStatic
    fun List<Int>.toCsvString(): String = joinToString(",")

    @TypeConverter
    @JvmStatic
    fun String.toIntList(): List<Int> = split(",").map { it.toInt() }
}

おまけ