【问题标题】:java.lang.IllegalArgumentException: Parameter specified as non-null is null while parsing JSON to kotlin Data classjava.lang.IllegalArgumentException: 将 JSON 解析为 kotlin 数据类时指定为非 null 的参数为 null
【发布时间】:2019-04-15 10:08:15
【问题描述】:

在 kotlin 成为 android 的第一语言之后,我就全身心投入其中。随着这些天的一点点进步,我一直在将我现有的知识迁移到 kotlin。最近,我正在学习如何在一个虚拟项目中使用 GSON、Retrofit 和 kotlin。

这里CurrentWeather是在视图中显示数据的模型

data class CurrentWeather(
    val latitude: Double,
    val longitude: Double,
    val placeName: String,
    val temperature: Float,
    val maxTemperature: Float,
    val minTemperature: Float,
    val windSpeed: Float,
    val windDirection: Float,
    val weatherType: String,
    val weatherDescription: String,
    val icon: String,
    val timestamp: Instant)

class Current 负责将 JSON 解析为 POJO 类,就像我过去所做的一样,但今天使用 kotlin 看起来有点不同

data class Current(@SerializedName("coord") val location: Location,
          @SerializedName("weather") val weather: List<Weather>,
          @SerializedName("main") val temperatureAndPressure: TemperatureAndPressure,
          @SerializedName("wind") val wind: Wind,
          @SerializedName("dt") val timeStamp: Long,
          @SerializedName("name") val placeName: String) {

val time: Instant by fastLazy { Instant.ofEpochSecond(timeStamp) }


val currentWeather = CurrentWeather(location.latitude,
        location.longitude,
        placeName,
        temperatureAndPressure.temperature,
        temperatureAndPressure.maxTemperature,
        temperatureAndPressure.minTemperature,
        wind.windSpeed ?: 0f,
        wind.windAngle ?: 0f,
        weather[0].main,
        weather[0].description,
        weather[0].icon,
        time)
 }

即使我从改造中获得了成功的响应(我已经检查了成员变量;例如位置:位置、天气:列表、温度和压力:温度和压力等。但是,我收到了这个错误。

2018-11-12 21:04:07.455 9948-9948/bus.green.fivedayweather E/AndroidRuntime: FATAL EXCEPTION: main 进程:bus.green.fivedayweather,PID:9948 java.lang.IllegalArgumentException:指定为非空的参数为空:方法 kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull,参数 p1 在 bus.green.fivedayweather.ui.CurrentWeatherFragment$retrieveForecast$1.invoke(未知来源:6) 在 bus.green.fivedayweather.ui.CurrentWeatherFragment$retrieveForecast$1.invoke(CurrentWeatherFragment.kt:20) 在 bus.green.fivedayweather.net.OpenWeatherMapProvider$RetrofitCallbackWrapper.onResponse(OpenWeatherMapProvider.kt:62)

我在解析时做错了吗?

【问题讨论】:

  • 你能发布你的方法retrieveForecast,它叫什么?这似乎是堆栈跟踪所指的

标签: android json kotlin gson


【解决方案1】:

我相信,如果您按照上述解决方案将变量设置为可空类型将无法解决您的问题。 在您的情况下,问题在于这种情况下 Gson 本身的 JSON 解析。首先,Gson 没有对 Kotlin 数据类的原生支持。我建议你通读这篇文章GSON+KOTLIN。 这篇文章的简短总结是

  1. 当我们考虑开发人员在使用不可为空类型时的空安全假设时,这尤其糟糕。它将在运行时导致 NullPointerException,IDE 不会提示可能的可空性。解析时我们甚至不会得到异常,因为 Gson 使用了不安全的反射,而 Java 没有不可为空类型的概念。
  2. 解决此问题的一种方法是让步并使所有内容都可以为空,就像@Kingfisher Phuoc 建议的答案一样。不幸的是,这不仅会使代码运行。原因是您的成员变量 val currentWeather 是数据类的一个实例,而使用反射的 Gson 无法从反序列化的 JSON 中实例化它,因此即使您正确解析 data class Current 的成员变量,它也会为空。

我的建议是切换到Moshi,它内置了对 Kotlin 的支持。相反,如果你是 Gson 的超级粉丝,你需要在默认值的帮助下遵循这个变通方法并制作变量空类型。为此,我们基本上将构造函数参数设为私有支持属性。然后,我们为每个具有真实名称的支持字段提供只读属性,并使用自定义 get() = 结合 Elvis 运算符来定义我们的默认值或行为,从而产生不可为空的返回值。

data class Current(@SerializedName("coord") val _location: Location?,
      @SerializedName("weather") val _weather: List<Weather>?,
      @SerializedName("main") val _temperatureAndPressure: TemperatureAndPressure?,
      @SerializedName("wind") val _wind: Wind?,
      @SerializedName("dt") val _timeStamp: Long?, = 0.0
      @SerializedName("name") val _placeName: String? = "") {


val location
   get() = _location ?: throw IllegalArgumentException("Location is required")
val weather
   get() = _weather ?: throw IllegalArgumentException("Title is required")
val wind
   get() = _wind ?: throw IllegalArgumentException("Title is required")
val temperatureAndPressure
   get() = _temperatureAndPressure ?: throw IllegalArgumentException("Title is required")
......and so on



val time: Instant by fastLazy { Instant.ofEpochSecond(timeStamp) }


val currentWeather = CurrentWeather(location.latitude,
    location.longitude,
    placeName,
    temperatureAndPressure.temperature,
    temperatureAndPressure.maxTemperature,
    temperatureAndPressure.minTemperature,
    wind.windSpeed ?: 0f,
    wind.windAngle ?: 0f,
    weather[0].main,
    weather[0].description,
    weather[0].icon,
    time)
}

在我看来,在 Kotlin 统治世界的这些日子里,Gson 一直没能跟上步伐。如果你只是为了学习而做这个项目,你绝对应该使用 Moshi。 它有 KotlinJsonAdapterFactory,它对 JSON 有开箱即用的支持

【讨论】:

    【解决方案2】:

    这是您的问题Parameter specified as non-null is null。您所有的数据类都用non-null parameter constructor 声明。但是,在解析 JSON 过程中,有一个空参数 --> 导致崩溃。要解决这个问题,您应该将构造函数参数声明为可为空,如下所示:

    data class Current(@SerializedName("coord") val location: Location?,
          @SerializedName("weather") val weather: List<Weather>?,
          @SerializedName("main") val temperatureAndPressure: TemperatureAndPressure?,
          @SerializedName("wind") val wind: Wind?,
          @SerializedName("dt") val timeStamp: Long?,
          @SerializedName("name") val placeName: String?) {
    // your CurrentWeather class should be the same. 
    // Of course, if you are sure with non-null parameters, you should make them non-null.
    

    【讨论】:

      猜你喜欢
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2020-07-26
      • 1970-01-01
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多