2017-09-22 23 views
0

J'ai une réponse JSON, qui ressemble à ceci:Comment analyser dynamiquement jsonarray avec Gson et retrofit2?

 { 
    "equipment_layer": [ 
     { 
      "id": 2, 
      "name": "Gateway", 
      "detail": "All gateways" 
     }, 
     { 
      "id": 3, 
      "name": "Node", 
      "detail": "All Nodes" 
     }, 
     { 
      "id": 1, 
      "name": "Miscellaneous", 
      "detail": "All miscellaneous assets" 
     }, 
     { 
      "id": 4, 
      "name": "Sensors", 
      "detail": "All Sensors" 
     }, 
     { 
      "id": 5, 
      "name": "IRM", 
      "detail": "Installation required material" 
     }, 
     { 
      "id": 6, 
      "name": "Communication", 
      "detail": "All communication devices such as Cellular Router, ETU etc. which are purely communication" 
     } 
    ], 
    "data": { 
     "1": [ 
      { 
       "equipment_id": 353, 
       "item_quantity": 1, 
       "name": "DC Current Transformer (20mm) (Old)", 
       "shortcode": "SNS-DCI-CT20m-R1A", 
       "part_number": "718,804,805,", 
       "equipment_layer_id": 1, 
       "equipment_layer_name": "Miscellaneous" 
      }, 
      { 
       "equipment_id": 357, 
       "item_quantity": 1, 
       "name": "Fuel Sensor - B4 (Old)", 
       "shortcode": "SNS-FUL-PSR-R1A", 
       "part_number": "718,810,811", 
       "equipment_layer_id": 1, 
       "equipment_layer_name": "Miscellaneous" 
      } 
     ], 
     "2": [ 
      { 
       "equipment_id": 345, 
       "item_quantity": 1, 
       "name": "RTU (Old)", 
       "shortcode": "RAN-RTU-PMCL-R1A", 
       "part_number": "787,788,789", 
       "equipment_layer_id": 2, 
       "equipment_layer_name": "Gateway" 
      } 
     ], 
     "3": [ 
      { 
       "equipment_id": 356, 
       "item_quantity": 1, 
       "name": "Battery Analyzer (Product) (Old)", 
       "shortcode": "RAN-BAM-PMCL-R1A", 
       "part_number": "787,808,809", 
       "equipment_layer_id": 3, 
       "equipment_layer_name": "Node" 
      } 
     ], 
     "4": [ 
      { 
       "equipment_id": 346, 
       "item_quantity": 1, 
       "name": "DC Current Transformer (30mm) (Old)", 
       "shortcode": "SNS-CT-DCI-R1A", 
       "part_number": "718,792,793", 
       "equipment_layer_id": 4, 
       "equipment_layer_name": "Sensors" 
      }, 
      { 
       "equipment_id": 350, 
       "item_quantity": 1, 
       "name": "AC Block CT (Old)", 
       "shortcode": "SNS-ACI-BLK-R1A", 
       "part_number": "718,790,791", 
       "equipment_layer_id": 4, 
       "equipment_layer_name": "Sensors" 
      } 
     ] 
    } 
} 

Maintenant la partie après l'étiquette « données » est dynamique, dans une réponse que je peux avoir sous-tableaux de « 1 », « 2 », mais pas de "3" ou "4". Le POJO des données à l'intérieur est le même que vous pouvez voir. Alors, comment puis-je analyser ces données? J'utilise Rerofit2 avec Gson.converterfactory. J'ai aussi essayé jsonchema2pojo mais les données à l'intérieur de l'objet "data" n'apparaissent pas. J'ai essayé de suivre cette méthode: Parsing Retrofit2 result using Gson with different JSON structures mais je n'arrive pas à déclencher le UnrwapConverter. Ceci est ma mise en œuvre converterfactory:

internal class UnwrappingGsonConverterFactory private constructor(private val gson: Gson) : Converter.Factory() { 

override fun responseBodyConverter(type: Type, annotations: Array<Annotation>, retrofit: Retrofit): Converter<ResponseBody, *> ?{ 
    if (!needsUnwrapping(annotations)) { 
     return super.responseBodyConverter(type, annotations, retrofit) 
    } 
    val typeAdapter = gson.getAdapter(TypeToken.get(type)) 
    return UnwrappingResponseConverter(typeAdapter) 
} 

private class UnwrappingResponseConverter (private val typeAdapter: TypeAdapter<*>) : Converter<ResponseBody, Any> , AnkoLogger{ 

    @Throws(IOException::class) 
    override fun convert(responseBody: ResponseBody): Any? { 
     responseBody.use { responseBody -> 
      JsonReader(responseBody.charStream()).use({ jsonReader -> 
       // Checking if the JSON document current value is null 
       val token = jsonReader.peek() 
       if (token === JsonToken.NULL) { 
        return null 
       } 
       // If it's an object, expect `{` 
       jsonReader.beginObject() 
       var value: Any? = null 
       // And iterate over all properties 
       while (jsonReader.hasNext()) { 
        val data = jsonReader.nextName() 
        debug("Unwrap Stuff: $data") 
        when (data) { 
         "1", "2", "3", "4", "5", "6" -> value = typeAdapter.read(jsonReader) 

         else ->jsonReader.skipValue() 
        } 
       } 
       // Consume the object end `}` 
       jsonReader.endObject() 
       return value 
      }) 
     } 
    } 

} 

companion object { 

    fun create(gson: Gson): Converter.Factory { 
     return UnwrappingGsonConverterFactory(gson) 
    } 

    private fun needsUnwrapping(annotations: Array<Annotation>): Boolean { 
     for (annotation in annotations) { 
      if (annotation is Unwrap) { 
       return true 
      } 
     } 
     return false 
    } 
} 

} 

Et l'interface:

@Retention(AnnotationRetention.RUNTIME) 
    @Target(AnnotationTarget.FUNCTION) 
    annotation class Unwrap 

Mes classes de données sont les suivantes:

data class ActivityNodes(@SerializedName("equipment_layer") val equipmentLayer: List<EquipmentLayer>, 
         @SerializedName("data") val data: nodeData) 

data class nodeData (@SerializedName("1") val nodeList: List<dataItem>) <-- this is where I need someway to tell SerializedName that the value can be anything from 1 to 6 

data class dataItem(@SerializedName("equipment_id") val equipmentId: Int, 
        @SerializedName("item_quantity") val itemQuantity: Int, 
        @SerializedName("name") val name: String, 
        @SerializedName("shortcode") val shortCode: String, 
        @SerializedName("part_number") val partNumber: String, 
        @SerializedName("equipment_layer_id") val equipmentLayerId: Int, 
        @SerializedName("equipment_layer_name") val equipmentLayerName: String, 
        var isScanned: Boolean = false) 



data class EquipmentLayer(@SerializedName("id") val id: Int, 
          @SerializedName("name") val name: String, 
          @SerializedName("detail") val details: String) 
+0

vous devez mettre le code que vous avez mis en œuvre – joao86

Répondre

0

utilisation ci-dessous pour la partie des "données" de JSON:

Type mapType = new TypeToken<Map<String, List<EqupmentDetail.class>>>() {}.getType(); // define generic type 
Map<String, List<EqupmentDetail.class>> result= gson.fromJson(new InputStreamReader(source), mapType); 

ici définir la classe EqipmentDetails même que votre refence

ce sera certainement travailler

+0

, je dois donc écrire un désérialiseur personnalisé? pas un converterfactory – ibraizQ9

+0

où devrais-je ajouter ces lignes? dans un désérialiseur ou l'usine de convertisseur? – ibraizQ9

0

Pour la JSON dynamique, vous devez analyser la chaîne JSON manuellement. Pour obtenir la chaîne JSON de retrofit, vous devez utiliser ScalarsConverterFactory au lieu de GsonConverterFactory.

Ajouter cette dépendance:

compile 'com.squareup.retrofit2:converter-scalars:2.3.0' 

Créer adaptateur comme ceci:

Retrofit retrofit = new Retrofit.Builder() 
    .baseUrl("http://echo.jsontest.com") 
    .addConverterFactory(ScalarsConverterFactory.create()) 
    .build() 

Créer méthode de demande avec ResponseBody

public interface MyService { 
    @GET("/key/value/one/two") 
    Call<ResponseBody> getData(); 
} 

Vous pouvez obtenir Json chaîne comme ceci:

MyService service = retrofit.create(MyService.class); 
Call<ResponseBody> result = service.getData(); 
result.enqueue(new Callback<ResponseBody>() { 
    @Override 
    public void onResponse(Response<ResponseBody> response) { 
     try { 
      System.out.println(response.body().string()); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public void onFailure(Throwable t) { 
     e.printStackTrace(); 
    } 
}); 

Maintenant, vous devez analyser la chaîne JSON manuellement pour obtenir vos données à partir de JSON.

Hope it helps :)