Retrofit генерирует неверные параметры запроса GET из карты - PullRequest
0 голосов
/ 10 декабря 2018

У меня есть следующие данные:

var dict: Map<String, Any> = listOf()
dict["p1"] = listOf(1, 3)
dict["p2"] = listOf(null, 2.1)
dict["p3"] = 1

Когда я передаю эти данные следующей функции:

@GET("uri?staticKey=staticValue")
fun testApi(@QueryMap(encoded = true) params: @JvmSuppressWildcards Map<String, Any>): Call<ResponseBody>

Я ожидаю, что URL запроса будет:

uri?staticKey=staticValue&
    p1[0]=1&p1[1]=3&
    p2[0]=&p2[1]=2.1&
    p3=1

Но вот что это выдает:

uri?staticKey=staticValue&
    p1=[1, 3]&
    p2=[null, 2.1]&
    p3=1

Я что-то не так делаю?Я только начал разработку Kotlin и Android, поэтому я не уверен, что это поддерживается библиотекой Retrofit / okhttp.

Примечание Мне нужна такая функция, как Map<String, Any>, чтобы легкодобавить / удалить параметры запроса.

Ответы [ 2 ]

0 голосов
/ 15 декабря 2018

Вот мое решение, которое предлагает


  • Оригинальные ключи в HashMap, так что возможно обновление / удаление, например

    dict.remove("p1")
    dict["p1"] = new value
    
  • Возможность иметь вложенные массивы, такие как

    [
      0: [coord1, coord2, coord3],
      1: [coord1, coord2, coord3]
    ]
    

data class URL(val params: MutableMap<String, Any> = mutableMapOf<String, Any>()) {

    override fun toString(): String = params.map {
        val value = it.value
        if (value !is Iterable<*>) {
            it.key + "=" + it.value.toString()
        } else {
            createPairs(it.key, value)
        }
    }.joinToString("&")

    fun createPairs(key: String, value: Iterable<*>): String {
        return value.mapIndexed { idx, value ->
            val useKey = key + "[" + idx + "]"
            if (value !is Iterable<*>) {
                useKey + "=" + (value?.toString() ?: "")
            } else
                createPairs(useKey, value)

        }.joinToString("&")
    }
}

Использование:

val url = URL()
url.params["p1"] = listOf(1, 3)
url.params["p2"] = listOf(null, 2.1)
url.params["p3"] = 1

val polygon1 = listOf("p1-coord1", "p1-coord2")
val polygon2 = listOf("p2-coord1", "p2-coord2", "p2-coord3")
val polygon3 = listOf("p3-coord1", "p3-coord2")
url.params["bbox"] = listOf(polygon1, polygon2, polygon3)

println(url.toString())

Вывод:

p1[0]=1&p1[1]=3&
p2[0]=&p2[1]=2.1&
p3=1&
bbox[0][0]=p1-coord1&bbox[0][1]=p1-coord2&
bbox[1][0]=p2-coord1&bbox[1][1]=p2-coord2&bbox[1][2]=p2-coord3&
bbox[2][0]=p3-coord1&bbox[2][1]=p3-coord2
0 голосов
/ 11 декабря 2018

Дооснащение просто вызывает toString() на значение Map<String, Any>.Чтобы достичь того, что вы намерены, вы должны определить его напрямую

var dict: Map<String, Any> = listOf()
dict["p1[0]"] = 1
dict["p1[1]"] = 3
dict["p2[0]"] = ""
dict["p2[1]"] = 2.1
dict["p3"] = 1

Вы можете отобразить карту, просто сгладив ее

fun Map<String, Any>.queryArgs(): Map<String, Any> {
    val map = mutableMapOf<String, Any>()
    forEach { (key, value) ->
        if (value !is Iterable<*>) {
            map[key] = value
        } else value.forEachIndexed { index, value ->
            map["$key[$index]"] = value ?: ""
        }
    }
    return map
}

Это предполагает только один уровень списков максимум.

...