【问题标题】:How to pass Map<String, Any> as parameter using Retrofit2?如何使用 Retrofit2 将 Map<String, Any> 作为参数传递?
【发布时间】:2021-06-17 23:50:40
【问题描述】:

我需要传递Map&lt;String, Any&gt; 作为 PUT 请求的参数。 Json(由 Map 制成)如下所示:

{
  "user": {
    "lastname": "Smith",
    "name": "John",
    ...
  },
  "foreign_language_keys": [
    "eng",
    "fr"
  ],
  "tachograph_cards": [
    {
      "tachograph_key": "estr",
      "tachograph_card_num":
      .....

如果我将 Map&lt;String, String&gt; 作为参数传递 - 它工作正常:

@FormUrlEncoded
@Headers("Content-Type: application/json")
@PUT("api/authorization/user/driver/{user_id}")
fun editUser(@Path("user_id") userId: String, @FieldMap body: Map<String, String>): Single<UserModel>

但如果我需要将 Map&lt;String, Any&gt; 作为参数传递 - 我会收到运行时错误“java.lang.IllegalArgumentException: Parameter type must not include a type variable or wildcard: java.util.Map (parameter #2)”

添加 @JvmSuppressWildcards 注释 (@FieldMap body: Map&lt;String, @JvmSuppressWildcards Any&gt;)) 没有帮助(我从服务器收到另一个错误“未定义索引”,用于 Json 中的一个必要字段,因为服务器在我的请求中看不到此字段)。

可行的解决方案是通过映射我模型中的所有字段(而不是传递Map&lt;String, Any&gt;)来制作com.google.gson.JsonObject,但这太难了。我确信它必须在不将我的模型转换为 Json 的情况下工作,但我找不到简单的解决方案。 有人可以帮忙吗?

【问题讨论】:

    标签: android kotlin retrofit2


    【解决方案1】:

    您的 JSON 结构看起来很奇怪且不一致。您为 Retrofit 传递结构,您需要定义清晰一致的结构。在您的情况下,看起来您的地图键始终是字符串,但地图的值部分有时是 Json 对象,有时是数组/列表或其他任何东西。不一致,这使得无法精确地确定结构化值。

    您不能肯定发布/放置Map&lt;String, Any,因为?是非法参数。

    您可以构造和发送Map&lt;String, JsonObject&gt;,如果您使用 Gson 库,创建 JsonObject 并不难。您所做的就是提取字符串(Json 对象的值部分)并将其提供给 Gson 库,然后它会生成 JsonObject 模型供您传递。

    或者你可以发送Map&lt;String, String&gt;,从解析端,你parse()stringify()的Json值,

    【讨论】:

      【解决方案2】:

      我最近遇到了同样的问题,我找到了可能是最简单的解决方案。 你可以在这里查看我对类似问题的完整答案:https://stackoverflow.com/a/61324340/7110268

      在你的特殊情况下,你可以试试这个:

      val body = mutableMapOf<String, String>()
      
      body["user[lastname]"] = "Smith"
      body["user[name]"] = "John"
      
      body["foreign_language_keys[0]"] = "eng"
      body["foreign_language_keys[1]"] = "fr"
      
      // and so on
      

      如果您需要传递一个巨大的动态列表,您可以轻松地将您的地图填充到for 循环中,例如。

      【讨论】:

        【解决方案3】:

        它必须是一个可变变量作为委托属性。能够用 Any 惩罚您想要放置的财产

        你的解决方案是把 MutableMap

        interface MutableMap<K, V> 
            
        V the type of map values. The mutable map is invariant in its value type.
        
        interfaceMap<K, V> 
            
        V the type of map values. The map is covariant in its value type.
        
        
        @FormUrlEncoded
        @Headers("Content-Type: application/json")
        @PUT("api/authorization/user/driver/{user_id}")
        fun editUser(@Path("user_id") userId: String, @FieldMap body: MutableMap<String, String>): Single<UserModel>
        

        【讨论】:

        • 这不是一个正确的答案,请详细说明它如何解决OP的问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-09
        • 2018-12-29
        • 1970-01-01
        • 2011-09-27
        相关资源
        最近更新 更多