Reputation: 3572
I get this error:
error: Cannot figure out how to save this field into database. You can consider adding a type converter for it. private final java.util.List<com.example.Detail.Stat> stats = null;
I can't figure it out. I have Added the typeconverter to the database, but still get this error. Any ideas what I do wrong?
Entity:
@Entity
data class Detail(
@PrimaryKey val id: Int,
val stats: List<Stat>,
val types: List<String>
){
data class Stat(
val baseStat: Int,
val stat: String
)
}
Typeconverter:
@ProvidedTypeConverter
class StatConverter @Inject constructor(
private val moshi: Moshi
){
@TypeConverter
fun fromJson(value: String): List<Detail.Stat>? {
val listType = Types.newParameterizedType(List::class.java, Detail.Stat::class.java)
val adapter: JsonAdapter<List<Detail.Stat>> = moshi.adapter(listType)
return adapter.fromJson(value)
}
@TypeConverter
fun toJson(type: List<Detail.Stat>?): String {
val listType = Types.newParameterizedType(List::class.java, Detail.Stat::class.java)
val adapter: JsonAdapter<List<Detail.Stat>> = moshi.adapter(listType)
return adapter.toJson(type)
}
}
Database:
@Database(entities = [Detail::class], version = 1, exportSchema = true)
@TypeConverters(StatConverter::class)
abstract class Database : RoomDatabase() {
abstract fun detailDao(): DetailDao
companion object{
const val DATABASE = "database"
}
}
DI module where room is provided:
@Singleton
@Provides
fun provideAppDatabase(
application: Application,
statConverter: StatConverter
): Database {
return Room
.databaseBuilder(application, Database::class.java,
Database.DATABASE
)
.addTypeConverter(statConverter)
.fallbackToDestructiveMigration()
.build()
}
EDIT:
The typeconverter code works fine with the other field (List) in the entity, but not with List.
Upvotes: 2
Views: 1268
Reputation: 87
To anyone who stumbles upon this, if you're using KSP, it's super important to make sure the field type matches the return type of the converter method. Even the nullability has to match.
For example, this will work:
Converter class:
@ProvidedTypeConverter
class SongListTypeAdapter {
// json adapter init omitted for brevity
@TypeConverter
fun songsListToString(songs: List<Station>): String {
return jsonAdapter.toJson(stations)
}
@TypeConverter
fun songsStringToList(songs: String): List<Song> {
return jsonAdapter.fromJson(songs) ?: emptyList()
}
}
Entity class:
@Entity(tableName = "playlist")
class Playlist: Serializable {
@PrimaryKey(autoGenerate = true)
var id = 0
@field:TypeConverters(SongListTypeAdapter::class)
@ColumnInfo(name = "songs") var songs: List<Song> = listOf()
}
This won't work:
@ProvidedTypeConverter
class SongListTypeAdapter {
// json adapter init omitted for brevity
@TypeConverter
fun songsListToString(songs: List<Station>): String {
return jsonAdapter.toJson(stations)
}
@TypeConverter
fun songsStringToList(songs: String): List<Song>? { // issue is here, it's nullable while the actual songs field is not
return jsonAdapter.fromJson(songs)
}
}
@Entity(tableName = "playlist")
class Playlist: Serializable {
@PrimaryKey(autoGenerate = true)
var id = 0
@field:TypeConverters(SongListTypeAdapter::class)
@ColumnInfo(name = "songs") var songs: List<Song> = listOf()
}
Notice how the return type in the second example is nullable. KSP will throw an error and you'll need to make sure the types match perfectly.
Upvotes: 1
Reputation: 1006674
Apparently, something about your nested data class
is causing problems, and so moving Stat
out from being nested in Detail
helped.
If you have the time, you might try creating a scrap project that illustrates the problem, then file an issue on the issue tracker, attaching that project as a demonstration of the problem. I don't see anything that quite matches, but there are a lot of issues, so perhaps I missed it.
Upvotes: 1
Reputation: 23381
I didn't run your code or test this out, but from eyeballing it here, is it possible it's the difference between nullable List<Detail.Stat>?
in the type converter and non-nullable List<Stat>
in the entity? Either make entity nullable or type-converter non-nullable and see if it works.
Upvotes: 1