Jéluchu
Jéluchu

Reputation: 484

How to make a TypeConverter in Room from a custom list?

I have made a TypeConverter but I get an error

Unable to create converter for class .models.lastanime.EpisodesEntityfor method EpisodesApi.getEpisodes

I can't finish understanding how to make the TypeConverter, I have done this, I know that the implementation is placed correctly since I have not had problems in the compilation, but the data does not load since I get an error, and it seems that it is not saved in the room database

TYPE CONVERTER

class ListStringConverter {

    @TypeConverter
    fun fromString(value: String?): List<ServerEntity> {
        val listType = object :
            TypeToken<List<ServerEntity?>?>() {}.type
        return Gson()
            .fromJson<List<ServerEntity>>(value, listType)
    }

    @TypeConverter
    fun listToString(list: List<ServerEntity?>?): String {
        val gson = Gson()
        return gson.toJson(list)
    }

}

MODEL EPISODES ENTITY

data class EpisodesEntity(
@SerializedName("episodes")
val episodes: List<EpisodeEntity>

)

MODEL EPISODE ENTITY

@Entity
data class EpisodeEntity(

    @PrimaryKey(autoGenerate = true)
    val id: Int,

    @SerializedName("poster")
    @ColumnInfo(name = "episode")
    val episode: Int?,

    @SerializedName("poster")
    @ColumnInfo(name = "poster")
    val poster: String?,

    @SerializedName("servers")
    @ColumnInfo(name = "servers")
    val servers: List<ServerEntity>?,

    @SerializedName("title")
    @ColumnInfo(name = "title")
    val title: String?

)

In addition to all the model, the list of Servers is what gives me trouble inserting it in room

@SerializedName("servers")
    @ColumnInfo(name = "servers")
    val servers: List<ServerEntity>?,

API REPOSITORY

interface LastEpisodesRepository {

fun lastEpisodes(): Flow<Either<Failure, List<Episode>>>

class Network(
    private val networkHandler: NetworkHandler,
    private val service: LastEpisodesService,
    private val local: EpisodeLocal
) : LastEpisodesRepository {

    val preferences by lazy { SharedPrefsHelpers() }

    override fun lastEpisodes(): Flow<Either<Failure, List<Episode>>> =
        flow {

            val days = local.getEpisodes()
            val time = preferences.getLong(LocalShared.LastAnimes.lastepisodes, 0L)

            if (days.isNullOrEmpty() || time == 0L || isFetchCurrentNeeded(time)) {
                emit(getRemoteDay())
            } else {
                emit(Either.Right(local.getEpisodes().map { it.toEpisode() }))
            }
        }.catch {
            emit(Either.Left(Failure.CustomError(ServiceKOs.DATABASE_ACCESS_ERROR, "DB Error")))
        }.flowOn(Dispatchers.IO)


    private fun getRemoteEpisode(): Either<Failure, List<Episode>> =
        when (networkHandler.isConnected) {
            true -> request(
                service.getEpisodes(),
                { episodeEntity ->

                    val episodeList: List<EpisodeEntity> = episodeEntity.episodes

                    preferences.saveLong(LocalShared.LastAnimes.lastepisodes, Date().time)

                    addAllEpisodes(episodeList)
                    episodeList.map { it.toEpisode() }

                },
                EpisodesEntity(emptyList())
            )
            false, null -> Either.Left(Failure.NetworkConnection())
        }

    private fun addAllEpisodes(episodes: List<EpisodeEntity>) {
        for (episode in episodes) {
            local.addEpisodes(episode)
        }
    }

}

Room are the calls that are made from the local variable, the application checks if there is downloaded data and if there is not, it calls the service, returns the data and at the same time saves it in the Room database.

Upvotes: 1

Views: 4466

Answers (2)

J&#233;luchu
J&#233;luchu

Reputation: 484

After several days carefully studying more about the advanced inserts of Room, I have discovered how to make the TypeConverter for a specific custom object, In my case ServersEntity

@TypeConverter
fun stringToListServer(data: String?): List<ServerEntity?>? {
    if (data == null) {
        return Collections.emptyList()
    }
    val listType: Type = object :
        TypeToken<List<ServerEntity?>?>() {}.type
    return gson.fromJson<List<ServerEntity?>>(data, listType)
}

@TypeConverter
fun listServerToString(someObjects: List<ServerEntity?>?): String? {
    return gson.toJson(someObjects)
}

On the other hand to convert the String lists, it would simply be done as follows

@TypeConverter
fun fromString(value: String?): List<String> {
    val listType = object :
        TypeToken<ArrayList<String?>?>() {}.type
    return Gson().fromJson(value, listType)
}

@TypeConverter
fun fromList(list: List<String?>?): String {
    val gson = Gson()
    return gson.toJson(list)
}

Upvotes: 4

CommonsWare
CommonsWare

Reputation: 1006869

You cannot have an entity holding a List of another entity. You need to define a one-to-many relation between them.

Upvotes: 1

Related Questions