1

I'm trying to convert a nested Map to a JSONObject like so:

    fun convertToJson(input: Map<String, Any>): JSONObject {
        val jsonObject = JSONObject()
        input.forEach { (key, value) ->
            if (value is Map<*, *>) {
                val iterator = value.entries.iterator()
                while (iterator.hasNext()) {
                    val pairs = iterator.next()
                    (pairs.key as? String)?.let { k ->
                        pairs.value?.let { v ->
                            jsonObject.put(k, v)
                        }
                    }
                }
            }
            jsonObject.put(key, value)
        }
        return jsonObject
    }

(I tried following this example Putting HashMap<String, object> in jsonobject)

I call it like so

val input = mapOf(
  "key1" to mapOf("inner_key1" to "foo"))
val output = convertToJson(input)

What I don't understand, is why is

output.optJSONObject("key1") null? From what I understand, output.opt("key1") returns a Map<*, *>.

That's about as far as I got. I'm not sure if my convertToJson needs fixing, or if my understanding needs correcting, in that, optJSONObject should not be used for nested types and I should use opt if I know the type will be a Map.

halfer
  • 19,824
  • 17
  • 99
  • 186
Crystal
  • 28,460
  • 62
  • 219
  • 393

2 Answers2

1

Try to put JSONObject inside JSONObject instead of Map<*, *>

fun convertToJson(input: Map<String, Any>): JSONObject {
    val jsonObject = JSONObject()
    input.forEach { (key, value) ->
        if (value is Map<*, *>) {
            val iterator = value.entries.iterator()
            val childObject = JSONObject()
            while (iterator.hasNext()) {
                val pairs = iterator.next()
                (pairs.key as? String)?.let { k ->
                    pairs.value?.let { v ->
                        childObject.put(k, v)
                    }
                }
            }

            jsonObject.put(key, childObject)
        } else {
            jsonObject.put(key, value)
        }
    }
    return jsonObject
}
Md. Asaduzzaman
  • 14,963
  • 2
  • 34
  • 46
1

The logic in your code doesn't put keys of a Map into a nested object, but directly into jsonObject. And then it also calls jsonObject.put(key, value) even for a Map (which I am a bit surprised doesn't throw an exception, because it isn't one of the allowed types:

Object: a JSONObject, JSONArray, String, Boolean, Integer, Long, Double, NULL, or null. May not be Double#isNaN() or Double#isInfinite().

).

Assuming keys of any nested Map are strings, I would just do it recursively:

@Suppress("UNCHECKED_CAST")
fun convertToJson(input: Map<String, Any>): JSONObject {
    val jsonObject = JSONObject()
    input.forEach { (key, value) ->
        value1 = if (value is Map<*, *>)
            convertToJson(value as Map<String, Any>)
        else
            value
        jsonObject.put(key, value1)
    }
    return jsonObject
}

(this really should be extended to handle Lists, null, etc. in addition, but that's not part of the question)

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487