当回复有时是一个对象而有时是一个数组时,如何在使用改进时解析JSON回复?

我正在使用Retrofit来获取JSON回复。

以下是我实施的部分内容 –

@GET("/api/report/list") Observable listBill(@Query("employee_id") String employeeID); 

和class级比尔是 –

 public static class Bills { @SerializedName("report") public ArrayList billItems; } 

BillItem类如下 –

 public static class BillItem { @SerializedName("id") Integer entryID; @SerializedName("employee_id") Integer employeeDBID; @SerializedName("type") String type; @SerializedName("subtype") String subtype; @SerializedName("date") String date; @SerializedName("to") String to; @SerializedName("from") String from; @SerializedName("amount") Double amount; @SerializedName("location") String location; @SerializedName("remark") String remark; @SerializedName("ispaid") String isPaid; @SerializedName("created_at") String createdAt; @SerializedName("updated_at") String updateAt; } 

问题是有时REST API返回一个BillItem对象数组,但有时它只是一个key-value对。 如何处理这种情况?

收到此响应后,一切正常,因为JSONArray被映射到ArrayList

 { "emp":{ "id":41, "name":"", "email":"", "created_at":"2016-02-01 10:36:38", "updated_at":"2016-02-01 10:36:38" }, "report":[ { "id":175, "employee_id":41, "type":"Travel", "subtype":"Car", "date":"2016-02-02 00:00:00", "to":"gaha", "from":"hshsj", "amount":"64", "location":"", "remark":"shhs", "ispaid":false, "created_at":"2016-02-01 13:52:52", "updated_at":"2016-02-01 13:52:52" }, { "id":179, "employee_id":41, "type":"Travel", "subtype":"Car", "date":"2016-02-01 00:00:00", "to":"Gsh", "from":"Dgdh", "amount":"7646", "location":"", "remark":"Shsh", "ispaid":false, "created_at":"2016-02-01 14:39:48", "updated_at":"2016-02-01 14:39:48" } ] } 

但是,有时响应是这样的,并且它给出了JsonSyntaxException

 { "emp":{ "id":41, "name":"", "email":"", "created_at":"2016-02-01 10:36:38", "updated_at":"2016-02-01 10:36:38" }, "report":{ "1":{ "id":175, "employee_id":41, "type":"Travel", "subtype":"Car", "date":"2016-02-02 00:00:00", "to":"gaha", "from":"hshsj", "amount":"64", "location":"", "remark":"shhs", "ispaid":false, "created_at":"2016-02-01 13:52:52", "updated_at":"2016-02-01 13:52:52" }, "2":{ "id":179, "employee_id":41, "type":"Travel", "subtype":"Car",":"2016-02-01 00:00:00", "to":"Gsh", "from":"Dgdh", "amount":"7646", "location":"", "remark":"Shsh", "ispaid":false, "created_at":"2016-02-01 14:39:48", "updated_at":"2016-02-01 14:39:48" }, "0":{ "id":181, "employee_id":41, "type":"Travel", "subtype":"Car", "date":"2016-02-01 00:00:00", "to":"ggg", "from":"vg", "amount":"0", "location":"", "remark":"cvv", "ispaid":false, "created_at":"2016-02-01 17:43:43", "updated_at":"2016-02-01 17:43:43" }, "3":{ "id":182, "employee_id":41, "type":"Travel", "subtype":"Car", "date":"2016-02-01 00:00:00", "to":"Haha", "from":"Ahah", "amount":"0", "location":"", "remark":"Ahah", "ispaid":false, "created_at":"2016-02-01 17:53:58", "updated_at":"2016-02-01 17:53:58" } } } 

如何处理这样的回复?

当您使用Gson反序列化器时,您可以检查JsonElement中的类型:

 Gson gson = new GsonBuilder() .registerTypeAdapter(BillItem.class, new BillItemDeserializer()) .registerTypeAdapter(Bills.class, new BillsDeserializer()) .create(); RestAdapter.Builder builder = new RestAdapter.Builder() //... .setConverter(new GsonConverter(gson)); public class BillsDeserializer implements JsonDeserializer { public Bills deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { BillItemList value = new BillItemList(); if (json.isJsonArray()) { for (JsonElement element : json.getAsJsonArray()) { value.add(gson.fromJson(element, BillItem.class)); } } else { value.add(gson.fromJson(element, BillItem.class)); } return value; } } 

请参阅示例: Gson反序列化 – 尝试将JSON解析为Object

正如@Gavriel的回答中所提到的,需要编写自定义Deserializer

这是我的实现(它可能包含多余的代码) –

实际API定义 –

 public interface ServerAPI { public static final String ENDPOINT = "http://xyz"; @GET("/api/report/list") Observable listBill(@Query("employee_id") String employeeID); public static class BillItem { @SerializedName("id") public Integer entryID; @SerializedName("employee_id") public Integer employeeDBID; @SerializedName("type") public String type; @SerializedName("subtype") public String subtype; @SerializedName("date") public String date; @SerializedName("to") public String to; @SerializedName("from") public String from; @SerializedName("amount") public Double amount; @SerializedName("location") public String location; @SerializedName("remark") public String remark; @SerializedName("ispaid") public String isPaid; @SerializedName("created_at") public String createdAt; @SerializedName("updated_at") public String updateAt; } public static class Bills { @SerializedName("report") // This seems to serve no purpose. public ArrayList billItems = new ArrayList<>(); // It was needed to initialize the ArrayList. public void add(BillItem billItem) { billItems.add(billItem); } } } 

这是我们在收到响应时实际创建BillItem类的地方。

 public class App extends Application { private static App instance; private static ServerAPI serverAPI; public static ServerAPI getServerAPI() { return serverAPI; } @Override public void onCreate() { super.onCreate(); Gson gson = new GsonBuilder() .registerTypeAdapter(BillItem.class, new BillItemDeserializer()) .registerTypeAdapter(Bills.class, new BillsDeserializer()) .create(); instance = this; serverAPI = new RestAdapter.Builder() .setEndpoint(ServerAPI.ENDPOINT) .setConverter(new GsonConverter(gson)) .setLogLevel(RestAdapter.LogLevel.FULL) .setLog(new RestAdapter.Log() { @Override public void log(String message) { Log.v("Retrofit", message); } }) .build().create(ServerAPI.class); } // This has nothing inside of it, it still works. public class BillItemDeserializer implements JsonDeserializer { @Override public BillItem deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return null; } } private class BillsDeserializer implements JsonDeserializer { @Override public Bills deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { Bills value = new Bills(); Gson gson = new Gson(); json = json.getAsJsonObject().get("report"); if (json.isJsonArray()) { for (JsonElement element : json.getAsJsonArray()) { value.add(gson.fromJson(element, BillItem.class)); } } else { JsonElement element = json.getAsJsonObject(); Set> entries = element.getAsJsonObject().entrySet(); for (Map.Entry entry : entries) { value.add(gson.fromJson(entry.getValue(), BillItem.class)); } } return value; } } } 

这是我们接收数据的Subscription对象。

 Subscription subscription = App.getServerAPI() .listBill(String.valueOf(employeeID)) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { Log.i(TAG, "ERROR: Value returned: " + e.getMessage()); e.printStackTrace(); } @Override public void onNext(ServerAPI.Bills bills) { for (ServerAPI.BillItem item : bills.billItems) { Log.i(TAG, "onNextBillItem: " + item); } } });