如何使用Gson和retrofit2动态解析名为jsonarray的?

时间:2017-09-22 12:24:57

标签: android json gson 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"
            }
        ]
    }
}

现在是"数据"之后的部分标签是动态的,在响应中,我可以有" 1"," 2"的子阵列。但不是" 3"或" 4"。内部数据的POJO与您可以看到的相同。那么我该如何解析这些数据呢?我使用Rerofit2和Gson.converterfactory。我也尝试了jsonchema2pojo但是数据内部的数据"对象没有出现。

我试图按照这种方法: Parsing Retrofit2 result using Gson with different JSON structures但我似乎无法触发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)

2 个答案:

答案 0 :(得分:0)

在下面使用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类与你的refence

相同

这肯定会有用

答案 1 :(得分:0)

对于动态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获取数据。

希望有所帮助:)