2
\$\begingroup\$

I do work for a project currently, where the data is send to the server as application/x-www-form-urlencoded (which is bad, and it should be JSON, but unfortunately I am not able to change this one).

The following code snipped will transfer the given parameters (in a loop) to a Map, which can then be transformed to json (eg. by using jackson).

I would like to make this even better, so please post your comments and suggestions.

Parameter-List:

_id=[5bfad95450642c333010daca], 
_rev=[1-9ce33949c3acd85cea6c58467e6a8144], 
type=[Group], 
user=[aUSer], 
default=[aDetail], 
store[aDetail][prop]=[5], 
store[aDetail][lprop1][0][time]=[00:00], 
store[aDetail][lprop1][0][value]=[14], 
store[aDetail][lprop1][0][timeAsSeconds]=[0],
store[aDetail][lprop1][1][time]=[07:00], 
store[aDetail][lprop1][1][value]=[8], 
store[aDetail][lprop1][1][timeAsSeconds]=[25200], 
store[aDetail][anprop]=[25], 
store[aDetail][lprop2][0][time]=[00:00], 
store[aDetail][lprop2][0][value]=[61], 
store[aDetail][lprop2][0][timeAsSeconds]=[0],   
store[bDetail][prop]=[6], 
store[bDetail][lprop1][0][time]=[00:10], 
store[bDetail][lprop1][0][value]=[12], 
store[bDetail][lprop1][0][timeAsSeconds]=[0],
store[bDetail][lprop1][1][time]=[07:10], 
store[bDetail][lprop1][1][value]=[9], 
store[bDetail][lprop1][1][timeAsSeconds]=[25200], 
store[bDetail][anprop]=[25], 
store[bDetail][lprop2][0][time]=[00:00], 
store[bDetail][lprop2][0][value]=[61], 
store[bDetail][lprop2][0][timeAsSeconds]=[0], 
created_at=[2018-01-11T20:48:22.574+0100],
...

Code-Snippet:

fun parseToMap(map: MutableMap<String, Any>, key: String, value: Any): MutableMap<String, Any> {
    val cleanedV = if (value is String) URLDecoder.decode(value, "UTF-8") else value

    if (!key.contains("[")) {
        map.putIfAbsent(key, cleanedV)
    } else {
        // mapKey is the key going to get stored in the map
        val mapKey = key.substring(0, key.indexOf("["))

        // nextKey is the next key pushed to the next call of parseToMap
        var nextKey = key.removePrefix(mapKey)
        nextKey = nextKey.replaceFirst("[", "").replaceFirst("]", "")

        var isArray = false
        var index = -1

        if (nextKey.contains("[") &&
                nextKey.substring(0, nextKey.indexOf("[")).matches(Regex("[0-9]+"))) {
            index = nextKey.substring(0, nextKey.indexOf("[")).toInt()
            isArray = true
        }

        // mapkey used for object in list
        val newMapKey = if (isArray) nextKey.substring(nextKey.indexOf("[") + 1, nextKey.indexOf("]")) else ""

        val child: Any?
        var childMap: MutableMap<String, Any> = mutableMapOf()

        if (map.containsKey(mapKey)) {
            println("key $mapKey exists already")
            child = map[mapKey]

            when (child) {
                is MutableList<*> -> {
                    if (child == null || child.isEmpty()) {
                        childMap = mutableMapOf()
                        val tmpList = child as MutableList<Any>
                        tmpList.add(childMap)
                        map.put(newMapKey, tmpList)
                    } else {
                        if (child.size > index) {
                            childMap = child.get(index) as MutableMap<String, Any>
                            childMap = parseToMap(childMap, newMapKey, value)
                        } else {
                            childMap = parseToMap(childMap, newMapKey, value)
                            val tmpList = child as MutableList<Any>
                            tmpList.add(childMap)
                        }
                    }
                }
                is MutableMap<*, *> -> childMap = map.get(mapKey) as MutableMap<String, Any>
            }
        } else {
            if (isArray) {
                child = mutableListOf<Any>()
                childMap = parseToMap(childMap, newMapKey, value)
                child.add(childMap)
                map.put(mapKey, child)
            } else {
                childMap = mutableMapOf<String, Any>()
            }
        }

        if (!isArray) parseToMap(childMap, nextKey, value)

        map.putIfAbsent(mapKey, childMap)
    }

    return map
}

Calling this method:

    decodedParameters.forEach { k, v -> run {
        val cleanedV = v.toString().replace("[", "").replace("]", "")
        jsonMap = parseToMap(jsonMap, k, cleanedV)
    } }
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.