Android room save custom type - android

I try save custom type in room database. I always getting an error
error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
I created converter for OutboxItemCache
My entity
#Entity(tableName = "request")
class RequestCache(
#ColumnInfo(name = "requestId")
#PrimaryKey var id: String = "",
#TypeConverters(RequestConverter::class)
var outboxItemCache: OutboxItemCache)
My RequestConverter
class RequestConverter {
companion object {
private val gson = Gson()
#TypeConverter
fun stringToOutboxItem(string: String): OutboxItemCache? {
if (TextUtils.isEmpty(string))
return null
return gson.fromJson(string, OutboxItemCache::class.java)
}
#TypeConverter
private fun outboxItemToString(outboxItem: OutboxItemCache): String {
return gson.toJson(outboxItem)
}
}
}
This my class OutboxItemCache
class OutboxItemCache(
var id: String = "",
val numder: String,
date: String,
val headerDate: String,
name: String,
val certCount: String,
val status: String,
val statusColor: Int,
var statusInfo: String? = null,
val vetCertIds: List<String>
)
The error never disappeared

As per google's documentation:
#Database(entities = {User.class}, version = 1)
#TypeConverters({RequestConverter.class})
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
You need to register your TypeConverters to your Database class.
EDIT:
In kotlin:
#Database(entities = arrayOf(User::class), version = 1)
#TypeConverters(RequestConverter::class)
abstract class AppDatabse : RoomDatabase() {
abstract fun userDAO(): UserDAO
}
The only line of code here that matters to you is
#TypeConverters(RequestConverter::class)
as you should already have the others.
EDIT 2:
Try writing your converter class as follows:
class RequestConverter {
#TypeConverter
fun stringToOutboxItem(string: String): OutboxItemCache? {
if (TextUtils.isEmpty(string))
return null
return Gson().fromJson(string, OutboxItemCache::class.java)
}
#TypeConverter
private fun outboxItemToString(outboxItem: OutboxItemCache): String {
return Gson().toJson(outboxItem)
}

Related

Android Room - "Cannot figure out how to save this field into database" error exists even though Type Converter is created

I have a model FoodDonation:
#Entity
#TypeConverters(DonatedObjectConverter::class)
data class FoodDonation(#PrimaryKey val id:String,
...
#TypeConverters(DonatedObjectConverter::class)
var donatedObjects : ArrayList<DonatedObject>
){
#Ignore
constructor():this("","",0,"","", ArrayList())
}
The donatedObjects model:
#Entity
data class DonatedObject(#PrimaryKey
val foodId: String,
val donatedAmount: Int)
{
#Ignore
constructor():this("",0)
}
My type converter:
class DonatedObjectConverter {
#TypeConverter
fun fromArray(foodDonationList:ArrayList<FoodDonation>?): String? {
return Gson().toJson(foodDonationList)
}
#TypeConverter
fun toArray(value:String?):ArrayList<FoodDonation>? {
val listType: Type = object : TypeToken<ArrayList<FoodDonation>>() {}.type
return Gson().fromJson(value, listType)
}
}
My database:
#Database(entities = [FoodDonation::class], version = 1, exportSchema = false)
#TypeConverters(DonatedObjectConverter::class)
abstract class FoodDonationDatabase:RoomDatabase() {
abstract fun foodDonationDao():FoodDonationDao
...
...
}
I had created the type converter and all the #TypeConverters(DonatedObjectConverter::class) has put in the files.
Why it still doesn't work?
have a great day
Try
#Database(entities = [FoodDonation::class], version = 1, exportSchema = false)
#TypeConverters(DonatedObjectConverter::class)
abstract class FoodDonationDatabase:RoomDatabase() {
abstract fun foodDonationDao():FoodDonationDao
...
...
}

Error of type convertors in room database

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)
}

How to make a converter class correctly?

I have POJO data classes from API.
#Entity(tableName = "pokemon")
class Pokemon(
#PrimaryKey(autoGenerate = true)
var id: Int? = null,
#SerializedName("count")
#Expose
val count: Int?,
#SerializedName("next")
#Expose
val next: String?,
#SerializedName("results")
#Expose
val results: List<Result>? = null
)
And class List:
class Result(
#SerializedName("name")
#Expose
val name: String?,
#SerializedName("url")
#Expose
val url: String?
)
My database class:
#Database(entities = [Pokemon::class], version = 1, exportSchema = false)
#TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
companion object {
private var db: AppDatabase? = null
private const val DB_NAME = "main.db"
private val LOCK = Any()
fun getInstance(context: Context): AppDatabase {
synchronized(LOCK) {
db?.let { return it }
val instance = Room.databaseBuilder(
context,
AppDatabase::class.java,
DB_NAME
)
.fallbackToDestructiveMigration()
.build()
db = instance
return instance
}
}
}
abstract fun PokemonDao(): PokemonDao
}
My class Converters:
class Converters {
#TypeConverters
fun fromResultToString(result: slode.elsloude.pokemonapi.pojo.Result?): String? {
return Gson().toJson(result)
}
#TypeConverters
fun fromStringToResult(value: String?): slode.elsloude.pokemonapi.pojo.Result? {
return Gson().fromJson(value, Result::class.java)
}
}
The error I get when attempting this is:
error: Class is referenced as a converter but it does not have any converter methods. - androidx.databinding.adapters.ConvertersC:\Users\elslode\.AndroidStudio3.6\PokemonApi\app\build\tmp\kapt3\stubs\debug\slode\elsloude\pokemonapi\pojo\Pokemon.java:22: 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<slode.elsloude.pokemonapi.pojo.Result> results = null;
^C:\Users\elslode\.AndroidStudio3.6\PokemonApi\app\build\tmp\kapt3\stubs\debug\slode\elsloude\pokemonapi\pojo\SinglePokemon.java:14: error: Cannot figure out how to read this field from a cursor.
The #TypeConverters annotation is used to link your converters with the database, as yuo have done here:
#TypeConverters(Converters::class)
However when declaring a converter method you should be using the #TypeConverter annotation:
class Converters {
#TypeConverter
fun fromResultToString(result: slode.elsloude.pokemonapi.pojo.Result?): String? {
return Gson().toJson(result)
}
#TypeConverter
fun fromStringToResult(value: String?): slode.elsloude.pokemonapi.pojo.Result? {
return Gson().fromJson(value, Result::class.java)
}
}
Note the plural on #TypeConverters vs #TypeConverter.
Secondly Room cannot automatically infer a list conversion for you, so the type converter functions will have to map the full List<Result> to a String and vice versa.

Android room/TypeConverter issue while retriving list of objects

I am implementing a local cache using Room. I have created typeconverter to convert list of objects to json and back. But I am receiving mapping issue while retrieving data from json with error:
The columns returned by the query does not have the fields [title,media] in
com.example.theApp.data.FlickrImage even though they are annotated as non-null or
primitive. Columns returned by the query: [items]
Another one like this:
error: Cannot figure out how to read this field from a cursor.
private final com.example.theApp.data.Media media = null;
I tried other answers here but its not associated directly with this issue.
Here is my typeconverter:
class FlickrImageConverters {
#TypeConverter
fun fromImageListToJson(stat: List<FlickrImage>): String {
return Gson().toJson(stat)
}
/**
* Convert a json to a list of Images
*/
#TypeConverter
fun fromJsonToImagesList(jsonImages: String): List<FlickrImage> {
val type = object : TypeToken<List<FlickrImage>>() {}.type
return Gson().fromJson<List<FlickrImage>>(jsonImages, type)
}
}
Here is my entity class:
#Entity
data class DatabaseImagesEntity(
#PrimaryKey
#TypeConverters(FlickrImageConverters::class)
#SerializedName("item")
val items: List<FlickrImage>)
Dao class
#Dao
interface ImagesDao {
#Query("select * from DatabaseImagesEntity")
fun getImages(): List<FlickrImage>
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(images: List<FlickrImage>)
}
FlickrImage class
data class FlickrImage(val title: String, val media: Media)
Media class
data class Media(val m: String)
LatestImage class
data class LatestImages(val items: List<FlickrImage>)
Please let me know if you faced this issue and if you know the solution for this.
Room database implementation
#Database(entities = [DatabaseImagesEntity::class], version = 1,
exportSchema = false)
#TypeConverters(FlickrImageConverters::class)
abstract class FlickrDatabase: RoomDatabase() {
abstract val imagesDao: ImagesDao
}
private lateinit var INSTANCE: FlickrDatabase
fun getDatabase(context: Context): FlickrDatabase{
synchronized(FlickrDatabase::class.java){
if(!::INSTANCE.isInitialized){
INSTANCE = Room.databaseBuilder(context.applicationContext,
FlickrDatabase::class.java,
"flickerImages").build()
}
}
return INSTANCE
}
The issue was I was saving data in the wrong entity, wrong TypeConverters and as a result, I was using the wrong Entity class at the time of database creation.
Here are the necessary changes I had to make to store the list of objects:
Flickr data class
#Entity(tableName = "FlickerImage")
data class FlickrImage(
#PrimaryKey(autoGenerate = true)
val id: Int,
val title: String,
#TypeConverters(MediaConverter::class)
val media: Media)
TypeConvertors for Media class
class MediaConverter {
#TypeConverter
fun fromMediaToJson(stat: Media): String {
return Gson().toJson(stat)
}
/**
* Convert a json to a list of Images
*/
#TypeConverter
fun fromJsonToMedia(jsonImages: String): Media {
val type = object : TypeToken<Media>() {}.type
return Gson().fromJson<Media>(jsonImages, type)
}
}
DAO class
#Dao
interface ImagesDao {
#Query("select * from FlickerImage")
fun getImages(): LiveData<List<FlickrImage>>
Database class
#Database(entities = [FlickrImage::class], version = 1, exportSchema = false)
#TypeConverters(MediaConverter::class)
abstract class FlickrDatabase: RoomDatabase() {
abstract val imagesDao: ImagesDao
}
private lateinit var INSTANCE: FlickrDatabase
fun getDatabase(context: Context): FlickrDatabase{
synchronized(FlickrDatabase::class.java){
if(!::INSTANCE.isInitialized){
INSTANCE = Room.databaseBuilder(context,
FlickrDatabase::class.java,
"flickerImages").build()
}
}
return INSTANCE
}
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(images: List<FlickrImage>)
}
You need to add the appropriate annotations to your data class - e.g. for Gson you need to add the annotations #SerializedName("field_name") Otherwise, there's no way for the converters to know how to translate the json.
To clarify, the current annotations you have are only for Room. Just check with whatever json library you are using for the necessary logic.
#Entity(tableName = "images")
data class DatabaseImagesEntity(
#PrimaryKey(autoGenerate = true)
var id: Int? = 0,
#TypeConverters(FlickrImageConverters::class)
#SerializedName("item")
val items: MutableList<FlickrImage>? = null
)
or
#Entity(tableName = "images")
class DatabaseImagesEntity {
#PrimaryKey(autoGenerate = true)
var id: Int? = 0
#TypeConverters(FlickrImageConverters::class)
#SerializedName("item")
val items: MutableList<FlickrImage>? = null
}
then update your DAO query to #Query("select * from images")
I named it images as an example - you can choose whatever you want.
class ListConverter {
//from List to String
#TypeConverter
fun fromList(list : List<Object>): String {
return Gson().toJson(list)
}
// from String to List
#TypeConverter
fun toList(data : String) : List<Object> {
if (data == null){
return Collections.emptyList()
}
val typeToken = object : TypeToken<List<Object>>() {}.type
return Gson().fromJson(data,typeToken)
}
}

Room - save custom object list

I'm trying to save List<Object> into Room database.
I get following error:
error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
private java.util.List<xxx.models.OBJECTX> carList;
Room implementation:
#Entity(tableName = "nameOfTable")
class CachedObjectX(
#PrimaryKey
#ColumnInfo(name = "id") val id: Long,
#ColumnInfo(name = "list")
var carList: List<ObjectX>
)
#Dao
interface CachedObjectXDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(list: ArrayList<CachedObjectX>)
#Delete
fun delete(list: ArrayList<CachedObjectX>)
#Query("SELECT * FROM ...")
fun getAll(): ArrayList<CachedObjectX>
}
class CachedObjectXConverter {
companion object {
var gson = Gson()
#TypeConverter
#JvmStatic
fun toInsuredVehicle(json: String): List<ObjectX> {
val type = object : TypeToken<List<ObjectX>>() {}.type
return gson.fromJson(json, type)
}
#TypeConverter
#JvmStatic
fun toJson(torrent: List<ObjectX>): String {
val type = object: TypeToken<List<ObjectX>>() {}.type
return gson.toJson(torrent, type)
}
}
}
#Database(entities = [CachedObjectX::class], version = 1, exportSchema = false)
#TypeConverters(CachedObjectXConverter::class)
abstract class CachedObjectXDb : RoomDatabase() {
companion object {
private const val DB_NAME = "CachedObjectX.db"
val instance: CachedObjectXDb by lazy {
Room.databaseBuilder(
getContext(),
CCchedObjectXDb::class.java,
DB_NAME
).build()
}
}
abstract fun getDao(): CachedObjectXDao
}
Interesting, that I've added TypeConverter, but it still throws error. What is wrong with my implementation? Just started with Room, so there is high chance that something is wrong. Thanks in advance.
You have to make the pojo of ObjectX be an entity too

Categories

Resources