androidkotlingsonandroid-roomtypeconverter

com.google.gson.JsonIOException: Abstract classes can't be instantiated! Register an InstanceCreator or a TypeAdapter for this type


Application crash when I try to insert list of Songs into Playlist class.I am using new Android studio version Flamingo and type coverters for converting list of model class. This is my Converter class,I have added type converters to my Database Class.

class DataConverters {

    @TypeConverter
    fun toSongList(string: String): List<Song> {
        val listType = object : TypeToken<List<Song>>() {}.type
        return Gson().fromJson(string, listType) //here crash
    }

    @TypeConverter
    fun fromSongList(list: List<Song>): String {
        return Gson().toJson(list) 
    }

}

This is my Song model class

@Entity(tableName = "song")
data class Song(
    val displayName:String,
    val artist:String,
    val data:String,
    val duration:Int,
    val title:String,
    val album: String,
    val uri: Uri,
    val artUri: String,
    val dateAdded: String,
    @PrimaryKey val id:Long
){
    fun doesMatchSearchQuery(query: String): Boolean {
        val matchingCombinations = listOf(
            displayName
        )

        return matchingCombinations.any {
            it.contains(query, ignoreCase = true)
        }
    }
}

This is my Playlist class.

@Entity(tableName = "playlist")
data class Playlist(
    @PrimaryKey val playlistName: String,
    val songCount: Int,
    val playlistDuration: Long,
    val songs: List<Song>,
)

I have tried to add some proguard rules and it didnt help me.


Solution

  • I think the error comes from the val uri: Uri since Gson doesn't know how to Deserialize the Uri.

    You should register an adapter for this type

    class UriJsonAdapter: JsonSerializer<Uri>, JsonDeserializer<Uri> {
        override fun serialize(src: Uri, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
            return JsonPrimitive(src.toString())
        }
        
        override fun deserialize(src: JsonElement, srcType: Type, context: JsonDeserializationContext): Uri {
            return try {
                val url = src.asString
                if (url.isNullOrEmpty()) {
                    Uri.EMPTY
                } else {
                    Uri.parse(url)
                }
            } catch (e: UnsupportedOperationException) {
                Uri.EMPTY
            }
        }
    }
    
    GsonBuilder().registerTypeAdapter(Uri::class.java, UriJsonAdapter())