3

编辑:

这是我拥有的json字符串:

json#1
{
    [
        {
            field1 : ""
            field2 : 0
            field3 : "Amount not fixed" or field : 250 // this field can be string or int
        },
        {
            field1 : ""
            field2 : 0
            field3 : "Amount not fixed" or field : 250 // this field can be string or int
        }

    ]
}

json#2
{
    field1 : ""
    field2 : 0
    field3 : "Amount not fixed" or field : 250 // this field can be string or int
}

或者它可以来自服务器的任何 json 字符串。这里的要点是可能有 1 个或多个字段可能具有动态值(在这种情况下 field3 可以是字符串或 int)

然后我想将它们反序列化为任何 POJO

class Temp1 {
    // field1 here
    // field2 here

    @SerializedName("field3")
    val field3Int: Int? = null

    @SerializedName("field3")
    val field3String: String? = null

}

这意味着如果从服务器发送的值是Int,我想将值设置为field3Int。如果是String,则设置为field3String

可能有其他 POJO 将具有这些可能具有动态值的字段。

感谢 Serj 的回答,但在我编辑问题以显示我的真实情况后,我仍然无法使其在 TypeAdapter 类上工作。

顺便提一句。我将它与 Retrofit2 一起使用,如下所示:

val moshi = Moshi.Builder()
                    .add(MultitypeJsonAdapterAdapter())
                    .build()
            return Retrofit.Builder().baseUrl(baseUrl)

                    .addConverterFactory(MoshiConverterFactory.create(moshi))
                    .client(httpClient.build())
                    .build()
4

2 回答 2

8

您可以利用Moshi表单的多态反序列化功能。只需编写一个将使用JsonReader#readJsonValue(). 请参见下面的代码:

data class Multitype constructor(val fieldInt: Int?, val fieldString: String?) {
  constructor(fieldInt: Int) : this(fieldInt, null)
  constructor(fieldString: String) : this(null, fieldString)
}

class MultitypeJsonAdapterAdapter {
   @FromJson fun fromJson(reader: JsonReader): Multitype {
      val jsonValue = reader.readJsonValue() as Map<String, Any?>
      val field = jsonValue["field"]
      return when (field) {
        is String -> Multitype(field)
        is Double -> Multitype(field.toInt()) // readJsonValue parses numbers as Double
        else -> throw JsonDataException("Expected a field of type Int or String")
      }
   }

   @ToJson fun toJson(writer: JsonWriter, value: Multitype?) {
     TODO("not implemented")
   }

}

class MultitypeJsonAdapterAdapterTest {
  @Test fun check() {
    val moshi = Moshi.Builder()
      .add(MultitypeJsonAdapterAdapter())
      .add(KotlinJsonAdapterFactory())
      .build()

    val adapter = moshi.adapter(Multitype::class.java)

    val fromJson1 = adapter.fromJson("""{ "field": 42 }""")
    assertThat(fromJson1).isEqualTo(Multitype(42))

    val fromJson2 = adapter.fromJson("""{ "field": "test" }""")
    assertThat(fromJson2).isEqualTo(Multitype("test"))
  }
}
于 2017-10-13T09:22:08.207 回答
3

我想我得到了我想要达到的目标。并且无需使用任何适配器。如果一个字段可以有任何动态类型,则需要在 POJO 中将其声明为 Any。然后如果你想使用它的实际值,你只需要检查它的类型并转换它。所以 POJO 应该是这样的:

class Temp1 {
    // field1 here
    // field2 here

    @SerializedName("field3")
    val field3: Any? = null

    fun getField3Str() : String {
        return when (field3) {
            is String -> field3 as String
            is Int -> {
                "%d".format(field3 as Int)
            }
            is Double -> {
                "%d".format(field3.toInt())
            }
            else -> ""
        }
    }
}
于 2017-10-16T03:16:43.903 回答