26

I'm running into the following crash and stack trace after upgrading to Moshi 1.9.1 (from 1.8.0):

java.lang.IllegalArgumentException: Cannot serialize Kotlin type com.garpr.android.data.models.RankedPlayer. Reflective serialization of Kotlin classes without using kotlin-reflect has undefined and unexpected behavior. Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin-codegen artifact.
for class com.garpr.android.data.models.RankedPlayer
for class com.garpr.android.data.models.AbsPlayer

    at com.squareup.moshi.Moshi$LookupChain.exceptionWithLookupStack(Moshi.java:349)
    at com.squareup.moshi.Moshi.adapter(Moshi.java:150)
    at com.squareup.moshi.Moshi.adapter(Moshi.java:98)
    at com.squareup.moshi.AdapterMethodsFactory$AdapterMethod.bind(AdapterMethodsFactory.java:313)
    at com.squareup.moshi.AdapterMethodsFactory.create(AdapterMethodsFactory.java:62)
    at com.squareup.moshi.Moshi.adapter(Moshi.java:138)
    at com.squareup.moshi.Moshi.adapter(Moshi.java:98)
    at com.squareup.moshi.Moshi.adapter(Moshi.java:72)
    at com.garpr.android.data.converters.AbsPlayerConverterTest.setUp(AbsPlayerConverterTest.kt:76)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:546)
    at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:252)
    at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.IllegalArgumentException: Cannot serialize Kotlin type com.garpr.android.data.models.RankedPlayer. Reflective serialization of Kotlin classes without using kotlin-reflect has undefined and unexpected behavior. Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin-codegen artifact.
    at com.squareup.moshi.ClassJsonAdapter$1.create(ClassJsonAdapter.java:83)
    at com.squareup.moshi.Moshi.nextAdapter(Moshi.java:169)
    at com.squareup.moshi.AdapterMethodsFactory$AdapterMethod.bind(AdapterMethodsFactory.java:312)
    at com.squareup.moshi.AdapterMethodsFactory.create(AdapterMethodsFactory.java:62)
    at com.squareup.moshi.Moshi.adapter(Moshi.java:138)
    ... 23 more

I saw this other Stack Overflow answer, but it does not apply to me, as I've already added the relevant @JsonClass(generateAdapter = X) line to my classes.

I use a custom AbsPlayerConverter class for my AbsPlayer class, this is used so that I can determine which subclass to resolve to. And then, if it resolves to RankedPlayer, I use another custom converter for that (RankedPlayerConverter).

Here is my Moshi-builder code:

Moshi.Builder()
        .add(AbsPlayerConverter)
        .add(AbsRegionConverter)
        .add(AbsTournamentConverter)
        .add(MatchConverter)
        .add(RankedPlayerConverter)
        .add(SimpleDateConverter)
        .build()

And here is Moshi in my gradle file:

implementation "com.squareup.moshi:moshi:1.9.1"
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.9.1"

So finally, after all of that text and info, I have no idea how I can be running into this crash. I clearly have defined how to serialize/deserialize my RankedPlayer class. And if I downgrade to Moshi 1.8.0, and leave my codebase completely as-is, this crash goes away and everything works flawlessly.

Anyone have any ideas?

Thanks!!

Charles Madere
  • 6,642
  • 5
  • 35
  • 34
  • So did you follow the instructions in the error message? `Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin-codegen artifact` – ianhanniballake Nov 03 '19 at 04:21
  • @ianhanniballake well I'm fairly certain that I have. I don't think I need to use `KotlinJsonAdapterFactory` as it's needed only if you aren't going to be using Moshi's codegen support. And the only places I don't use Moshi's codegen are with those 6 converter classes that I listed above. And none of this information on Moshi's reflection/codegen capabilities in [the readme](https://github.com/square/moshi/blob/master/README.md) have changed since before 1.8.0, which when I downgrade to this version, all of my problems disappear. – Charles Madere Nov 03 '19 at 05:05
  • 3
    The [Kotlin part of the readme](https://github.com/square/moshi/blob/master/README.md#kotlin) makes it pretty clear that you need to add the `KotlinJsonAdapterFactory` if you're not using Moshi's codegen...like for those specific converters. That is absolutely something that changed in Moshi 1.9.X as per [the blog post about Moshi 1.9](https://www.zacsweers.dev/a-closer-look-at-moshi-1-9/). What makes you think that doesn't apply for your case? – ianhanniballake Nov 03 '19 at 05:12
  • @ianhanniballake you should put this as an Answer for upvoting and acceptance – Yuri Schimke Nov 03 '19 at 08:13
  • 2
    @ianhanniballake I just didn't think I needed Moshi's Kotlin reflection capabilities because the documentation makes it sounds pretty optional, for example this line from [their readme](https://github.com/square/moshi/blob/master/README.md#kotlin): "you may use reflection, codegen, or both". And since I didn't used to need it with `1.8.0`, I figured I was still okay without it... But had never seen that blogpost you linked . I guess my feeling now is that they could be a bit more clear on this in the readme. Thank you for the help!! – Charles Madere Nov 03 '19 at 18:34
  • 2
    @CharlesMadere you are right. Got stuck 2 hours just for a legacy documentation of 1.8 – Oz Shabat Dec 22 '19 at 13:35

3 Answers3

39

The error message specifically says Please use KotlinJsonAdapter from the moshi-kotlin artifact or use code gen from the moshi-kotlin-codegen artifact

As per the Kotlin part of the readme, you must add the KotlinJsonAdapterFactory if you're not using Moshi's codegen. This was a specific behavior change in Moshi 1.9 as per the blog post about Moshi 1.9.

Moshi.Builder()
    .add(AbsPlayerConverter)
    .add(AbsRegionConverter)
    .add(AbsTournamentConverter)
    .add(MatchConverter)
    .add(RankedPlayerConverter)
    .add(SimpleDateConverter)
    .add(KotlinJsonAdapterFactory())
    .build()

And make sure you're using implementation("com.squareup.moshi:moshi-kotlin:1.9.1")

ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
25

I'm using retrofit and I had to do the following:

In the build.grade:

implementation "com.squareup.moshi:moshi-kotlin:$moshiVersion"

In my repository:

val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()

val retrofit = Retrofit.Builder()
    .baseUrl(WEB_SERVICE_URL)
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .build()
daemon_nio
  • 1,446
  • 1
  • 16
  • 19
6

I got this when I forgot to add @JsonClass(generateAdapter = true) to one of my classes.

Tom
  • 6,946
  • 2
  • 47
  • 63