I'm trying to save some data in my Room database but it keeps showhing me an error, here's the code:
MovieDao.kt
#Dao
interface MoviesDao {
#Query("SELECT * from movie")
fun getAll() : LiveData<List<Movie>>
#Update
fun update(movie: Movie)
#Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(movie: Movie)
}
MoviesDatabase.kt
#Database(entities = [Movie::class], version = 1, exportSchema = false)
#TypeConverters(TorrentConverter::class, GenreConverter::class)
abstract class MoviesDatabase : RoomDatabase() {
companion object {
private var instance: MoviesDatabase? = null
fun getDatabase(context: Context) : MoviesDatabase{
if(instance == null) {
instance = Room.databaseBuilder(context.applicationContext, MoviesDatabase::class.java,
"movies_database").build()
}
return instance as MoviesDatabase
}
}
abstract fun getMoviesDao() : MoviesDao
}
MovieModels.kt
#Entity(tableName = "movie")
data class Movie(
val url: String,
#PrimaryKey
val imdb_code: String,
val title: String,
val year: Int,
val rating: Float,
val runtime: Int,
#TypeConverters(GenreConverter::class)
val genres: List<String>?,
val synopsis: String,
val yt_trailer_code: String,
val language: String,
val mpa_rating: String,
val medium_cover_image: String,
val large_cover_image: String,
val state: String,
#TypeConverters(TorrentConverter::class)
var torrents: List<Torrent>,
var saved: Boolean = false,
var marked: Boolean = false
) : Serializable
data class Torrent(
val url: String,
val hash: String,
val quality: String,
val seeds: Int,
val peers: Int,
val size: String,
val size_bytes: Long
) : Serializable
TypeConverters.kt
class TorrentConverter {
#TypeConverter
fun toTorrent(json: String): Torrent {
val type = object : TypeToken<Torrent>() {}.type
return Gson().fromJson(json, type)
}
#TypeConverter
fun toJson(torrent: Torrent) = Gson().toJson(torrent)
}
class GenreConverter {
#TypeConverter
fun toGenre(json: String): List<String> {
val type = object : TypeToken<List<String>>() {}.type
return Gson().fromJson(json, type)
}
#TypeConverter
fun toJson(genres: List<String>) = Gson().toJson(genres)
}
the error shows me:
error: Cannot figure out how to save this field into database. You can
consider adding a type converter for it.
private java.util.List torrents;
Can someone please help me to figure out why is this error happening? Thanks alot.
It's happening because your TorrentConverter is returning and getting the wrong types.
The method toTorrent should return a List<Torrent> and the method toJson should receive a List<Torrent>
Try this TypeConverter:
class TorrentConverter {
#TypeConverter
fun toTorrent(json: String): List<Torrent> {
val type = object : TypeToken<List<Torrent>>() {}.type
return Gson().fromJson(json, type)
}
#TypeConverter
fun toJson(torrent: List<Torrent>): String {
val type = object: TypeToken<List<Torrent>>() {}.type
return Gson().toJson(torrent, type)
}
}
Related
I am trying to make a type convertor for a model class in my app. The model class is given below.
Order
#Entity(tableName = "Orders")
data class Order(
#PrimaryKey
var customerId:String,
var companyId:String,
var orderBookerId:String,
#ColumnInfo(name = "items") var list:List<SelectedProductsModel>
)
SelectedProductsModel
data class SelectedProductsModel(
var quantity: Int,
var skuId: String,
var companyId: String,
var productName: String?,
var vendor_brand_name: String,
var purchasePrice: Int,
var image: String,
var position: Int
):Serializable
now as you can see that in the Order class there is a var list:List<SelectedProductsModel>. I want to write a type converter for this list but i keep getting an error
error: cannot find symbol
#androidx.room.TypeConverters(value = {SelectedProductModelConvertor.class})
following is my Room database class
#Database(entities = [VisitedPjpModel::class,Order::class], version = 1)
#TypeConverters(SelectedProductModelConvertor::class)
abstract class RoomDatabaseClass : RoomDatabase()
{
public abstract fun visitedDao(): VisitedPjpDao
public abstract fun orderDao():OrderDao
companion object
{
private var instance: RoomDatabaseClass? = null
fun getInstance(context: Context): RoomDatabaseClass?
{
if (instance == null)
{
synchronized(RoomDatabaseClass::class)
{
instance = Room.databaseBuilder(context, RoomDatabaseClass::class.java, "tarseel_database").allowMainThreadQueries().build()
}
}
return instance
}
}
}
i have tried different implementations of type convertors but iam getting the same error which is mentioned above. following are the implementations of type converotrs that i have tried
class SelectedProductModelConvertor
{
#TypeConverter
fun fromList(value : List<SelectedProductsModel>) = Json.encodeToString(value)
#TypeConverter
fun toList(value: String) = Json.decodeFromString<List<SelectedProductsModel>>(value)
}
class SelectedProductModelConvertor
{
#TypeConverter
fun listToJson(value: List<SelectedProductsModel>) = Gson().toJson(value)
#TypeConverter
fun jsonToList(value: String) = Gson().fromJson(value, Array<SelectedProductsModel>::class.java).toList()
}
class SelectedProductModelConvertor
{
#TypeConverter
fun fromListLangList(value: List<SelectedProductsModel>): String
{
val gson = Gson()
val type = object : TypeToken<List<SelectedProductsModel>>()
{}.type
return gson.toJson(value, type)
}
#TypeConverter
fun toSelectedProductsModelList(value: String): List<SelectedProductsModel>
{
val gson = Gson()
val type = object : TypeToken<List<SelectedProductsModel>>()
{}.type
return gson.fromJson(value, type)
}
}
I have tried all these type convertors but iam getting error. please help me
You cannot have a List/Array for a column.
What you can do, is have a class that holds the List/Array and have a Type Converter for that.
So you could have:-
data class SelectedProductsModelList(
val selectedProductsModelList: List<SelectedProductsModel>
)
Then have :-
#Entity(tableName = "Orders")
data class Order(
#PrimaryKey
var customerId:String,
var companyId:String,
var orderBookerId:String,
#ColumnInfo(name = "items") var list:SelectedProductsModelList //<<<<<<<<<<
)
and TypeConverters that convert from/to a SelectProductsModelList object e.g.
#TypeConverter
fun fromSelectedProductsModelList(selectedProductsModelList: SelectedProductsModelList): String {
return Gson().toJson(selectedProductsModelList)
}
#TypeConverter
fun toSelectedProductsModelList(json: String): SelectedProductsModelList {
return Gson().fromJson(json,SelectedProductsModelList::class.java)
}
I'm using Android Room and I have a problem with it. I made a TypeConverter class (in my case it's ConverterHelper), added annotations #ProvidedTypeConverter, #TypeConverter, and #TypeConverters(ConverterHelper::class) but I get the following error:
java.lang.IllegalArgumentException: Unexpected type converter class com.example.mas_implementation_kotlin.helper.ConverterHelper. Annotate TypeConverter class with #ProvidedTypeConverter annotation or remove this converter from the builder.
Here is my ConverterHelper:
#ProvidedTypeConverter
class ConverterHelper {
#TypeConverter
fun stringToListOfStrings(value: String): ArrayList<String> {
val listType: Type = object : TypeToken<ArrayList<String?>?>() {}.type
return Gson().fromJson(value, listType)
}
#TypeConverter
fun listOfStringsToString(list: List<String>): String {
val gson = Gson()
return gson.toJson(list)
}
#TypeConverter
fun listOfVisitsToString(listOfVisits: List<Visit>): String {
return Gson().toJson(listOfVisits).toString()
}
#TypeConverter
fun stringToListOfVisits(value: String): List<Visit> {
val listOfVisits = object : TypeToken<ArrayList<Visit>>() {}.type
return Gson().fromJson(value, listOfVisits)
}
}
Database:
#Database(
entities = [
Consultant::class,
Doctor::class,
Person::class,
Place::class,
PreparationToTest::class,
Receptionist::class,
Referral::class,
Survey::class,
Technician::class,
Test::class,
TestResult::class,
Visit::class
], version = 1
)
#TypeConverters(ConverterHelper::class)
abstract class AppDatabase : RoomDatabase() {
public abstract fun entitiesDao(): EntitiesDao
}
My Entity:
#Entity
#TypeConverters
data class Visit(
#PrimaryKey val id: String,
#ColumnInfo(name = "visitDate") val visitDate: String,
#ColumnInfo(name = "visitPlaceId") val visitPlaceId: String,
#ColumnInfo(name = "defrayalOfExpenses") val defrayalOfExpenses: String,
#ColumnInfo(name = "additionalInfo") val additionalInfo: String,
#ColumnInfo(name = "personId") val personId: String,
#ColumnInfo(name = "consultantId") val consultantId: String,
#ColumnInfo(name = "receptionistId") val receptionistId: String,
#ColumnInfo(name = "referralId") val referralId: String,
#ColumnInfo(name = "visitsStatus") val visitStatus: String,
#ColumnInfo(name = "testId") val testId: String
)
And this is how i create Db in onCreate method:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
setUI()
database = Room.databaseBuilder(
this,
AppDatabase::class.java,
"database"
)
.addTypeConverter(ConverterHelper::class)
.fallbackToDestructiveMigration()
.build()
fetchDataFromDatabase()
fetchListOfBookedVisitsFromDb()
}
This is how i fetched data from db:
private fun fetchDataFromDatabase() {
val visitAdapter = VisitAdapter(baseContext, this::onClickAction)
lifecycleScope.launch(Dispatchers.IO) {
val entitiesDao = database.entitiesDao()
databaseHelper = DatabaseHelper(entitiesDao)
visitAdapter.setAdapterList(databaseHelper.getPersonVisitModelList())
withContext(Dispatchers.Main) {
binding.mainNewVisitListRecyclerView.apply {
adapter = visitAdapter
layoutManager = LinearLayoutManager(this#MainActivity)
}
}
}
}
Where my DatabaseHelper class has method:
fun getPersonVisitModelList(): List<VisitModel> {
val visitModelList = mutableListOf<VisitModel>()
val personVisitsString = entitiesDao.getAllPatientVisits()
val converterHelper = ConverterHelper()
val personVisitsList = converterHelper.stringToListOfVisits(personVisitsString)
for (visit in personVisitsList) {
visitModelList.add(
VisitModel(
visit.id,
getTestTypeByTestId(visit.testId),
getTestPlaceByPlaceId(visit.visitPlaceId),
visit.visitDate
)
)
}
return visitModelList
}
Do you know how to fix this error? I tried commenting getPersonVisitModelList method because I'm not sure if I can create and use an instance of the ConverterHelper class, but the error still occurs.
MyData.kt
#Entity(tableName = "my_table")
data class MyData(
#PrimaryKey(autoGenerate = true)
var id: Long = 0L,
#ColumnInfo(name = "ListData")
#TypeConverters(DataTypeConverter::class)
var mList: List<User> = emptyList(),
#Embedded
var user: User
)
MyDataDao.kt
#Dao
interface MyDataDao {
#Insert
suspend fun insert(data: MyData)
#Update
suspend fun update(data: MyData)
#Query("SELECT * FROM my_table")
fun getAll(): LiveData<List<MyData>>
}
DataTypeConverter.kt
import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
class DataTypeConverter {
companion object {
inline fun <reified T> Gson.fromJson(json: String) =
fromJson<T>(json, object : TypeToken<T>() {}.type)
#TypeConverter
fun stringToList(data: String?): List<User> {
data?.let {
return Gson().fromJson(data)
}
return emptyList()
}
#TypeConverter
fun listToString(users: List<User>): String {
return Gson().toJson(users)
}
}
}
User.kt
data class User(
#ColumnInfo(name = "first_name")
val firstName: String,
#ColumnInfo(name = "last_name")
val lastName: String
)
on build getting this error
error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
Even after using typeconverters the problem is persistent
I think your DataTypeConverter is wrong you can try change like this :
class DataTypeConverter{
var gson = Gson()
#TypeConverter
fun stringToUserList(data: String?): List<User?>? {
if (data == null) {
return Collections.emptyList()
}
val listType: Type =
object : TypeToken<List<User?>?>() {}.type
return gson.fromJson<List<User?>>(data, listType)
}
#TypeConverter
fun userDetailListToString(someObjects: List<User?>?): String? {
return gson.toJson(someObjects)
}
}
Don't forget to add #TypeConverters(DataTypeConverter::class) to #Database
I'm doing weather app in Kotlin, and in Activity is method which firstly takes cache data from Room, and after one hour data is updated. But there is problem probably with saving of data in database. I checked API logs in Profiles and there is no null with Weather List, so API works fine.
I'm trying to save Weather list as an ArrayList, but the answer from logs is still null. I also tried Type Converter, but still nothing. Maybe someone will find the reason for my problem and the answer.
EDIT: I removed #Embedded(prefix = "weather_") above the ArrayList and it works.
CurrentWeather (stores Weather ArrayList):
#Entity(tableName = "current_weather")
data class CurrentWeather(
#Embedded(prefix = "weather_")
val weather: ArrayList<Weather>? = ArrayList(), //here is my problem
#SerializedName("base")
val base: String,
#Embedded(prefix = "clouds_")
val clouds: Clouds,
#SerializedName("cod")
val cod: Int,
#Embedded(prefix = "coord_")
val coord: Coord,
#SerializedName("dt")
val dt: Int,
#SerializedName("id")
val id: Int,
#Embedded(prefix = "main_")
val main: Main,
#SerializedName("name")
val name: String,
#Embedded(prefix = "sys_")
val sys: Sys,
#SerializedName("visibility")
val visibility: Int,
#Embedded(prefix = "wind_")
val wind: Wind
) {
#PrimaryKey(autoGenerate = false)
var idKey: Int = CURRENT_WEATHER_ID
}
Weather:
data class Weather(
#SerializedName("description")
val description: String,
#SerializedName("icon")
val icon: String,
#SerializedName("id")
val id: Int,
#SerializedName("main")
val main: String
)
Converter:
class Converters {
#TypeConverter
fun arrayListToJson(value: List<Weather>?): String {
return Gson().toJson(value)
}
#TypeConverter
fun jsonToArrayList(value: String): List<Weather> {
val objects = Gson().fromJson(value, Array<Weather>::class.java) as Array<Weather>
val list = objects.toList()
return list
}
Database:
#Database(entities = [CurrentWeather::class, Location::class], version = 15, exportSchema = false)
#TypeConverters(Converters::class) //converter initialization
abstract class WeatherDatabase : RoomDatabase() {
Here is the modified converter class. It might help you.
object class Converters {
val gson = Gson()
#TypeConverter
fun arrayListToJson(list: List<Weather>?): String? {
return if(list == null) null else gson.toJson(list)
}
#TypeConverter
fun jsonToArrayList(jsonData: String?): List<Weather>? {
return if (jsonData == null) null else gson.fromJson(jsonData, object : TypeToken<List<Weather>?>() {}.type)
}
}
I'm try to using save values to database via room persistance library. My SettingsValueModelConverter is wrong somethings are missing. How I can save SettingsKeyContract objects best way?
Logcat:
SettingsModel
Error:(14, 1) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
Codes:
object SETTING_CONS{
const val TABLE = "Content_Setting"
const val ID = "uid"
const val KEY = "key"
const val VALUE = "value"
}
class SettingsValueModel(var value: SettingsKeyContract)
class SettingsValueModelConverter {
#TypeConverter
fun fromString(value: String): SettingsKeyContract = Gson().fromJson(value, object : TypeToken<SettingsKeyContract>() {}.type)
#TypeConverter
fun fromModel(value: SettingsKeyContract): String = Gson().toJson(value)
}
#Entity(tableName = SETTING_CONS.TABLE)
class SettingsModel(#ColumnInfo(name = SETTING_CONS.KEY) #SETTINGS var key: String,
#ColumnInfo(name = SETTING_CONS.VALUE) var value: SettingsValueModel) {
#ColumnInfo(name = SETTING_CONS.ID)
#PrimaryKey(autoGenerate = true)
var uid: Int = 0
}
#Dao
interface SettingsDao {
#Query("SELECT * FROM ${SETTING_CONS.TABLE} WHERE ${SETTING_CONS.ID} = :key")
fun get(#SETTINGS key: String): LiveData<SettingsModel>
#get:Query("SELECT * FROM ${SETTING_CONS.TABLE}")
val all: LiveData<MutableList<SettingsModel>>
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(model: SettingsModel): Long
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg models: SettingsModel): LongArray
#Query("DELETE FROM ${SETTING_CONS.TABLE} WHERE ${SETTING_CONS.KEY} = :key")
fun delete(#SETTINGS key: String)
#Query("DELETE FROM ${SETTING_CONS.TABLE}")
fun clear()
}
interface SettingsKeyContract { val key: String }
interface TypeSettingsKeyContract<out T : Any> : SettingsKeyContract { val default: T }
sealed class SETTING(override val key: String) : SettingsKeyContract {
object FIRST_LAUNCH_DATE : SETTING("first_launch_date"), TypeSettingsKeyContract<Long> { override val default = 0L }
}
Where do you define your database?
You should have the option there to specify which converter to use, like such :
#Database(entities = arrayOf(SettingsModel::class) , version = 1, exportSchema = false)
#TypeConverters(SettingsValueModelConverter::class)
abstract class AppDatabase: RoomDatabase() {
abstract fun SettingsDao(): SettingsDao
}