Murat
Murat

Reputation: 445

Room TypeConverter with constructor

I have Room TypeConverter and I need to inject parameter to it's constructor

class RoomConverters(moshi Moshi) {

    @TypeConverter
    fun fromUserActionLog(data: UserActionLogModel): String {
        return moshi.adapter(UserActionLogModel::class.java).toJson(data)
    }

    @TypeConverter
    fun toUserActionLog(json: String): UserActionLogModel {
        return moshi.adapter(UserActionLogModel::class.java).fromJson(json)}
    }
}

But when I can not annotate TypeConverter to database object with contructor;

@Database(entities = [SsidModel::class], version = 1, exportSchema = false)
@TypeConverters(RoomConverters::class)   
abstract class AppDatabase : RoomDatabase() {

    abstract fun ssidDao(): SsidDao
}

Is there any way to achieve this?

Upvotes: 16

Views: 5016

Answers (5)

Nataraj KR
Nataraj KR

Reputation: 1102

Now that 2.3.0 of Room library is released. It is possible to instantiate Room type converters and provide them to database builder.

Add @ProvidedTypeConverter annotation to the TypeConverter class.

@ProvidedTypeConverter
class RoomConverter(moshi Moshi) {

    @TypeConverter
    fun fromUserActionLog(data: UserActionLogModel): String {
        return moshi.adapter(UserActionLogModel::class.java).toJson(data)
    }

    @TypeConverter
    fun toUserActionLog(json: String): UserActionLogModel {
        return moshi.adapter(UserActionLogModel::class.java).fromJson(json)}
    }
}

Mention the TypeConverter in the @TypeConverter annotation of the database abstract class.

@Database(entities = [/* entities here */], version = 1, exportSchema = false)
@TypeConverters(RoomConverters::class)   
abstract class AppDatabase : RoomDatabase() {
    ......
    // your code here
    ......
}

Now build the database using the static method databaseBuilder of Room class and provide TypeConverter using the method addTypeConverter()

val roomConverter = RoomConverter(moshi)
val appDb = Room.databaseBuilder(
                            applicationContext,
                            AppDatabase::class.java, DB_NAME
                        )
                            .addTypeConverter(roomConverter)
                            .build()

Upvotes: 10

m.myalkin
m.myalkin

Reputation: 1158

You can create Room TypeConverter with constructor parameters from version 2.3.0-alpha03

Release notes:

Room now has APIs for providing instances of type converters such that the app can control their initialization. To mark a type converter that will be provided to Room use the new annotation @ProvidedTypeConverter

https://developer.android.com/jetpack/androidx/releases/room#2.3.0-alpha03

In your case you should add @ProvidedTypeConverter to RoomConverter

@ProvidedTypeConverter    
class RoomConverters(moshi: Moshi)

Create converter at db creation time and pass it to database builder:

val roomConverter = RoomConverters(Moshi())
val db = Room.databaseBuilder()
         .addTypeConverter(roomConverter)
         .build()

Also you can use DI framework e.g. Dagger2

Upvotes: 19

Cody
Cody

Reputation: 1879

As of August 11th 2020 there's still no fix for this from Google. Check either of these workarounds in the meantime.

https://issuetracker.google.com/issues/142086380 https://issuetracker.google.com/issues/121067210

Upvotes: 0

Paweł Dedio
Paweł Dedio

Reputation: 1358

I checked documentation even for the newest rc version (2.2.0-rc01) and there is no way to do that. I think it's a joke that we can't register custom TypeConverters in DatabaseBuilder, so I created bug for that on Google issue tracker.

Upvotes: 2

Sergey Motyrev
Sergey Motyrev

Reputation: 61

I use dagger-android, and faced same problem. Solution is when creating AppDatabase

@Provides @Reusable
fun provideDatabase(context: Context, moshi: Moshi): AppDatabase = 
    Room.databaseBuilder(...).build().apply { AppDatabase.moshi = moshi }

AppDatabase is simple RoomDatabase:

@Database(
    entities = [OrderEntity::class],
    version = 1,
    exportSchema = false
)
@TypeConverters(DbConverters::class)
abstract class AppDatabase : RoomDatabase() {
    companion object {
        lateinit var moshi: Moshi
    }

    abstract fun orderDao(): OrderDao
}

Then use this companion object in converter:

class DbConverters {

    @TypeConverter
    fun orderInfoToString(orderInfo: OrderInfo?): String? = 
           AppDatabase.moshi.adapter(OrderInfo::class.java).toJson(orderInfo)

    @TypeConverter
    fun stringToOrderInfo(value: String): OrderInfo? = 
          AppDatabase.moshi.adapter(OrderInfo::class.java).fromJson(value)
}

This is looking ugly, I guess, but works. Maybe using static/companion object with @Reuseable scope is a bad idea. Moshi, though, is provided using @Singleton scope in AppModule, so basically live through entire application life

Upvotes: 2

Related Questions