Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin Gson custom deserializer for list

How to register custom Json deserializer in Gson?

When I'm register deserializer in java code all works fine, but when I convert Kotlin to Java - deserializer method not called.

Kotlin register code:

val listType: Type = object : TypeToken<List<Advert>>() {}.type
val gson = GsonBuilder()
           .registerTypeAdapter(listType, deserializer)

val retrofit = Retrofit.Builder()
               .addConverterFactory(GsonConverterFactory.create(gson))

Java code:

Type listType = new TypeToken<List<Advert>>() {}.getType();
Gson gson = new GsonBuilder()
            .registerTypeAdapter(listType, deserializer)

Retrofit retrofit = new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create(gson))

Deserializer declaration:

class AdvertsDeserializer : JsonDeserializer<List<Advert>> {
override fun deserialize(json: JsonElement?, typeOfT: Type?,
                         context: JsonDeserializationContext?): List<Advert> {

Method calling

// list is List<Advert>
service.getAdverts()
            .subscribe({
                list ->
                viewState.showAdvertsList(list)
            }, {
                error ->
                error.printStackTrace()
            })

As I understand - problem in type of Json object(listType), or what I'm doing wrong?

like image 880
Mamykin Andrey Avatar asked Jul 26 '17 13:07

Mamykin Andrey


1 Answers

The problem is that Kotlin compiler sees List like a covariant generic type List<out T> and compiles its instantiations as wildcard types, i. e. List<CharSequence> gets compiled as List<? extends Charsequence>.

The solution is either to use MutableList which is invatiant

object : TypeToken<MutableList<Advert>>() {}.type

or to supperss wildcard generation

object : TypeToken<List<@JvmSuppressWildcards Advert>>() {}.type

More info: Kotlin Generics. Variance

like image 189
Miha_x64 Avatar answered Nov 20 '22 05:11

Miha_x64