Moshi: PolymorphicJsonAdapterFactory with SkipBadElementsListAdapter IllegalArgumentException No JsonAdapter for E (with no annotations) [Kotlin]

Created on 13 Jun 2019  路  12Comments  路  Source: square/moshi

[TL, DR] Here is a sample that reproduces the crash in a simple android app

Long Description
I have two polymorphic hierarchies of Vehicle and Tyre class like this

sealed class Vehicle {
    abstract val model: String
    abstract val type : String
    abstract val tyres: List<Tyre>?
}

@JsonClass(generateAdapter = true)
data class Car(override val model: String,
               override val type: String,
               override val tyres: List<Tyre>?): Vehicle()

@JsonClass(generateAdapter = true)
data class Truck(override val model: String,
                 override val type: String,
                 override val tyres: List<Tyre>?): Vehicle()


sealed class Tyre {
    abstract val type : String
}

@JsonClass(generateAdapter = true)
data class MRFTyre(override val type : String): Tyre()

@JsonClass(generateAdapter = true)
data class ApolloTyre(override val type : String): Tyre()

I am creating Moshi instance as follows

 val moshi = Moshi.Builder()
            // ... add your own JsonAdapters and factories ...
            .add(
                PolymorphicJsonAdapterFactory.of(Vehicle::class.java, "type")
                    .withSubtype(Car::class.java, "car")
                    .withSubtype(Truck::class.java, "truck")
            )
            .add(
                PolymorphicJsonAdapterFactory.of(Tyre::class.java, "type")
                    .withSubtype(MRFTyre::class.java, "mrf")
                    .withSubtype(ApolloTyre::class.java, "apollo")
            )
            .add(SkipBadElementsListAdapter.Factory)
            .build()

I am Using SkipBadElementsListAdapter from this stackoverflow answer And trying to deserialize this JSON

[
  {
    "model": "m1",
    "type": "car",
    "tyres": [
      {
        "type": "mrf"
      },
      {
        "type": "apollo"
      }
    ]
  },

  {
    "model": "m2",
    "type": "truck",
    "tyres": [
      {
        "type": "mrf"
      },
      {
        "type": "apollo"
      },
      {
        "type": "apollo"
      }
    ]
  }
]

When I try to deserialize if Json I get followingIllegalArgumentException

java.lang.IllegalArgumentException: No JsonAdapter for E (with no annotations)
    for E
    for interface java.util.List
    for class java.lang.Object
    for class com.example.moshitest.Tyre
    for java.util.List<com.example.moshitest.Tyre> tyres
    for class com.example.moshitest.Car
    for class com.example.moshitest.Vehicle
    for java.util.List<com.example.moshitest.Vehicle>
...
...

I am not sure why its not able to find right JsonAdapter when using SkipBadElementsListAdapter. Strangely, it works fine when this adapter is not added to Moshi.Builder(). Let me know if I am doing something wrong here.

needs info

All 12 comments

Update

Upon investigating more I found that Tyres does not have to be a polymorphic list in order for crash to reproduce. Its crashing with even a simple list

following class hierarchy also reproduce the issue

sealed class Vehicle {
    abstract val model: String
    abstract val type : String
    abstract val tyres: List<Tyre>?
}

@JsonClass(generateAdapter = true)
data class Car(override val model: String,
               override val type: String,
               override val tyres: List<Tyre>?): Vehicle()

@JsonClass(generateAdapter = true)
data class Truck(override val model: String,
                 override val type: String,
                 override val tyres: List<Tyre>?): Vehicle()

@JsonClass(generateAdapter = true)
data class Tyre(val type: String)

I have simplified the sample accordingly. Also I can confirm that in this setting both factories work individually fine just not together.

thanks so much for the repro case. We'll take a look soon 馃檹

Same problem here. Maybe someone can provide some suggestion for investigation?
SkipBadElementsListAdapter looks fine I think.

Sorry we slipped on this for 1.9.0. I'll take a look this week

@abhishekBansal I tried your example and it works fine for me. Example branch: https://github.com/square/moshi/tree/z/repro_865

@vararg do you have an actionable repro example?

@ZacSweers I can still reproduce this everytime on master branch of same repository with same library versions. This sample app crashes with provided crashstack on logcat upon launch. My test device is Google Pixel 3 running Android 10

Please try your sample project with the latest version (1.9.1)? I pulled the sample into the linked branch and it works fine on Moshi master. There have been a number of changes and there鈥檚 a chance your issue was maybe indirectly fixed along the way.

works fine in v1.9.1.
You may now close the issue.
Also if you can shed some light on what was the issue would be great. Thanks!

For a hint if I place this check in Factory. This issue does not re reproduce even in older version

    if (type !is ParameterizedType) {
                return null // No type parameter? This factory doesn't apply.
            }

@ZacSweers Sorry can't provide more info right now, after lib update to 1.9.1 my sample blocked with new issue https://github.com/square/moshi/issues/990

Closing this out since @abhishekBansal's original issue is resolved. To be totally honest, so much has changed since 1.8 that I'm not certain why it works now. But, all's well that ends well?

@vararg please open a separate issue with concrete repro steps if you're still seeing this after 1.9.2

@vararg mind trying your issue against latest master? It has a fix for #990

Was this page helpful?
0 / 5 - 0 ratings