48

Trying to parse JSON array in Kotlin, made it work for single JSON object to a WeatherObject object (code snippet below)

{
"coord": {
    "lon": -2.93,
    "lat": 43.26
},

"weather": [{
    "id": 802,
    "main": "Clouds",
    "description": "scattered clouds",
    "icon": "03d"
}],

"main": {
    "temp": 283.681,
    "temp_min": 283.681,
    "temp_max": 283.681,
    "pressure": 991.72,
    "sea_level": 1034.92,
    "grnd_leve": 991.72,
    "humidity": 98
},
"wind": {
    "speed": 1.07,
    "deg": 144.001
},

"dt": 1429773245,
"id": 3128026,
"name": "Bilbao",
"cod": 200

}

but not sure how to do the same if the JSON is a array of same JSON object, i.e.

from json array [ {}, {} …] to ArrayList<WeatherObject >

something like:

fun getWeatherObjectArrayFromJson(jsonStr: String): ArrayList&lt;WeatherObject &gt

having problem with gsonBuilder.registerTypeAdapter(ArrayList<WeatherObject &gt::class.java, WeatherDeserializer())

class WeatherObject {

    var main: String = ""
    var description: String = ""
    var temp: Float = 0.0f
    var tempMax: Float = 0.0f
    var tempMin: Float = 0.0f
    var humidity: Int = 0
    var wind: WindObject? = null

}

class WeatherDeserializer : JsonDeserializer<WeatherObject> {

    override fun deserialize(json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext?): WeatherObject? {
        val jsonObj = json as JsonObject

        val wheather = WeatherObject()
        val wind = WindObject()

        val jsonWeatherArray = jsonObj.getAsJsonArray("weather").get(0)
        val jsonMainObj = jsonObj.getAsJsonObject("main")
        val jsonWindObj = jsonObj.getAsJsonObject("wind")

        wheather.main = jsonWeatherArray.asJsonObject.get("main").asString
        wheather.description = jsonWeatherArray.asJsonObject.get("description").asString
        wheather.temp = jsonMainObj.get("temp").asFloat
        wheather.tempMax = jsonMainObj.get("temp_max").asFloat
        wheather.tempMin = jsonMainObj.get("temp_min").asFloat
        wheather.humidity = jsonMainObj.get("humidity").asInt
        wind.speed = jsonWindObj.get("speed").asFloat
        wind.deg = jsonWindObj.get("deg").asFloat
        wheather.wind = wind

        return wheather

    }
}

fun getWeatherObjectFromJson(jsonStr: String): WeatherObject {

        var stringReader: StringReader = StringReader(jsonStr)
        var jsonReader: JsonReader = JsonReader(stringReader)

        val gsonBuilder = GsonBuilder().serializeNulls()
        gsonBuilder.registerTypeAdapter(WeatherObject::class.java, WeatherDeserializer())
        val gson = gsonBuilder.create()

        val weather: WeatherObject = gson.fromJson(jsonReader, WeatherObject::class.java)

        return weather
    }

Update:

tried the solution from chandil03, IT IS WORKING! put the testing json array data and the function here:

tried

fun getWeatherObjectFromJsonArray(jsonArrayStr: String): List<WeatherObject> {

        var stringReader: StringReader = StringReader(jsonStr)
        //var jsonReader: JsonReader = JsonReader(stringReader)

        val gsonBuilder = GsonBuilder().serializeNulls()
        gsonBuilder.registerTypeAdapter(WeatherObject::class.java, WeatherDeserializer())
        val gson = gsonBuilder.create()

        val weatherList: List<WeatherObject> = gson.fromJson(stringReader , Array<WeatherObject>::class.java).toList()
        //val weatherList: List<WeatherObject> = gson.fromJson(jsonReader, Array<WeatherObject>::class.java).toList

        return weatherList
    }

got exception at

val weatherList: List<WeatherObject> = gson.fromJson(stringReader , Array<WeatherObject>::class.java).toList()

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

the json array data is like:

[
{
  "coord": {
    "lon": -2.93,
    "lat": 43.26
  },

  "weather": [{
    "id": 802,
    "main": "Clouds",
    "description": "scattered clouds",
    "icon": "03d"
  }],

  "main": {
    "temp": 283.681,
    "temp_min": 283.681,
    "temp_max": 283.681,
    "pressure": 991.72,
    "sea_level": 1034.92,
    "grnd_leve": 991.72,
    "humidity": 98
  },
  "wind": {
    "speed": 1.07,
    "deg": 144.001
  },
  "clouds": {
    "all": 36
  },
  "dt": 1429773245,
  "id": 3128026,
  "name": "Bilbao",
  "cod": 200
}, 

{
  "coord": {
    "lon": -2.93,
    "lat": 43.26
  },

  "weather": [{
    "id": 802,
    "main": "Clouds",
    "description": "scattered clouds",
    "icon": "03d"
  }],

  "main": {
    "temp": 283.681,
    "temp_min": 283.681,
    "temp_max": 283.681,
    "pressure": 991.72,
    "sea_level": 1034.92,
    "grnd_leve": 991.72,
    "humidity": 98
  },
  "wind": {
    "speed": 1.07,
    "deg": 144.001
  },
  "clouds": {
    "all": 36
  },
  "dt": 1429773245,
  "id": 3128026,
  "name": "Bilbao",
  "cod": 200
}
]
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
lannyf
  • 9,865
  • 12
  • 70
  • 152

2 Answers2

86

You need to change parameter in your fromJson() function call like following:

val weatherList: List<WeatherObject> = gson.fromJson(stringReader , Array<WeatherObject>::class.java).toList()

You need to pass Array<WeatherObject>::class.java for class type and then convert result into List. No need to change registerTypeAdapter() function call.

Check following code:

fun getWeatherObjectFromJson(jsonStr: String): List<WeatherObject> {

        var stringReader: StringReader = StringReader(jsonStr)
        var jsonReader: JsonReader = JsonReader(stringReader)

        val gsonBuilder = GsonBuilder().serializeNulls()
        gsonBuilder.registerTypeAdapter(WeatherObject::class.java, WeatherDeserializer())
        val gson = gsonBuilder.create()

       val weatherList: List<WeatherObject> = gson.fromJson(stringReader , Array<WeatherObject>::class.java).toList()

        return weatherList
    }
Sachin Chandil
  • 17,133
  • 8
  • 47
  • 65
  • thanks chandil03! but having problem with the class WeatherDeserializer : JsonDeserializer, which is dealing with single json object, how does it work with the json string which has a array of the same json objects, does it need to define a array version of the deserializer? – lannyf Aug 10 '17 at 11:40
  • @lannyf No, the code mentioned above just works file with string containing array of weather object. I have checked it. Changed required in only one line. – Sachin Chandil Aug 10 '17 at 12:11
  • tried with your function, it got exception. I update the function and the json array dat in the question. – lannyf Aug 10 '17 at 12:58
  • @lannyf i have checked code with your given JSON also, working properly fine without any issue. What i can understand from the exception that you are giving previous input that has weather object not the array. That exception occurs only when you expect an array and giving object in jsonString input. – Sachin Chandil Aug 10 '17 at 13:08
  • it is working! my bad I was still testing with the non-array dat and thought it is using the array data. Thanks a lot. Not sure why kotlin complain about when passing the JsonReader instead of the StringReader though. val weatherList: List = gson.fromJson(jsonReader, Array::class.java).toList – lannyf Aug 10 '17 at 13:21
  • @chandil03 what if we follow this answer https://stackoverflow.com/questions/48853750/kotlin-convert-json-array-to-model-list-using-gson ?? – Himanshu Mori Jul 26 '18 at 10:09
1

an alternative extension function:

inline fun <reified T> Gson.fromJson(json: String) = fromJson<T>(json, object : TypeToken<T>() {}.type)

usage:

val str ="[....]"
val list:List<WeatherObject> = Gson().fromJson<List<WeatherObject>>(str)
yazan sayed
  • 777
  • 7
  • 24