Moshi 1.9.x无法序列化Kotlin类型。

30

我在升级到Moshi 1.9.1(从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

我看到了这个 Stack Overflow 的答案,但它并不适用于我,因为我已经在我的类中添加了相关的 @JsonClass(generateAdapter = X) 行。

我为我的 AbsPlayer 类使用一个自定义的 AbsPlayerConverter,这样我就可以确定要解析到哪个子类。然后,如果解析到 RankedPlayer,我会使用另一个自定义转换器 (RankedPlayerConverter)。

这是我的 Moshi-builder 代码

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

这是Moshi在我的gradle文件中:

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

所以最终,在所有这些文本和信息之后,我不知道为什么会遇到这个崩溃。我明确地定义了如何序列化/反序列化我的RankedPlayer类。如果我降级到Moshi 1.8.0,并且完全保留我的代码库,这个崩溃就消失了,一切都可以正常工作。

有人有任何想法吗?

谢谢!


你有按照错误信息中的指示操作吗?请使用moshi-kotlin库中的KotlinJsonAdapter,或者使用moshi-kotlin-codegen库中的代码生成工具。 - ianhanniballake
@ianhanniballake 嗯,我相当确定我已经解决了这个问题。我认为我不需要使用 KotlinJsonAdapterFactory,因为它只在你不使用 Moshi 的代码生成支持时才需要。而我不使用 Moshi 的代码生成的唯一地方就是那6个转换器类,我在上面列出了。而且,在 自述文件 中关于 Moshi 的反射/代码生成能力的所有信息都没有改变,自1.8.0之前以来,当我降级到这个版本时,所有问题都消失了。 - Charles Madere
3
如果您没有使用Moshi的代码生成器,那么Moshi自述文件中关于Kotlin部分非常明确地表明您需要添加KotlinJsonAdapterFactory,就像对于那些特定的转换器一样。正如Moshi 1.9版本博客文章所述,这是Moshi 1.9.X中发生的变化。您为什么认为这不适用于您的情况? - ianhanniballake
@ianhanniballake,你应该将这个放在回答中以便获得赞同和接受。 - Yuri Schimke
2
@ianhanniballake,我之前并没有觉得需要Moshi的Kotlin反射功能,因为文档中说得很明确,例如在它们的自述文件中有这样一句话:“您可以使用反射、代码生成或两者都使用”。而且由于我之前在1.8.0版本中并不需要它,所以我认为没有问题...但是我从来没有看过你提供的那篇博客文章。我现在的感觉是,他们在自述文件中应该更加清楚地说明这一点。谢谢你的帮助! - Charles Madere
2
@CharlesMadere 你是对的。为了一个1.8版本的旧文档,我被卡住了2个小时。 - Oz Shabat
3个回答

43
错误信息明确指出,请使用来自moshi-kotlin构件的KotlinJsonAdapter或使用moshi-kotlin-codegen构件中的代码生成器。
根据自述文件中的Kotlin部分,如果您未使用Moshi的代码生成器,则必须添加KotlinJsonAdapterFactory。这是Moshi 1.9中特定的行为更改,如有关Moshi 1.9的博客文章所述。
Moshi.Builder()
    .add(AbsPlayerConverter)
    .add(AbsRegionConverter)
    .add(AbsTournamentConverter)
    .add(MatchConverter)
    .add(RankedPlayerConverter)
    .add(SimpleDateConverter)
    .add(KotlinJsonAdapterFactory())
    .build()

确保你正在使用 implementation("com.squareup.moshi:moshi-kotlin:1.9.1")


9
如果您没有使用 Moshi 的代码生成部分,我不理解这部分的含义。 - David

25

我正在使用Retrofit,需要进行以下操作:

在 build.gradle 文件中:

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

在我的代码库中:

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

val retrofit = Retrofit.Builder()
    .baseUrl(WEB_SERVICE_URL)
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .build()

8

我在一个类中忘记添加@JsonClass(generateAdapter = true)时得到了这个错误提示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接