Retrofit Expected BEGIN_OBJECT but was BEGIN_ARRAY
I’m fairly new to JSON parsing, I’m using the Retrofit library of Square and ran into this problem. I’m trying to parse this JSON reponse:
public class Contacts < public Listcontacts; >
public interface ContactsInterface < @GET("/users.json") void contacts(Callbackcb); >
@Override public void success(Contacts c, Response r) < Listnames = new ArrayList(); for (int i = 0; i < c.contacts.size(); i++) < String name = c.contacts.get(i).toString(); Log.d("Names", "" + name); names.add(name); >ArrayAdapter spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item, names); mSentTo.setAdapter(spinnerAdapter); >
7 Answers 7
Right now you are parsing the response as if it was formatted like this:
The exception tells you this in that you are expecting an object at the root but the real data is actually an array. This means you need to change the type to be an array.
The easiest way is to just use a list as the direct type in the callback:
@GET("/users.json") void contacts(Callback> cb);
dependencies used :
compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0'
json responses can be an array response or an object response or even a combination of both. See the following three cases
Case 1 : Parsing a json array response (OP’s case)
This case applies to those json responses which are of the form [ <. >,<. >]
First create a model class for this array or just goto jsonschema2pojo and auto generate one like 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 like the following
public interface ContactsInterface < @GET("/users.json") Call> getContacts(); >
Then make the retrofit2 call like the following
Retrofit retrofit = new Retrofit.Builder() .baseUrl("baseurl_here") .addConverterFactory(GsonConverterFactory.create()) .build(); ContactsInterface request = retrofit.create(ContactsInterface.class); Call> call = request.getContacts(); call.enqueue(new Callback>() < @Override public void onResponse(Call> call, Response> response) < Toast.makeText(MainActivity.this,response.body().toString(),Toast.LENGTH_SHORT).show(); >@Override public void onFailure(Call> call, Throwable t) < Log.e("Error",t.getMessage()); >>);
response.body() will give you the list of objects
YOU MAY ALSO CHECK THE FOLLOWING TWO CASES FOR REFERENCE
Case 2 : Parsing a json object response
This case applies to those json responses which are of the form
Here, we have the same object as above example. So the model class will be the same, but like above example we dont have an array of these objects — just one single object and hence we dont need to parse it as a list.
So make the following changes for an object response
public interface ContactsInterface < @GET("/users.json") CallgetContacts(); >
Then make the retrofit2 call like the following
Retrofit retrofit = new Retrofit.Builder() .baseUrl("baseurl_here") .addConverterFactory(GsonConverterFactory.create()) .build(); ContactsInterface request = retrofit.create(ContactsInterface.class); Call call = request.getContacts(); call.enqueue(new Callback() < @Override public void onResponse(Callcall, Response response) < Toast.makeText(MainActivity.this,response.body().toString(),Toast.LENGTH_SHORT).show(); >@Override public void onFailure(Call call, Throwable t) < Log.e("Error",t.getMessage()); >>);
response.body() will give you the object
You may also check a common error while parsing json object response :«expected begin_array but was begin_object»
Case 3 : Parsing a json array inside json object
This case applies to those json responses which are of the form <"array_name":[<. >,<. >]>
You will need two model classes here since we have two objects(one outside and one inside the array).Generate it like below
ContactWrapper
public class ContactWrapper < @SerializedName("contacts") @Expose private Listcontacts = null; public List getContacts() < return contacts; >public void setContacts(List contacts) < this.contacts = contacts; >>
You can use Contacts.java generated above for the list objects(generated for case 1)
So make the following changes for an object response
public interface ContactsInterface < @GET("/users.json") CallgetContacts(); >
Then make the retrofit2 call like the following
Retrofit retrofit = new Retrofit.Builder() .baseUrl("baseurl_here") .addConverterFactory(GsonConverterFactory.create()) .build(); ContactsInterface request = retrofit.create(ContactsInterface.class); Call call = request.getContacts(); call.enqueue(new Callback() < @Override public void onResponse(Callcall, Response response) < Toast.makeText(MainActivity.this,response.body().getContacts().toString(),Toast.LENGTH_SHORT).show(); >@Override public void onFailure(Call call, Throwable t) < Log.e("Error",t.getMessage()); >>);
Here, the difference from case 1 is that we should use response.body().getContacts() instead of response.body() to get the list of objects
Some references for above cases :
hai i am trying to request getting data in 3rd format but i am continuously getting the same error can you please help me
please provide more info about your code, also make sure your array name spelling in the model class matches exactly with that of response
in your interface replace
@GET("/users.json") void contacts(Callback cb);
@GET("/users.json") void contacts(Callback> cb);
It’s true, I had the same error and before modifying the pojo I decided to create an arrayList and get the same result
BenchmarksListModel_v1[] benchmarksListModel = res.getBody().as(BenchmarksListModel_v1[].class);
Source Code Working
public interface ApiInterface < @GET("inbox.json") Call> getInbox(); > call.enqueue(new Callback>() < @Override public void onResponse(Call> call, Response> response) < YourpojoClass.addAll(response.body()); mAdapter.notifyDataSetChanged(); >@Override public void onFailure(Call> call, Throwable t) < Toast.makeText(getApplicationContext(), "Unable to fetch json: " + t.getMessage(), Toast.LENGTH_LONG).show(); >>);
Using MPV, in your Deserializer, put this
JsonObject obj = new JsonObject(); obj.add("data", json); JsonArray data = obj.getAsJsonObject().getAsJsonArray("data");
If the server response has a JSON format like this , then retrofit can’t iterate correctly, a prefix must be placed on the JSON, as Jake Wharton suggests. the final JSON would be like this and problem solved.[..]>
The stack here is Kotlin, Retrofit2, RxJava and we’re migrating to that off regular Call methods.
The service that I had created was throwing com.google.gson.JsonSyntaxException and java.lang.IllegalStateException with message:
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column2
But all the answers I could find said that this was caused by not having 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/") fun getInventoryData(@Path("storeId") storeId: String, @Query("startDate") startDate: String, @Query("endDate") endDate: String) : Result>> >
The problem was the Result in there, which I had put in when I was using an earlier Call based solution.
Removing it fixed the problem. I also had to change the signature of the two error handling methods at my call-site for the service:
/// WORKING SERVICE interface InventoryService < @GET("getInventoryData/") fun getInventoryData(@Path("storeId") storeId: String, @Query("startDate") startDate: String, @Query("endDate") endDate: String) : Single> >
And the call-site fragment code 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>` private fun successResult(result: List)
Note that the above code has been changed a little. In particular I used a Retrofit2 ConverterFactory to allow the dates to be passed in as OffsetDateTime objects instead of strings.
Expected BEGIN_ARRAY but was BEGIN_OBJECT
I am a beginner and I am using Retrofit 2 in my app. I have this JSON. (I have tried many solution but nothing worked for me). Thank for your help Error which I have: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 JSON
public interface PointsInterface < String BASE_URL = "MY_URL/"; @POST("getPointsOnMap") Call> getPointsOnMap(); class Factory < private static PointsInterface service; public static PointsInterface getInstance() < if (service == null) < Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create()).baseUrl(BASE_URL).build(); service = retrofit.create(PointsInterface.class); return service; >else < return service; >> > >
public void serviceInit() < PointsInterface.Factory.getInstance().getPointsOnMap().enqueue(new Callback>() < @Override public void onResponse(Call> call, Response> response) < Listresult = response.body(); Log.d("response", "Number of points received: " + result.size()); > @Override public void onFailure(Call> call, Throwable t) < Log.e("error", "Error"); >>);>
public class PointsOnMap < @SerializedName("lat") private Double lat; @SerializedName("lng") private Double lng; @SerializedName("title") private String title; @SerializedName("desc") private String desc; public PointsOnMap(Double lat, Double lng, String title, String desc) < this.lat = lat; this.lng = lng; this.title = title; this.desc = desc; >public Double getLat() < return lat; >public void setLat(Double lat) < this.lat = lat; >public Double getLng() < return lng; >public void setLng(Double lng) < this.lng = lng; >public String getTitle() < return title; >public void setTitle(String title) < this.title = title; >public String getDesc() < return desc; >public void setDesc(String desc) < this.desc = desc; >>
GSON Expected BEGIN_ARRAY but was BEGIN_OBJECT?
I just start to learn about gson. I see lot of topic about this error, but i don’t find any help or answer corresponding of my problem. I’m trying to parse a JSON string like this one:
< "CodeAnalytique": "XXXX", "Domaine": "XXXX", "HabilitationAD": [ < "Key": "XXXX", "Value": [ < "Applicatif": "XXXX", "Cle": "E", "Role": "Red", "Valeur": "XXXX" >, < "Applicatif": "XXXX", "Cle": "E", "Role": "Red", "Valeur": "XXXX" >//lot of other value ] > ], "HabilitationInterprete": [ < "Key": "XX", "Value": [ < "Applicatif": "XXXX", "Cle": "Z", "Role": "Red", "Valeur": "XXX" >, < "Applicatif": "XXXX", "Cle": "Z", "Role": "Red", "Valeur": "XXXX" >//lot of other value ] > ], "Identity": "XXXX", "InfoConsolidee": "Operation requested at XXXX", "IsAdminI": true, "IsAdminM": false, "IsAuthentif": true, "Matricule": "XXX", "Nom": "XXXX", "PasswordEnvoye": "XXXX", "Prenom": "XXX", "PrincipalPermissionMode": 1, "RoleSGBD": [ "xxxx" ], "RoleSI": [ null, "APP_02", "APP_03", //lot of other value ], "Societe": "XXX", "TypeClient": null >
InfoSecuriteBean mInfoSecuriteBean = gson.fromJson(reader, InfoSecuriteBean.class);
import com.google.gson.annotations.SerializedName; import java.util.HashMap; import java.util.List; import java.util.Map; public class InfoSecuriteBean < @SerializedName("IsAuthentif") private boolean mIsAuthentif = false; @SerializedName("PrincipalPermissionMode") private enumPrincipalPermissionMode mPrincipalPermissionMode; @SerializedName("RoleSGBD") private ListmRoleSGBD; @SerializedName("RoleSI") private List mRoleSI; @SerializedName("Identity") private String mIdentity = null; @SerializedName("Password") private String mPassword = null; @SerializedName("InfoConsolidee") private String mInfoConsolidee = null; @SerializedName("IsAdminM") private boolean mIsAdminM = false; @SerializedName("IsAdminI") private boolean mIsAdminI = false; @SerializedName("Matricule") private String mMatricule = null; @SerializedName("Nom") private String mNom = null; @SerializedName("Prenom") private String mPrenom = null; @SerializedName("CodeAnalytique") private String mCodeAnalytique = null; @SerializedName("Domaine") private String mDomaine = null; @SerializedName("Societe") private String mSociete = null; @SerializedName("TypeClient") private String mTypeClient = null; @SerializedName("HabilitationAD") private Map> mHabilitationAD = new HashMap>(); @SerializedName("HabilitationInterprete") private Map> mHabilitationInterprete = new HashMap>(); //Getter and setter
import com.google.gson.annotations.SerializedName; public class HabilitationBean < @SerializedName("Applicatif") private String mApplicatif = null; @SerializedName("Role") private String mRole = null; @SerializedName("Cle") private String mCle = null; @SerializedName("Valeur") private String mValeur = null; //getter and setter
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECTat line 1 column 60
Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 60 path $.HabilitationAD[0] at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:200) at com.google.gson.Gson.fromJson(Gson.java:810) at com.google.gson.Gson.fromJson(Gson.java:748) at com.sig.webservice.WebSecurityGBD.doInBackground(WebSecurityGBD.java:69) at com.sig.webservice.WebSecurityGBD.doInBackground(WebSecurityGBD.java:23) at android.os.AsyncTask$2.call(AsyncTask.java:292) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:818) Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 60 path $.HabilitationAD[0] at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:172) at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:103) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:196) at com.google.gson.Gson.fromJson(Gson.java:810) at com.google.gson.Gson.fromJson(Gson.java:748) at com.sig.webservice.WebSecurityGBD.doInBackground(WebSecurityGBD.java:69) at com.sig.webservice.WebSecurityGBD.doInBackground(WebSecurityGBD.java:23) at android.os.AsyncTask$2.call(AsyncTask.java:292) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:818)
@SerializedName("HabilitationAD") private Map> mHabilitationAD = new HashMap>(); @SerializedName("HabilitationInterprete") private Map> mHabilitationInterprete = new HashMap>();
if i comment this properties i don't have any probleme to build my json objet. I found this link Deserializing a Map field with Gson Currently i try something like this
public class InfoSecuriteBeanDeserializer implements JsonDeserializer < @Override public InfoSecuriteBean deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException < JsonArray jArray = (JsonArray) json; InfoSecuriteBean mInfoSecuriteBean = new InfoSecuriteBean(); for (int i=1; ireturn mInfoSecuriteBean; > >
Expected BEGIN_ARRAY but was BEGIN_OBJECT when using GSON
Ok, I know that many of questions like that have been asked, but I have a specific question, which none of the others has. I want to know how I'd go on to parse following JSON file with GSON.
< "BUYER": < "IGN": "MGlolenstine", "ProductID": "51" >, "BUYER": < "IGN": "MGlolenstine", "ProductID": "55" >, "BUYER": < "IGN": "MGlolenstine", "ProductID": "0" >, "BUYER": < "IGN": "MGlolenstine", "ProductID": "51" >, "BUYER": < "IGN": "MGlolenstine", "ProductID": "56" >>
Scanner scanner = new Scanner( new File(path) ); String text = scanner.useDelimiter("\\A").next(); Gson gson = new GsonBuilder().create(); ArrayList p = gson.fromJson(new FileReader(path), Purchases.class); for(int i = 0; i < p.size(); i++)< arg0.sendMessage(ChatColor.GOLD+"Player: "+p.get(i).BUYER.IGN); arg0.sendMessage(ChatColor.GOLD+"ProductID: "+String.valueOf(p.get(i).BUYER.ProductID)); >scanner.close();
Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 2 column 12
public class Purchases < PlayerRank BUYER; >public class PlayerRank
The problem is probably me not knowing how the JSON arrays and objects look like. Could someone please explain the difference between JSONArray and JSONObject in my JSON code? Thank you in advance. EDIT: So this is the fixed JSON
Scanner scanner = new Scanner( new File(path) ); String text = scanner.useDelimiter("\\A").next(); Gson gson = new GsonBuilder().create(); Purchases p = gson.fromJson(new FileReader(path), Purchases.class); for(int i = 0; i
public class Purchases < PlayerRank buyers[]; >public class PlayerRank