PuchkaIndur
PuchkaIndur

Reputation: 114

java.lang.IllegalArgumentException: Parameter specified as non-null is null while parsing JSON to kotlin Data class

After kotlin being the first language for android, I have devoted myself into it. With a little progress over the days I have been migrating my existing knowledge to kotlin. Recently, I am learning how to use GSON, Retrofit and kotlin in a dummy project.

Here CurrentWeather is the model which shows data in a view

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 is responsible to parse the JSON to POJO class just like I did in the past, but today it just looks a little different for using 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)
 }

Even if I get a successful response from retrofit(I have checked the members variables; such as location: Location, weather: List, temperatureAndPressure: TemperatureAndPressure etc. However, I am getting this error.

2018-11-12 21:04:07.455 9948-9948/bus.green.fivedayweather E/AndroidRuntime: FATAL EXCEPTION: main Process: bus.green.fivedayweather, PID: 9948 java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter p1 at bus.green.fivedayweather.ui.CurrentWeatherFragment$retrieveForecast$1.invoke(Unknown Source:6) at bus.green.fivedayweather.ui.CurrentWeatherFragment$retrieveForecast$1.invoke(CurrentWeatherFragment.kt:20) at bus.green.fivedayweather.net.OpenWeatherMapProvider$RetrofitCallbackWrapper.onResponse(OpenWeatherMapProvider.kt:62)

Am I doing anything wrong in parsing?

Upvotes: 1

Views: 4716

Answers (2)

Wubbalubbadubdub
Wubbalubbadubdub

Reputation: 2485

I believe if you follow the above solution by making your variable nullable type won't solve your problem. In your case problem lies in JSON parse for this case Gson itself. First of all, Gson has no native support for Kotlin data class. I would suggest you read through this article GSON+KOTLIN. A short summary of this writing is

  1. This is especially awful when we consider the assumption of null-safety by the developer when using non-nullable types. It will result in a NullPointerException at runtime with no hints by the IDE about possible nullability. We won’t even get an exception while parsing, because Gson uses unsafe reflection and Java has no concept of the non-nullable types.
  2. One way of dealing with this is giving in and making everything nullable, just like the answer suggested by @Kingfisher Phuoc. Unfortunately, that won't just make the code run. The reason is your member variable val currentWeather which is an instance of the data class and Gson which uses reflect can't instantiate it from deserialised JSON, hence it will be null even if you parse the member variables for data class Current correctly.

My suggestion would be a switch to Moshi, which has a built-in support for Kotlin.On the contrary, if you are an extreme fan of Gson, you need to follow this workaround with help of default value and making variables null type. For this, we basically have the constructor arguments be private backing properties. We then provide a read-only property for each backing field with the real name and use the custom get() = combined with the Elvis operator to define our default value or behavior, resulting in non-nullable return values.

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)
}

In my opinion, in these days of Kotlin ruling world Gson hasn't been able to keep up the pace. If you are just doing this project just for sake of learning, you should definitely use Moshi. it has KotlinJsonAdapterFactory which has out-of-the-box support for JSON

Upvotes: 0

Kingfisher Phuoc
Kingfisher Phuoc

Reputation: 8200

this is your issue Parameter specified as non-null is null. All your data classes are declared with non-null parameter constructor. However, in parsing JSON process, there's a null parameter --> that made the crash. To solve this issue, you should declare constructor parameters as nullable as below:

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.

Upvotes: 7

Related Questions