Showing posts with label retrofit. Show all posts
Showing posts with label retrofit. Show all posts

Using custom gson converter to parse dynamic json with free source code

We often come across issue where a json dynamically switches its type based on the response. For example, in normal cases suppose that you have a list of cars returned as an array from your backend, but when the number of cars in the list is one, you are given just an abject instead of array. In such cases, your code should be ready to handle the response no matter whether it is an array or an object.


To handle such cases, Gson provides plenty of customisation options. One such option is registerTypeAdapter. So lets dive deeper to check how its done.

In this tutorial we will be using retrofit to make the network calls and of course gson-converter, so go to your app level build.gradle and add the following as dependencies

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

please add the latest dependency versions for retrofit, converter-gson


Now check the following json strcutures that we will be parsing

cars_object_json.json
{
"cars" : {
   "car_type" : "Hatchback", 
   "car_models" : {"car_name":"Swift" , "power_window":"yes" }
  }
}

cars_array_json.json
{
"cars" : {
   "car_type" : "Sedan" , 
   "car_models" : [ 
      { 
         "car_name" : "Xcent",
         "power_window" : "no"
      },
      {
         "car_name" : "Ciaz",
         "power_window" : "yes"
      } 
  ]}
}


In cars_object_json.json you can see that car_models is an object because there is only one item inside it whereas in cars_array_json.json  car_models is an array since there are more than one items in it. We have to write a parser which could automatically identify the response format and parse both the cases easily. registerTypeAdapter is exactly what we want here.

Alright, lets see some code now

First of all, there are two type of object models or POJOs that we need to create for the above json >> Cars,CarModels

1) Automatic model class/pojo class generation using http://www.jsonschema2pojo.org/
Specify Target language as Java, Source Type as JSON and annotation style as Gson
  • Now click preview and copy the generated java files
Now copy the contents of the class and add it in android studio project

Now copy the classes Cars,CarModels from http://www.jsonschema2pojo.org/ and add it to your project like this

Cars.java

public class Cars {
    @SerializedName("car_type")
    @Expose
    private String carType;
    @SerializedName("car_models")
    @Expose
    private List<CarModel> cardModels = null;

    public String getCarType() {
        return carType;
    }

    public void setCarType(String carType) {
        this.carType = carType;
    }

    public List<CarModel> getCardModels() {
        return cardModels;
    }

    public void setCardModels(List<CarModel> cardModels) {
        this.cardModels = cardModels;
    }

}


CarModels.java

public class CarModel {
    @SerializedName("car_name")
    @Expose
    private String carName;
    @SerializedName("power_window")
    @Expose
    private String powerWindow;

    public String getCarName() {
        return carName;
    }

    public void setCarName(String carName) {
        this.carName = carName;
    }

    public String getPowerWindow() {
        return powerWindow;
    }

    public void setPowerWindow(String powerWindow) {
        this.powerWindow = powerWindow;
    }
}


Now, create a deserializer like shown below

GsonBuilder b = new GsonBuilder();
        b.registerTypeAdapter(Cars.class, new JsonDeserializer<Cars>() {
            @Override
            public Cars deserialize(JsonElement arg0, Type arg1,
                                     JsonDeserializationContext arg2) throws JsonParseException {
                JsonObject CarsObj = arg0.getAsJsonObject();
                JsonObject innerObj=CarsObj.getAsJsonObject("cars");

                Gson g = new Gson();
                Cars a = g.fromJson(arg0, Cars.class);
                List<CarModel> carModels = null;

                if (innerObj.get("car_models").isJsonArray()) {
                    carModels = g.fromJson(innerObj.get("car_models"),
                            new TypeToken<List<CarModel>>() {
                            }.getType());
                } else {
                    CarModel single = g.fromJson(innerObj.get("car_models"), CarModel.class);
                    carModels = new ArrayList<CarModel>();
                    carModels.add(single);
                }
                a.setCardModels(carModels);
                return a;
            }
        });

In the above deserializer, you can clearly see that we have checked whether car_models is an array or an object and then parsed the response accordingly.

Now go ahead and attach the converter to your retrofit implementation so that the entire code for your MainActivity.java will look like this

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        parseJson();
    }

    private void parseJson() {

        GsonBuilder b = new GsonBuilder();
        b.registerTypeAdapter(Cars.class, new JsonDeserializer<Cars>() {
            @Override
            public Cars deserialize(JsonElement arg0, Type arg1,
                                     JsonDeserializationContext arg2) throws JsonParseException {
                JsonObject CarsObj = arg0.getAsJsonObject();
                JsonObject innerObj=CarsObj.getAsJsonObject("cars");

                Gson g = new Gson();
                Cars a = g.fromJson(arg0, Cars.class);
                List<CarModel> carModels = null;

                if (innerObj.get("car_models").isJsonArray()) {
                    carModels = g.fromJson(innerObj.get("car_models"),
                            new TypeToken<List<CarModel>>() {
                            }.getType());
                } else {
                    CarModel single = g.fromJson(innerObj.get("car_models"), CarModel.class);
                    carModels = new ArrayList<CarModel>();
                    carModels.add(single);
                }
                a.setCardModels(carModels);
                return a;
            }
        });
        
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://navneet7k.github.io/")
                .addConverterFactory(GsonConverterFactory.create(b.create()))
                .build();
        

        RequestInterface request = retrofit.create(RequestInterface.class);
        Call<Cars> call1=request.getJson();
        call1.enqueue(new Callback<Cars>() {
            @Override
            public void onResponse(Call<Cars> call, Response<Cars> response) {
                Toast.makeText(MainActivity.this,"Success!",Toast.LENGTH_SHORT).show();
            }

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

        });
    }

}

And your RequestInterface.java for cars_object_json.json  will be like this

interface RequestInterface {
    @GET("cars_object_json.json")
    Call<Cars> getJson();
}

RequestInterface.java for cars_array_json.json  will be like this


interface RequestInterface {
    @GET("cars_array_json.json")
    Call<Cars> getJson();
}

By this method you will get the correct response for Response<Cars> response in the retrofit callbacks even if your response changes dynamically.

Loading images using picasso library in android

In this tutorial we are about to load image in recyclerview using picasso library as shown in the following gif
images loaded in recyclerview using picasso library

In this tutorial we will be parsing the following json array example into a recyclerview along with the images
You can check the json file here https://navneet7k.github.io/cars_list.json
Update internet permission in AndroidManifest.xml as shown below
Add the dependencies for cardview,design,retrofit,converter-gson and picasso in your app level build.gradle as shown below
Please make sure that you add the dependencies in app level build.gradle itself and not project level build.gradle like depicted below

build.gradle files


Create model class like shown below

CarItem.java
Create recyclerview adapter

DataAdapter.java
Here we have used

 Picasso.get().load(articles.get(i).getImage()).resize(500,500).into(viewHolder.car_img); 

to load the image into car_img using Picasso library. Also I have implemented a filter method in the above adapter class which you can use to integrate a search feature in the above recyclerview - you may check this tutorial to integrate search feature inside recyclerview.

create activity file

MainActivity.java
Since we have to parse a json array example, we have used List<CarItem> as response parameter type in retrofit callback methods as shown above. If we were parsing a json object example, we would have to set CarItem as response parameter type.

RequestInterface.java
Now create the resource files

activity_main.xml
item_layout.xml
colors.xml
strings.xml

Download file from url in android using retrofit

Downloading files from a url is a common use case these days for a countless number of apps. The files to be downloaded can be of smaller size or bigger size depending on the app requirements. We will be checking how to download a bigger sized file in this tutorial.

We will be using retrofit 2 as our network client in this tutorial.

So first of all, go ahead and add the following dependencies in your newly created android studio project. Be sure that you add the dependencies in your app level build.gradle file and not the project level build.gradle file :

implementation 'com.squareup.retrofit2:retrofit:2.3.0' 
implementation 'com.squareup.okhttp3:okhttp:3.10.0'

Parse a json array inside another json object in android with free source code download




We will be using retrofit,gson for parsing, so go to your app level build.gradle and add the following as dependencies

implementation 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
please add the latest dependency versions for retrofit, converter-gson

Hi, in this tutorial, we will parse the below json. Check this json here >> https://navneet7k.github.io/sample_object_array.json

Here you can see that the cars_array is wrapped inside another json object, so we will need two model/pojo classes


1) Automatic model class/pojo class generation using http://www.jsonschema2pojo.org/


You can make use of jsonschema2pojo to covert json to java object online. This is a really effective tool which even supports various annotation types like jackson, gson, moshi etc.
Specify Target language as Java, Source Type as JSON and annotation style as Gson
  • Now click preview and copy the generated java files
Now copy the contents of the class and add it in android studio project

Now rename the generated classes like shown below and add it inside your android studio project

SampleResponse.java

public class SampleResponse {
    @SerializedName("id")
    @Expose
    private String id;
    @SerializedName("type")
    @Expose
    private String type;
    @SerializedName("cars_array")
    @Expose
    private List<CarsArray> carsArray = null;

    public String getId() {
        return id;
    }

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

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public List<CarsArray> getCarsArray() {
        return carsArray;
    }

    public void setCarsArray(List<CarsArray> carsArray) {
        this.carsArray = carsArray;
    }

}


CarsArray.java

public class CarsArray {
    @SerializedName("id")
    @Expose
    private String id;
    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("desc")
    @Expose
    private String desc;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}


MainActivity.java

private void parseJson() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://navneet7k.github.io/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        RequestInterface request = retrofit.create(RequestInterface.class);
        Call<SampleResponse> call1=request.getJson();
        call1.enqueue(new Callback<SampleResponse>() {
            @Override
            public void onResponse(Call<SampleResponse> call, Response<SampleResponse> response) {
                Toast.makeText(MainActivity.this,"Success! response for first item >> \n car :" +response.body().getCarsArray().get(0).getName()+"\ndesc :"+response.body().getCarsArray().get(0).getDesc(),Toast.LENGTH_SHORT).show();
            }

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

        });
    }

RequestInterface.java

interface RequestInterface {
    @GET("sample_object_array.json")
    Call<SampleResponse> getJson();
}


Download free source code

Parse json object in android with free source code download




We will be using retrofit,gson for parsing, so go to your app level build.gradle and add the following as dependencies

implementation 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
please add the latest dependency versions for retrofit, converter-gson

Hi, we will be parsing the below json in this tutorial. Check this json here >> https://navneet7k.github.io/sample_object.json

Clearly, the json is of the form {..} and we can parse it as an object from android
Now inorder to generate model class/pojo class for above json, you may either create it automatically using http://www.jsonschema2pojo.org/ or generate it manually

1) Automatic model class/pojo class generation using http://www.jsonschema2pojo.org/

You can make use of jsonschema2pojo to covert json to java object online. This is a really effective tool which even supports various annotation types like jackson, gson, moshi etc.
Specify Target language as Java, Source Type as JSON and annotation style as Gson
  • Now click preview and copy the generated java files
Now copy the contents of the class and add it in android studio project

Now copy the above generated contents into SampleJson.java as shown below

SampleJson.java

public class SampleJson {
    @SerializedName("title")
    @Expose
    private String title;
    @SerializedName("description")
    @Expose
    private String description;
    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("id")
    @Expose
    private String id;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }

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


MainActivity.java

private void parseJson() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://navneet7k.github.io/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        RequestInterface request = retrofit.create(RequestInterface.class);
        Call<SampleJson> call1=request.getJson();
        call1.enqueue(new Callback<SampleJson>() {
            @Override
            public void onResponse(Call<SampleJson> call, Response<SampleJson> response) {
                Toast.makeText(MainActivity.this,"Success!",Toast.LENGTH_SHORT).show();
            }

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

        });
    }

RequestInterface.java

interface RequestInterface {
    @GET("sample_object.json")
    Call<SampleJson> getJson();
}


Download free source code

Parse json array in android with free source code download



We will be using retrofit,gson for parsing, so go to your app level build.gradle and add the following as dependencies

implementation 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
please add the latest dependency versions for retrofit, converter-gson

Hi, in this tutorial we are about to parse the below json array. Check this json array >> https://navneet7k.github.io/sample_array.json

Clearly, the json is of the form [{},{}..] . It is a json array, hence we can parse it as a list from android
Now inorder to generate model class/pojo class for above json, you may either create it automatically using http://www.jsonschema2pojo.org/ or generate it manually

1) Automatic model class/pojo class generation using http://www.jsonschema2pojo.org/
Specify Target language as Java, Source Type as JSON and annotation style as Gson
  • Now click preview and copy the generated java files
Now copy the contents of the class and add it in android studio project
Now in the android studio project, create a new java file Cars.java and add the above generated code inside it like shown below

Cars.java

public class Cars {
    @SerializedName("id")
    @Expose
    private String id;
    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("desc")
    @Expose
    private String desc;

    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}


Since the json is an array, we can parse it as a list like this <List<Cars>> from android. So add the below code in your MainActivity.java file

MainActivity.java

private void parseJson() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://navneet7k.github.io/")
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        RequestInterface request = retrofit.create(RequestInterface.class);
        Call<List<Cars>> call1=request.getJson();
        call1.enqueue(new Callback<List<Cars>>() {
            @Override
            public void onResponse(Call<List<Cars>> call, Response<List<Cars>> response) {
                Toast.makeText(MainActivity.this,"Success!",Toast.LENGTH_SHORT).show();
            }

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

        });
    }

RequestInterface.java

interface RequestInterface {
    @GET("sample_array.json")
    Call<List<Cars>> getJson();
}


Download free source code

You may also check this tutorial to parse a json array into recyclerview


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