[英]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.