Retrofit 从 Map<String : Any> 生成错误的 GET 请求参数
Retrofit generates wrong GET request parameters from Map<String : Any>
我有以下数据:
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>
这样的功能,以便轻松add/delete查询参数。
Retrofit 只是在 Map<String, Any>
的值上调用 toString()
。要实现你想要的,你必须直接定义它
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
}
这假设最多只有一层列表。
这是我提供的解决方案
HashMap中的原始key,这样updating/deleting是可以的,比如
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
我有以下数据:
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>
这样的功能,以便轻松add/delete查询参数。
Retrofit 只是在 Map<String, Any>
的值上调用 toString()
。要实现你想要的,你必须直接定义它
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
}
这假设最多只有一层列表。
这是我提供的解决方案
HashMap中的原始key,这样updating/deleting是可以的,比如
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