Dedicated Server

Parse json array with unkown key using Map in Android

Hi, this is yet another tutorial associated with json parsing in android. Let us see how can we parse a json array for which the key is not known beforehand. This means that the key names of the json array has to be identified and parsed dynamically.

You may take a look at one of my previous post regarding json parsing with unknown key, if you haven't already checked.

In this tutorial, we can make use of Map to parse the json array with dynamic key. We will be using retrofit library to perform the network calls.

First of all, add the following dependecies to your app level build.gradle file :

compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'

Let us try to parse a json response which will be like this sometimes

{
  "response": "success",
  "servicecode": "134",
  "forecast": {
    "month": {
      "jan": [
        {
          "id": "1",
          "price": "12",
          "Product": "1086",
          "Qty": "14",
          "date": "2018-10-27 16:08:57"
        },
        {
          "id": "2",
          "price": "19",
          "Product": "1746",
          "Qty": "45",
          "date": "2018-10-27 16:08:57"
        }
      ],
      "april": [
        {
          "id": "3",
          "price": "89",
          "Product": "1986",
          "Qty": "15",
          "date": "2018-10-27 16:08:57"
        },
        {
          "id": "1",
          "price": "12",
          "Product": "1086",
          "Qty": "145",
          "date": "2018-10-27 16:08:57"
        }
      ],
      "jun": [
        {
          "id": "81",
          "price": "132",
          "Product": "17086",
          "Qty": "1445",
          "date": "2018-10-27 16:08:57"
        },
        {
          "id": "11",
          "price": "132",
          "Product": "10786",
          "Qty": "1445",
          "date": "2018-10-27 16:08:57"
        }
      ]
    }
  },
  "message": "Competitor Sales."
}

and it will be changing dynamically like this sometimes

{
  "response": "success",
  "servicecode": "134",
  "forecast": {
    "month": {
      "april": [
        {
          "id": "3",
          "price": "89",
          "Product": "1986",
          "Qty": "15",
          "date": "2018-10-27 16:08:57"
        },
        {
          "id": "1",
          "price": "12",
          "Product": "1086",
          "Qty": "145",
          "date": "2018-10-27 16:08:57"
        }
      ]
    }
  },
  "message": "Competitor Sales."
}

Here you can see that the json array key names jan, jun are missing in second response. So we will have to dynamically parse these key names.

From the above response we can see that :

  • the entire response is enclosed in a json object({}), so we will create a model class(Example.java
  • we can see that there is one more json object inside the outer json object - forecast, so we will create another model class for it(Forcast.java)
  • inside forecast, there is one more json object - month, but it contains some dynamically named json array. So we need to create a Map object that takes in a String and List<MonthModel>>. Please note that the Map object is used to parse the following pattern

"april": [
        {
          "id": "3",
          "price": "89",
          "Product": "1986",
          "Qty": "15",
          "date": "2018-10-27 16:08:57"
        }

where String corresponds to "april" and List<MonthModel>> corresponds to the json array enclosed in [{}]

  • So we need to create one more mode class MonthModel.java
Now generate the model classes as explained :

Example.java

public class Example {
    @SerializedName("response")
    @Expose
    private String response;
    @SerializedName("servicecode")
    @Expose
    private String servicecode;
    @SerializedName("forecast")
    @Expose
    private Forecast forecast;
    @SerializedName("message")
    @Expose
    private String message;

    public String getResponse() {
        return response;
    }

    public void setResponse(String response) {
        this.response = response;
    }

    public String getServicecode() {
        return servicecode;
    }

    public void setServicecode(String servicecode) {
        this.servicecode = servicecode;
    }

    public Forecast getForecast() {
        return forecast;
    }

    public void setForecast(Forecast forecast) {
        this.forecast = forecast;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

Forecast.java
public class Forecast {
    @SerializedName("month")
    @Expose
    private Map<String, List<MonthModel>> result;

    public Map<String, List<MonthModel>> getResult() {
        return result;
    }

    public void setResult(Map<String, List<MonthModel>> result) {
        this.result = result;
    }
}

MonthModel.java
public class MonthModel {
    @SerializedName("id")
    @Expose
    private String id;
    @SerializedName("price")
    @Expose
    private String price;
    @SerializedName("Product")
    @Expose
    private String product;
    @SerializedName("Qty")
    @Expose
    private String qty;
    @SerializedName("date")
    @Expose
    private String date;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getProduct() {
        return product;
    }

    public void setProduct(String product) {
        this.product = product;
    }

    public String getQty() {
        return qty;
    }

    public void setQty(String qty) {
        this.qty = qty;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }
}

Now we can make the retrofit call as shown below
private void getMonthData() {
        Gson gson = new GsonBuilder()
                .setLenient()
                .create();
        Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create(gson))
                .baseUrl("enter_base_url")
                .build();
        RequestInterface requestInterface = retrofit.create(RequestInterface.class);
        Call<Example> call = requestInterface.getMonths();
        call.enqueue(new Callback<Example>() {
            @Override
            public void onResponse(Call<Example> call, Response<Example> response) {
                Map<String, List<MonthModel>> resultMap=response.body().getForecast().getResult();
                Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onFailure(Call<Example> call, Throwable t) {
                Toast.makeText(MainActivity.this, "Failure", Toast.LENGTH_SHORT).show();
            }
        });
    }

Create RequestInterface.java like this :
public interface RequestInterface {
    @GET("enter_url_endpoint")
    Call<Example> getMonths();
}

Now inside onResponse, you will have all the dynamic json array as Map inside resultMap

You may also check similar issue in StackOverflow



4 comments:

  1. You seem to be losing the month label (ie "April"). Am I right? Is there any way I can obtain that automatically?

    ReplyDelete
    Replies
    1. Hi, you can get the key and values like this.

      for (Entry> data : data.getResult().entrySet()) {
      Log.d("TAG", data.getKey()+":"); //this is for KEY name

      for (int i = 0; i < data.getValue().size(); i++) {
      Log.d("TAG", data.getValue().get(i)); //this is for VALUE of List
      }

      }

      Delete
    2. where you get Entry ? can u please make show complete code showing label and value , thank youu

      Delete