2017-10-13 7 views
3

ÉDITÉE:Gson ou Moshi: champ POJO pourrait avoir 2 types, comment enregistrer dans l'un des champs

Voici la chaîne JSON que j'ai:

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 
} 

ou il pourrait tout JSON chaîne du serveur. Le point ici est il pourrait y avoir 1 ou plusieurs champs qui peuvent avoir une valeur dynamique (est-ce field3 cas peut être une chaîne ou int)

Je veux les désérialiser à tout POJO

class Temp1 { 
    // field1 here 
    // field2 here 

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

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

} 

Il signifie que si la valeur envoyée par le serveur est Int, je souhaite définir la valeur sur field3Int. S'il s'agit d'un String, définissez sur field3String.

Il pourrait y avoir d'autres POJO qui auront ce type de champs qui peuvent avoir une valeur dynamique. Merci à Serj pour sa réponse, mais je ne peux toujours pas le faire fonctionner sur la classe TypeAdapter après avoir édité la question pour montrer ma situation réelle.

Btw. Je l'utilise avec cette Retrofit2 comme ceci:

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

        .addConverterFactory(MoshiConverterFactory.create(moshi)) 
        .client(httpClient.build()) 
        .build() 
+0

est-ce que 'field1' et' field2' ont des types fixes ou sont-ils aussi dynamiques? –

+0

également dans votre exemple, 'json # 1' n'est pas un JSON valide. –

+0

@SerjLotutovici n'importe quel champ pourrait être dynamique. dans ce pojo, son seul champ3. – iori24

Répondre

1

Je pense que j'ai obtenu ce que je veux réaliser. Et pas besoin d'utiliser un adaptateur. Si un champ peut avoir un type dynamique, vous devez le déclarer comme Any dans votre POJO. Ensuite, si vous voulez utiliser sa valeur réelle, il vous suffit de vérifier son type et de le lancer. Donc, le POJO devrait aimer ceci:

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 -> "" 
     } 
    } 
} 
2

Avec Moshi vous pouvez tirer parti de former la fonction de désérialisation polymorphes. Il suffit d'écrire un adaptateur personnalisé qui utilisera JsonReader#readJsonValue(). Voir le code ci-dessous:

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")) 
    } 
} 
+0

Merci Serj pour l'aide. Btw, j'ai édité la question et j'ai lutté sur la partie amusante de @FromJson fromJson (lecteur: JsonReader). Besoin d'aide = / – iori24