Reputation: 2259
I'm trying to parse json from an http request in a Kotlin Android file. I'd really like to avoid having to specifically use GSON to deserialize into a class every time I make an http request if I just want to pull a single element. I come from javascript land where parsing json into object notation comes right out of the box, so this has caused irritation.
Here is what I am working with currently. I'm using Fuel to make the http request and Klaxon to try and parse it.
Fuel.get("http://api.openweathermap.org/data/2.5/weather?q=Austin,us&appid=MYAPIKEYSUPERDUPERSECRET").responseString { request, response, result ->
//do something with response
result.fold({ d ->
println("value of d")
println(d)
val parser = Parser()
val stringBuilder = StringBuilder(d)
val json: JsonObject = parser.parse(stringBuilder) as JsonObject
println("Weather : ${json.string("weather")}")
}, { err ->
//do something with error
})
}
So when I run the above I get the following.
From my println("value of d")
I get
{"coord":{"lon":-97.74,"lat":30.27},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],"base":"stations","main":{"temp":297.15,"pressure":1010,"humidity":69,"temp_min":296.15,"temp_max":298.15},"visibility":16093,"wind":{"speed":5.7,"deg":150,"gust":11.8},"clouds":{"all":90},"dt":1519082640,"sys":{"type":1,"id":2558,"message":0.0053,"country":"US","sunrise":1519045581,"sunset":1519086201},"id":4671654,"name":"Austin","cod":200}
The specifics are probably not important, it's just a pull from WeatherApi, but I can see that it works. Also, that it appears to be a string. Importantly if I try and println(d.toString())
it recognizes it as a string, and greys out .toString()
Now, from the Klaxon parsing I get the following error:
FATAL EXCEPTION: main
Process: com.example.patientplatypus.androidhoneytabs, PID: 32050
java.lang.ClassCastException: com.beust.klaxon.JsonArray cannot be cast to java.lang.String
at com.beust.klaxon.JsonObject.string(JsonObject.kt:74)
at com.example.patientplatypus.androidhoneytabs.MainActivity$onCreate$2.invoke(MainActivity.kt:74)
at com.example.patientplatypus.androidhoneytabs.MainActivity$onCreate$2.invoke(MainActivity.kt:39)
at com.github.kittinunf.fuel.core.DeserializableKt$response$1.invoke(Deserializable.kt:37)
at com.github.kittinunf.fuel.core.DeserializableKt$response$1.invoke(Unknown Source:4)
at com.github.kittinunf.fuel.core.DeserializableKt$response$5$1.invoke(Deserializable.kt:62)
at com.github.kittinunf.fuel.core.DeserializableKt$response$5$1.invoke(Unknown Source:0)
at com.github.kittinunf.fuel.core.Request$callback$1.run(Request.kt:225)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
So the error here is telling me that somewhere I am trying to cast a jsonarray object to a string. It can't be from d -> JsonObject. I have seen that if I comment out the line println("Weather : ${json.string("weather")}")
, but I'm not sure if that still means that the val json
object is still being mishandled (if it assigns and isn't used does the compiler properly evaluate it?).
What's frustrating is that this appears to be proper usage according to the Klaxon documentation. See: https://github.com/cbeust/klaxon and below:
val parser: Parser = Parser()
val stringBuilder: StringBuilder = StringBuilder("{\"name\":\"Cedric Beust\", \"age\":23}")
val json: JsonObject = parser.parse(stringBuilder) as JsonObject
println("Name : ${json.string("name")}, Age : ${json.int("age")}")
Does anyone have any ideas what is going wrong?
Quick Edit:
result.fold({ d ->
println("value of d")
println(d)
val parser: Parser = Parser()
val stringBuilder: StringBuilder = StringBuilder("{\"name\":\"Cedric Beust\", \"age\":23}")
val json: JsonObject = parser.parse(stringBuilder) as JsonObject
println("Name : ${json.string("name")}, Age : ${json.int("age")}")
Does correctly print Cedric's name. So that seems fine. Hmm....
Upvotes: 2
Views: 6120
Reputation: 127034
Neat, that I know Fuel.
"http://api.openweathermap.org/data/2.5/weather?q=Austin,us&appid=MYAPIKEYSUPERDUPERSECRET"
.httpGet().responseJSON { _, _, result ->
result.get().obj() // here you have your JSON object
}
Note, that httpGet
is just another way of writing Fuel.get()
, it is a String
extension function and the important part is that I used reponseJSON
instead of responseString
.
Also you will need to use .getString("name")
on the object. You can also use something like .getJSONObject
or .getJSONArray
.
Upvotes: 6