簡體   English   中英

如何使用Gson和Retrofit2解析動態命名的jsonarray?

[英]How to parse dynamically named jsonarray using Gson and retrofit2?

我有一個JSON響應,如下所示:

     {
    "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"
            }
        ]
    }
}

現在,“ data”標簽之后的部分是動態的,在響應中,我可以具有“ 1”,“ 2”而不是“ 3”或“ 4”的子數組。內部數據的POJO與您看到的相同。 那么我該如何解析這些數據呢? 我正在將Rerofit2與Gson.converterfactory一起使用。 我也嘗試過jsonchema2pojo,但“數據”對象內的數據未顯示。

我嘗試遵循這種方法: 使用具有不同JSON結構的Gson解析Retrofit2結果,但我似乎無法觸發UnrwapConverter。 這是我的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
    }
}

 }

和界面:

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

我的數據類是這些:

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)

在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);

在這里定義與您的引用相同的EqipmentDetails類

這肯定會工作

對於動態JSON,您必須手動解析JSON字符串。 要從改型中獲取JSON字符串,您必須使用ScalarsConverterFactory而不是GsonConverterFactory

添加此依賴項:

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

像這樣創建適配器:

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

使用ResponseBody創建請求方法

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

您可以這樣獲得Json String:

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();
    }
});

現在,您必須手動解析JSON字符串才能從JSON獲取數據。

希望能幫助到你:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM