I am using Kotlin to parse JSON. For example, I have this representation of a country: {"code":"US", "name":"United States of America"}
. To produce a Country
object from such a JSONObject
, I have this function:
val produceCountry = fun (js: JSONObject) =
Country(js.getString("code"), js.getString("name"))
I can easily parse an array of Country
with this function. Besides arrays of Country
, however, I also have arrays of Cat
, Car
, Cart
, CordlessPhone
, etc. Each has their own produce*
function transforming a JSONObject
to a Kotlin object of that type. To generalize array parsing, I have this function:
fun <T> produceSetOf(array: JSONArray, element: (JSONObject) -> T): Set<T> {
val set = mutableSetOf<T>()
for (i in 0 until array.length())
set.add(element(array.getJSONObject(i)))
return set
}
So I can call produceSetOf(jsonArray, produceCountry)
on encountering an array whose elements are of type Country
. This works well on arrays of Cat
, Car
, Cart
, CordlessPhone
too.
Problem arises when I see an array of strings. Instead of array.getJSONObject(i)
, I have to use array.getString(i)
. In effect, I am thinking of introducing another parameterized type to the function above and have it make the call differently:
fun <S,T> produceSetOf(array: JSONArray, element: (S) -> T): Set<T> {
val set = mutableSetOf<T>()
for (i in 0 until array.length()) {
when (S) {
is String ->
set.add(element(array.getString(i)))
is JSONObject ->
set.add(element(array.getJSONObject(i)))
}
}
return set
}
Of course, Kotlin does not allow me to do that. Any suggestion how I could do that while maintaining the generality of produceSetOf()
and without introducing another layer of abstraction (e.g. an element iterator, or a function transforming an index into String/JSONObject)?
Thank you.
`. If I put `S::class.java` in `when`, the complaint turns to `Incompatible types: String and Class– Nick Lee Jul 26 '18 at 10:10`. The line `is JSONObject` does not raise complaint in either case. Any clue why that is? Thank again.