Android Kotlin中Moshi PolymorphicJsonAdapter无法运行报错问题
Moshi多态JSON解析失效排查方案
问题根因
你看到的Accessing hidden method Ljava/lang/invoke/MethodHandles$Lookup;->(Ljava/lang/Class;I)V只是Android 9+系统输出的隐藏API反射告警,不是导致解析失败的核心原因,真正的问题出在三处配置错误:
- 多态标签值不匹配:你给枚举字段加的
@Json(name = "MediaTile")注解仅在Moshi序列化/反序列化枚举本身时生效,调用TileContentType.mediaTile.name取到的是枚举常量的原生名称mediaTile(首字母小写),和接口返回的type字段值MediaTile(首字母大写)完全不一致,多态适配器无法匹配到对应子类,直接触发解析失败。 - 基类字段重复定义:
Tile基类构造函数里已经声明了type和id字段,子类MediaTile又重写了这两个字段,会导致Moshi解析时重复映射字段,出现赋值异常。 - 低版本Moshi兼容问题:1.13以下版本的Moshi使用了Android高版本限制访问的隐藏反射API,会持续输出你看到的告警日志,部分机型上甚至会直接触发反射失败。
修复步骤
1. 修正多态标签值传参
不要直接取枚举的name属性,给枚举增加自定义字段存储和接口一致的标签值:
enum class TileContentType(val label: String) { MEDIA_TILE("MediaTile"), QUESTION_TILE("QuestionTile"), CONVERSATION_STARTER_TILE("ConversationStarterTile") }
Moshi实例配置保持官方推荐的顺序即可(KotlinJsonAdapterFactory放在最后作为兜底适配器),修改标签传参:
@Provides fun provideRetrofit(okHttpClient: OkHttpClient, BASE_URL: String): Retrofit { val moshi = Moshi.Builder() .add( PolymorphicJsonAdapterFactory.of(Tile::class.java, "type") .withSubtype(MediaTile::class.java, TileContentType.MEDIA_TILE.label) .withSubtype(QuestionTile::class.java, TileContentType.QUESTION_TILE.label) .withSubtype(ConversationStarterTile::class.java, TileContentType.CONVERSATION_STARTER_TILE.label) ) // Kotlin反射适配器放在最后注册,兜底处理所有没有自定义适配器的类 .add(KotlinJsonAdapterFactory()) .build() return Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(MoshiConverterFactory.create(moshi)) .client(okHttpClient) .build() }
2. 重构基类避免字段重复
将Tile改为密封类,去掉构造函数的传参,所有字段由子类实现,从根源避免重复映射:
sealed class Tile { @Json(name = "type") abstract val type: String @Json(name = "id") abstract val id: String }
对应修改MediaTile的继承逻辑,去掉父类构造传参:
data class MediaTile( @Json(name= "id") override val id: String, @Json(name= "type") override val type: String, override val author: Author, override val createdDate: String, override var text: PostText?, override val topComment: Comment?, override val seeAllCommentsAction: DeeplinkAction?, override val allComments: List<Comment?>?, override val tags: List<Tag>?, val images: List<TileImage>?, val reactions: PostReactions?, ) : Tile(), PostTile
3. 升级Moshi依赖消除反射告警
将Moshi相关依赖升级到1.14.0及以上稳定版本,官方已经适配了Android高版本的隐藏API限制,升级后不会再出现相关告警日志,也不会触发反射失败。
验证方法
改完配置后先写本地单元测试验证逻辑,不需要发起真实接口请求:
@Test fun testPolymorphicParse() { val moshi = Moshi.Builder() .add( PolymorphicJsonAdapterFactory.of(Tile::class.java, "type") .withSubtype(MediaTile::class.java, "MediaTile") ) .add(KotlinJsonAdapterFactory()) .build() val adapter = moshi.adapter(Tile::class.java) // 填充接口返回的最小必要字段 val testJson = """ {"type":"MediaTile","id":"001","author":{},"createdDate":"2024-01-01"} """.trimIndent() val result = adapter.fromJson(testJson) // 验证解析结果类型正确 check(result is MediaTile) }
内容的提问来源于stack exchange,提问作者Jalson1982
相关产品推荐
相关产品推荐

