在Moshi中处理可空值的问题及构造器异常排查
我来帮你搞定这个问题——你遇到的JsonDataException和NoSuchMethodException都是Kotlin结合Moshi/Retrofit时的常见坑,咱们一步步来解决:
一、先搞定必填字段缺失的异常
首先要明确:在Kotlin里用Moshi,不需要加@Nullable注解,那是Java时代的用法。Moshi对Kotlin的可空类型支持是靠语言本身的?和默认值来实现的。
你需要把所有可能在JSON中缺失的字段,直接声明为可空类型(加?),并且给它设置默认值null。比如OWM的返回里,rain、snow这些字段只有在对应天气出现时才会存在,所以你的CurrentWeather类要改成这样:
@JsonClass(generateAdapter = true) data class CurrentWeather( @Json(name = "coord") val coordinates: Coordinates, @Json(name = "weather") val condition: List<Condition>, @Json(name = "base") val base: String, @Json(name = "main") val weatherCondition: Weather, @Json(name = "wind") val windCondition: Wind, @Json(name = "clouds") val cloudCondition: Cloud, @Json(name = "rain") val rainCondition: Rain? = null, // 可空+默认null @Json(name = "snow") val snowCondition: Snow? = null, // 可空+默认null @Json(name = "dt") val date: Double, @Json(name = "sys") val sysCondition: Sys, @Json(name = "id") val cityId: Long, @Json(name = "name") val cityName: String, @Json(name = "cod") val status: Int )
如果还有其他可能缺失的字段(比如某些地区的sys字段会不会有特殊情况?),也照这个逻辑处理就行。
二、解决Condition类的构造器找不到异常
你改完可空字段后遇到的NoSuchMethodException,大概率是Moshi的Kotlin代码生成没配置对,或者缓存搞鬼了。咱们按顺序排查:
1. 检查依赖配置是否正确
确保你的Module级build.gradle(或build.gradle.kts)里加了Moshi的Kotlin支持和代码生成依赖:
plugins { id 'org.jetbrains.kotlin.android' // 别忘了加Moshi的代码生成插件 id 'com.squareup.moshi' version '1.15.0' // 用最新稳定版就行 } dependencies { // Moshi核心库 implementation 'com.squareup.moshi:moshi:1.15.0' // Kotlin适配库 implementation 'com.squareup.moshi:moshi-kotlin:1.15.0' // 关键!代码生成器,必须加,因为你用了@JsonClass(generateAdapter = true) kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.15.0' }
如果是Kotlin DSL,语法稍微调整一下,比如plugins里用id("com.squareup.moshi") version "1.15.0",依赖里用kapt("com.squareup.moshi:moshi-kotlin-codegen:1.15.0")。
2. 确保Condition类的字段都有默认值
看你的Condition类,目前的字段都加了可空和默认值,这是对的,但要注意OWM的weather数组里的对象通常还有main字段,如果你没声明的话,也可能出问题。建议补全所有可能的字段并设置默认值:
@JsonClass(generateAdapter = true) data class Condition( @Json(name = "id") val id: Int? = null, @Json(name = "main") val main: String? = null, // 补全这个字段 @Json(name = "description") val description: String? = null, @Json(name = "icon") val icon: String? = null // 还有icon字段,也可能用到 )
3. 清理缓存重新构建
有时候Android Studio的缓存会搞事情,导致代码生成不完整。执行:
Build -> Clean Project- 然后
Build -> Rebuild Project
或者用命令行跑./gradlew clean build,强制重新生成所有代码。
三、最后检查Retrofit的Moshi配置
这一步很容易忘!默认的Moshi实例不支持Kotlin的可空类型和数据类默认值,你必须给Moshi加上KotlinJsonAdapterFactory,然后传给Retrofit:
// 先创建带Kotlin支持的Moshi实例 val moshi = Moshi.Builder() .add(KotlinJsonAdapterFactory()) .build() fun retrofit(url: String): Retrofit = Retrofit.Builder() .client(owmClient) .baseUrl(url) .addConverterFactory(MoshiConverterFactory.create(moshi)) // 用这个配置好的Moshi .addCallAdapterFactory(CoroutineCallAdapterFactory()) .build()
之前你直接用MoshiConverterFactory.create(),相当于用了默认的Moshi实例,没有Kotlin支持,所以可空字段的处理会出问题。
总结一下
按这个顺序来:
- 给所有可能缺失的字段加
?和默认值null - 检查并补全Moshi的Kotlin依赖和代码生成插件
- 给Moshi实例添加
KotlinJsonAdapterFactory - 清理缓存重新构建
这样就能同时解决你遇到的两个异常了,亲测适配OWM的API完全没问题。
内容的提问来源于stack exchange,提问作者Sparker0i

