Before we begin, keep this in mind
begin_array means the json response is an array which will look something like this [{},{},..]
begin_object means the json response is an object which will look something like this {....}
gson is one cool library that will provide us with cool tips in the form of errors while handling json responses. One such tip is "expected begin_array but was begin_object". These tips/errors are quite self explanatory, we can now look deeper into these errors.
While handling responses using retrofit, we often tend to come across an error "expected begin_array but was begin_object", which is thrown by gson. Obviously this means that we are trying to parse the response as if it is a json array response but when actually it is a json object response. But still we come across these errors a lot of time. We will be looking in detail about such situations in this post.
First add the following dependencies in your app's build.gradle file
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
PARSING JSON OBJECT RESPONSES :
- A json object response is of the form {....}. The json object may also contain a json array like the below example where the json object contains a json array named user_array.
{ "username":"jon", "email":"jon@email.com", "user_array": [ { "user_address":"jon", "user_location":"jon@email.com" }, {..}, . . ] }
In order to parse the above json object you can either use the JsonObject from gson or create pojo classes
1. Parsing using JsonObject from gson
Retrofit retrofit = new Retrofit.Builder() .baseUrl("base_url") .addConverterFactory(GsonConverterFactory.create()) .build(); RequestInterface request = retrofit.create(RequestInterface.class); Call<JsonObject> call=request.getJson(); call.enqueue(new Callback<JsonObject>() { @Override public void onResponse(Call<JsonObject> call, Response<JsonObject> response) { progressDialog.dismiss(); String s= String.valueOf(response.get("username")); JsonArray user_array= response.getAsJsonArray("user_array"); Toast.makeText(PrintTicket.this,response.toString(),Toast.LENGTH_SHORT).show(); } @Override public void onFailure(Call<JsonObject> call, Throwable t) { progressDialog.dismiss(); Toast.makeText(PrintTicket.this,t.toString(),Toast.LENGTH_SHORT).show(); } });
RequestInterface.java
public interface RequestInterface { @GET("api_endpoint") Call<JsonObject> getJson(); }
2. Parsing using POJO class
You can automatically generate the pojo classes by pasting your json response structure in http://www.jsonschema2pojo.org/ .
FYI : after pasting the response structure in http://www.jsonschema2pojo.org/ , set the source type to JSON and Annotation style to Gson , now click preview button and you can see generated pojo class/classes
For the above case you will need to generate two classes like below
Example.java
public class Example { ("username") private String username; ("email") private String email; ("user_array") private List<UserArray> userArray = null; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public List<UserArray> getUserArray() { return userArray; } public void setUserArray(List<UserArray> userArray) { this.userArray = userArray; } }
UserArray.java
public class UserArray { ("user_address") private String userAddress; ("user_location") private String userLocation; public String getUserAddress() { return userAddress; } public void setUserAddress(String userAddress) { this.userAddress = userAddress; } public String getUserLocation() { return userLocation; } public void setUserLocation(String userLocation) { this.userLocation = userLocation; } }
In the above pojo classes, we have used @SerializedName annotation which will help us to map the class variables to respective keys in the response json. For example, in UserArray.java, the string variable userAddress is correctly mapped to user_address by using the @SerializedName annotation like this
@SerializedName("user_address") @Expose private String userAddress;
The Example.java is for parsing the outer json object whereas UserArray.java is for parsing the inner json object which should be parsed as a list(since there is a list of objects in user_array)
Now the retrofit call should be made like the following
ArrayList<RouteStop> user_array; Retrofit retrofit = new Retrofit.Builder() .baseUrl("base_url") .addConverterFactory(GsonConverterFactory.create()) .build(); RequestInterface request = retrofit.create(RequestInterface.class); Call<Example> call=request.getJson(); call.enqueue(new Callback<Example>() { @Override public void onResponse(Call<Example> call, Response<Example> response) { progressDialog.dismiss(); String user_name= response.getUsername(); user_array= new ArrayList<>(response.getUserArray()); Toast.makeText(PrintTicket.this,response.toString(),Toast.LENGTH_SHORT).show(); } @Override public void onFailure(Call<Example> call, Throwable t) { progressDialog.dismiss(); Toast.makeText(PrintTicket.this,t.toString(),Toast.LENGTH_SHORT).show(); } });
RequestInterface.java
public interface RequestInterface { @GET("api_endpoint") Call<Example> getJson(); }
Similarly we get the error "expected begin_object but was begin_array" when we are trying to make an object request were the response is of the form [{},{},..], which is a json array example. In such case we should make the call like Call<List<Example>>
Please check this tutorial to parse json array and display it in a recyclerview. Also free source code download is avalaible.
You may also check similar issues in StackOverflow
You may also check the following video that shows how to parse a json response using retrofit 2
thanks...this was very informative
ReplyDeletethanks, really glad it helped
DeleteOutstanding
ReplyDeletehi, thanks for the feedback
Deletethanks, so usefull
ReplyDeletehappy to help, thanks for the feedback
DeleteThanks! Your article was really helpful
ReplyDeletereally glad it helped, thanks for leaving the feedback
DeleteThis article really helped me understand Retrofit more clearly as well as solving the problem which I was facing.Thanks a lot, Keep the good work going.
DeleteWhat is this----- ArrayList user_array;
ReplyDeleteThe solution number one solved my problem. Thanks a lot for sharing!!!
ReplyDeleteThank you, it really helped
ReplyDeleteWhat about i want to use RecyclerView? Can You Help me?
ReplyDelete