Search code examples
androidandroid-room

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
}

Solution

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