Retrofit Expected BEGIN_OBJECT, but BEGIN_ARRAY

I am new to JSON parsing, I am using Retrofit Square library and have encountered this problem.

I am trying to parse this JSON response:

[ { "id": 3, "username": "jezer", "regid": "oiqwueoiwqueoiwqueoiwq", "url": "http:\/\/192.168.63.175:3000\/users\/3.json" }, { "id": 4, "username": "emulator", "regid": "qwoiuewqoiueoiwqueoq", "url": "http:\/\/192.168.63.175:3000\/users\/4.json" }, { "id": 7, "username": "test", "regid": "ksadqowueqiaksj", "url": "http:\/\/192.168.63.175:3000\/users\/7.json" } ] 

Here are my models:

 public class Contacts { public List<User> contacts; } 

...

 public class User { String username; String regid; @Override public String toString(){ return(username); } } 

my interface:

 public interface ContactsInterface { @GET("/users.json") void contacts(Callback<Contacts> cb); } 

my success method:

 @Override public void success(Contacts c, Response r) { List<String> names = new ArrayList<String>(); for (int i = 0; i < c.contacts.size(); i++) { String name = c.contacts.get(i).toString(); Log.d("Names", "" + name); names.add(name); } ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, names); mSentTo.setAdapter(spinnerAdapter); } 

When I use it in my success method, it throws an error

Expected BEGIN_OBJECT, but was BEGIN_ARRAY on row 1 column2

What is wrong here?

+64
java json android gson retrofit
Jun 11 '14 at 4:54 on
source share
7 answers

Now you process the response as if it were formatted as follows:

 { "contacts": [ { .. } ] } 

An exception tells you that you are expecting an object at the root, but the real data is actually an array. This means that you need to change the type as an array.

The easiest way is to simply use the list as a direct type in the callback:

 @GET("/users.json") void contacts(Callback<List<User>> cb); 
+136
Jun 11 '14 at 5:12
source share

in your interface replace

 @GET("/users.json") void contacts(Callback<Contacts> cb); 

In this code

 @GET("/users.json") void contacts(Callback<List<Contacts>> cb); 
+7
Mar 30 '17 at 19:16
source share

dependencies used :

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

Json array response can be array response or object response or even a combination of both. See the following three cases

Case 1: Parsing a json array response (OP case)

This case applies to those json responses that take the form [{...} ,{...}]

for example

 [ { "id": 3, "username": "jezer", "regid": "oiqwueoiwqueoiwqueoiwq", "url": "http:\/\/192.168.63.175:3000\/users\/3.json" }, . . ] 

First create a model class for this array or just go to jsonschema2pojo and automatically generate it as shown below

Contacts.java

 public class Contacts { @SerializedName("id") @Expose private Integer id; @SerializedName("username") @Expose private String username; @SerializedName("regid") @Expose private String regid; @SerializedName("url") @Expose private String url; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getRegid() { return regid; } public void setRegid(String regid) { this.regid = regid; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } 

ContactsInterface

In this case, you should return a list of objects as shown below

 public interface ContactsInterface { @GET("/users.json") Call<List<Contacts>> getContacts(); } 

Then make a retrofit2 call like the following

 Retrofit retrofit = new Retrofit.Builder() .baseUrl("baseurl_here") .addConverterFactory(GsonConverterFactory.create()) .build(); ContactsInterface request = retrofit.create(ContactsInterface.class); Call<List<Contacts>> call = request.getContacts(); call.enqueue(new Callback<List<Contacts>>() { @Override public void onResponse(Call<List<Contacts>> call, Response<List<Contacts>> response) { Toast.makeText(MainActivity.this,response.body().toString(),Toast.LENGTH_SHORT).show(); } @Override public void onFailure(Call<List<Contacts>> call, Throwable t) { Log.e("Error",t.getMessage()); } }); 

response.body() will give you a list of objects

YOU CAN CHECK THE FOLLOWING TWO CASE FOR LINK

Case 2: Parsing a json object response

This case applies to those json answers that have the form {..}

for example

 { "id": 3, "username": "jezer", "regid": "oiqwueoiwqueoiwqueoiwq", "url": "http:\/\/192.168.63.175:3000\/users\/3.json" } 

Here we have the same object in the example above. Thus, the model class will be the same, but, as in the above example, we do not have an array of these objects - only one separate object, and therefore, we do not need to parse it as a list.

Therefore, make the following changes to object response

 public interface ContactsInterface { @GET("/users.json") Call<Contacts> getContacts(); } 

Then make a retrofit2 call like the following

 Retrofit retrofit = new Retrofit.Builder() .baseUrl("baseurl_here") .addConverterFactory(GsonConverterFactory.create()) .build(); ContactsInterface request = retrofit.create(ContactsInterface.class); Call<Contacts> call = request.getContacts(); call.enqueue(new Callback<Contacts>() { @Override public void onResponse(Call<Contacts> call, Response<Contacts> response) { Toast.makeText(MainActivity.this,response.body().toString(),Toast.LENGTH_SHORT).show(); } @Override public void onFailure(Call<Contacts> call, Throwable t) { Log.e("Error",t.getMessage()); } }); 

response.body() will give you an object

You can also check for a typical error while parsing the response of a json object: "begin_array expected, but was begin_object"

Case 3: Parsing a json array inside json object

This case applies to those json responses that take the form {"array_name":[{...} ,{...}]}

for example

  { "contacts": [ { "id": 3, "username": "jezer", "regid": "oiqwueoiwqueoiwqueoiwq", "url": "http:\/\/192.168.63.175:3000\/users\/3.json" } ] } 

You will need two model classes, since we have two objects (one outside and one inside the array). Create it as below

ContactWrapper

 public class ContactWrapper { @SerializedName("contacts") @Expose private List<Contacts> contacts = null; public List<Contacts> getContacts() { return contacts; } public void setContacts(List<Contacts> contacts) { this.contacts = contacts; } } 

You can use the Contacts.java generated above for list objects (generated for case 1)

Therefore, make the following changes to object response

 public interface ContactsInterface { @GET("/users.json") Call<ContactWrapper> getContacts(); } 

Then make a retrofit2 call like the following

 Retrofit retrofit = new Retrofit.Builder() .baseUrl("baseurl_here") .addConverterFactory(GsonConverterFactory.create()) .build(); ContactsInterface request = retrofit.create(ContactsInterface.class); Call<ContactWrapper> call = request.getContacts(); call.enqueue(new Callback<ContactWrapper>() { @Override public void onResponse(Call<ContactWrapper> call, Response<ContactWrapper> response) { Toast.makeText(MainActivity.this,response.body().getContacts().toString(),Toast.LENGTH_SHORT).show(); } @Override public void onFailure(Call<ContactWrapper> call, Throwable t) { Log.e("Error",t.getMessage()); } }); 

Here the difference from case 1 is that we must use response.body().getContacts() instead of response.body() to get a list of objects.

Some links for the above cases:

case 1: parsing a json array response , case 2: parsing a json object response , mixed: parsing a json array inside another json object

+3
May 15 '18 at 16:34
source share

Convert it to a list.

The following is an example:

 BenchmarksListModel_v1[] benchmarksListModel = res.getBody().as(BenchmarksListModel_v1[].class); 
+1
Dec 11 '16 at 9:26
source share

Working with source code

https://drive.google.com/open?id=0BzBKpZ4nzNzUVFRnVVkzc0JabUU

 public interface ApiInterface { @GET("inbox.json") Call<List<Message>> getInbox(); } call.enqueue(new Callback<List<Message>>() { @Override public void onResponse(Call<List<Message>> call, Response<List<Message>> response) { YourpojoClass.addAll(response.body()); mAdapter.notifyDataSetChanged(); } @Override public void onFailure(Call<List<Message>> call, Throwable t) { Toast.makeText(getApplicationContext(), "Unable to fetch json: " + t.getMessage(), Toast.LENGTH_LONG).show(); } }); 
+1
Jul 24. '17 at 7:31 on
source share

Using MPV , in Deserializer, put this

 JsonObject obj = new JsonObject(); obj.add("data", json); JsonArray data = obj.getAsJsonObject().getAsJsonArray("data"); 
0
Feb 24 '18 at 17:12
source share

Here we use the Kotlin, Retrofit2, RxJava stack, and we move on to this from the usual Call methods.

The service I created generated a com.google.gson.JsonSyntaxException and java.lang.IllegalStateException with the message:

 Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column2 

But all the answers that I could find said that this was caused by the lack of an array type in the service, which I already did. My Kotlin service looked like this:

 // Data class. Retrofit2 & Gson can deserialize this. No extra code needed. data class InventoryData( val productCode: String, val stockDate: String, val availCount: Int, val totalAvailCount: Int, val inventorySold: Int, val closed: Boolean ) // BROKEN SERVICE. Throws com.google.gson.JsonSyntaxException // Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column2 interface InventoryService { @GET("getInventoryData/{storeId}") fun getInventoryData(@Path("storeId") storeId: String, @Query("startDate") startDate: String, @Query("endDate") endDate: String) : Result<Single<List<InventoryData>>> } 

The problem was with Result , which I inserted when I used an earlier Call based solution.

Removing this solved the problem. I also had to change the signature of the two error handling methods on my call site for the service:

 /// WORKING SERVICE interface InventoryService { @GET("getInventoryData/{storeId}") fun getInventoryData(@Path("storeId") storeId: String, @Query("startDate") startDate: String, @Query("endDate") endDate: String) : Single<List<InventoryData>> } 

And the code snippet of the call site that uses the service:

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel.disposables .add(viewModel.ratsService.getInventoryData(it, fromDate, toDate) .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io()) .subscribe(this::successResult, this::failureResult)) } } private fun failureResult(error: Throwable) { when (error) { is HttpException -> { if (error.code() == 401) { textField.text = "Log in required!" } } else -> textField.text = "Error: $error." } } /// Had to change to this from previous broken /// one that took 'Result<List<InventoryData>>' private fun successResult(result: List<InventoryData>) { textField.text = result.toString() } 

Please note that the above code has been slightly modified. In particular, I used Retrofit2 ConverterFactory so that dates can be passed as OffsetDateTime objects instead of strings.

0
May 10 '19 at 5:39
source share



All Articles