Gson или Moshi: в поле POJO может быть 2 типа, как сохранить в любом из полей

Редакция:

Вот строка 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 или более полей, которые могут иметь динамическое значение (в этом случае поле3 может быть строкой или 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 после того, как я отредактировал вопрос, чтобы показать свою реальную ситуацию.

Btw. Я использую это с Retrofit2 следующим образом:

 val moshi = Moshi.Builder() .add(MultitypeJsonAdapterAdapter()) .build() return Retrofit.Builder().baseUrl(baseUrl) .addConverterFactory(MoshiConverterFactory.create(moshi)) .client(httpClient.build()) .build() 

Solutions Collecting From Web of "Gson или Moshi: в поле POJO может быть 2 типа, как сохранить в любом из полей"

С 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")) } } 

Я думаю, что получил то, что хочу. И не нужно использовать какой-либо адаптер. Если поле может иметь любой динамический тип, вам нужно объявить его как «Любой» в вашем POJO. Затем, если вы хотите использовать его фактическое значение, вам просто нужно проверить его тип и бросить его. Поэтому 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) } else -> "" } } }