This error drove me crazy I tried using different kind of Volley requests such as JsonArrayRequest
and JsonObjectRequest
but no luck !!
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
Here's the JSON response link => http://www.mocky.io/v2/58df83a80f00005922eaf4e1
Here's my model class
public class Order {
@SerializedName("status")
@Expose
private String status; //status
@SerializedName("total")
@Expose
private float price; //total
@SerializedName("created_at")
@Expose
private Date time;
@SerializedName("line_items")
@Expose
public List<ItemsNum> lineItems = new ArrayList<ItemsNum>();
@SerializedName("sub_orders")
@Expose
public List<OrdersNum> subOrders = new ArrayList<OrdersNum>();
@SerializedName("shipping_address")
@Expose
public CusAddress cusAdress;
@SerializedName("customer")
@Expose
public Customer customer;
public Order(Customer customer, String status, float price, String cusPicURL, String firstName, String lastName, Date time, List<ItemsNum> lineItems, List<OrdersNum> subOrders, CusAddress cusAdress) {
this.status = status;
this.price = price;
this.customer = customer;
this.time = time;
this.lineItems = lineItems;
this.subOrders = subOrders;
this.cusAdress = cusAdress;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public List<ItemsNum> getLineItems() {
return lineItems;
}
public void setLineItems(List<ItemsNum> lineItems) {
this.lineItems = lineItems;
}
public List<OrdersNum> getSubOrders() {
return subOrders;
}
public void setSubOrders(List<OrdersNum> subOrders) {
this.subOrders = subOrders;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public CusAddress getCusAdress() {
return cusAdress;
}
public void setCusAdress(CusAddress cusAdress) {
this.cusAdress = cusAdress;
}
// //////////// Inner-Classes
public class Customer {
@SerializedName("avatar_url")
@Expose
private String cusPicURL; //avatar_url
@SerializedName("first_name")
@Expose
private String firstName; //first_name
@SerializedName("last_name")
@Expose
private String lastName; //last_name
public String getCusPicURL() {
return cusPicURL;
}
public void setCusPicURL(String cusPicURL) {
this.cusPicURL = cusPicURL;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
public class CusAddress {
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
@SerializedName("address_1")
@Expose
public String address;
@SerializedName("city")
@Expose
public String city;
@SerializedName("state")
@Expose
public String state;
@SerializedName("country")
@Expose
public String country;
}
public class ItemsNum {
@SerializedName("id")
@Expose
public Integer id;
}
public class OrdersNum {
@SerializedName("id")
@Expose
public Integer id;
}
}
My Adapter
public class OrdersDataAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public Context context;
private int num;
ArrayList<Order> orders;
public OrdersDataAdapter(ArrayList<Order> orders, Context context) {
this.orders = orders;
this.context = context;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.order_card, parent, false);
return new NewOrderVH(v);
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
final Order order = this.orders.get(position);
final NewOrderVH vh1 = (NewOrderVH) holder;
vh1.setData(orders.get(position));
}
@Override
public int getItemCount() {
return orders.size();
}
public class NewOrderVH extends RecyclerView.ViewHolder {
private ImageView cusPic;
private TextView cusName;
private TextView CusAdress;
private TextView vendorsNum;
private TextView itemsNum;
private TextView time;
public NewOrderVH(View itemView) {
super(itemView);
orderCard = (CardView) itemView.findViewById(R.id.OrderCard);
cusPic = (ImageView) itemView.findViewById(R.id.cusPic);
cusName = (TextView) itemView.findViewById(R.id.cusName);
CusAdress = (TextView) itemView.findViewById(R.id.CusAdress);
vendorsNum = (TextView) itemView.findViewById(R.id.vendorsNum);
itemsNum = (TextView) itemView.findViewById(R.id.itemsNum);
time = (TextView) itemView.findViewById(R.id.time);
}
public void setData(final Order data) {
cusName.setText(data.customer.getFirstName() + "" + data.customer.getLastName());
Picasso.with(context).load(data.customer.getCusPicURL()).into(cusPic);
time.setText(data.getTime().getMinutes());
vendorsNum.setText(data.getSubOrders().size());
itemsNum.setText(data.getLineItems().size());
CusAdress.setText(data.cusAdress.getAddress() + "" + data.cusAdress.getCity() + "" + data.cusAdress.getCountry() + "" + data.cusAdress.getState());
}
}
}
Request Method inside a Fragment
private void fetchPosts() {
requestQueue = Volley.newRequestQueue(getActivity());
StringRequest jRequest = new StringRequest(Request.Method.GET, ENDPOINT, onPostsLoaded, onPostsError);
requestQueue.add(jRequest);
}
private final Response.Listener<String> onPostsLoaded = new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Gson gson = new Gson();
Type listType = new TypeToken<List<Order>>() {}.getType();
modelData = gson.fromJson(response, listType);
adapter = new OrdersDataAdapter((ArrayList<Order>) modelData, getActivity());
recyclerView.setAdapter(adapter);
adapter.setMode(Attributes.Mode.Single);
}
};
private final Response.ErrorListener onPostsError = new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.e("PostActivity", error.toString());
}
};
Here your problem is the orders
object. You don't deserialize orders
. You can solve this issue
public class OrderHolder{
private List<Order> orders;
public List<Order> getOrders(){ return orders; }
}
OrderHolder holder = new Gson().fromJson(response, OrderHolder.class);
modelData = holder.getOrders();
or
JsonElement jelement = new JsonParser().parse(response);
JsonObject jobject = jelement.getAsJsonObject();
String ordersString = jobject.get("orders").getAsString();
Gson gson = new Gson();
Type listType = new TypeToken<List<Order>>() {}.getType();
modelData = gson.fromJson(ordersString, listType);
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
This is easy to read: it means that you're parsing something like a list (so that BEGIN_ARRAY
[
is expected), but the given JSON document starts with BEGIN_OBJECT
{
, that is caused by mismatched expected type. And it happens at the very beginning of the JSON document.
Apart from the mismanc 's answer , there is also a third-way, that requires a slightly more code (can be extracted to a method though), but it does not require both wrappers or intermediate JSON trees like JsonElement
and its subclasses (that may consume slightly more memory for the 1st case, and definitely more memory for the second case because the whole intermediate JSON tree must be stored in memory).
// JsonReader allows to read JSON token stream
try ( final JsonReader jsonReader = new JsonReader(new StringReader(JSON)) ) {
// Just skip the leading `{`
jsonReader.beginObject();
// Check if the next property name is what we're expecting
final String name = jsonReader.nextName();
if ( !name.equals("orders") ) {
throw new MalformedJsonException("Unexpected: " + name);
}
// If it's fine, then we:
// * are assuming the JsonReader "pointer" is at the property value now
// * are asking Gson for the proper type adapter
@SuppressWarnings("unchecked")
final TypeAdapter<List<Order>> typeAdapter = (TypeAdapter<List<Order>>) gson.getAdapter(TypeToken.get(orderListType));
// Just read the orders
final List<Order> orders = typeAdapter.read(jsonReader);
System.out.println(orders);
}
JSON schema to POJO automatic converters/generators do not always create optimal mappings. For example:
ItemsNum
and OrdersNum
are represented by the same POJO structure, however it can be final class Id { @SerializedName("id") final Integer id = null; }
final class Id { @SerializedName("id") final Integer id = null; }
. avatar_url
is represented as java.lang.String
, but it can be java.net.URL
too. Minor notes:
Gson
class instances not required to be created every time you need deserialization. They are fully thread-safe and can be instantiated once and then re-used easily. Also, created and configured else Gson
instance can be just injected to your code. Type
instances produced with TypeToken
s can be considered immutable value objects therefore to be cached into a static final
field too. here's the correct answer, I was using wrong type of request..!
JsonObjectRequest jsObjRequest = new
JsonObjectRequest(Request.Method.GET,ENDPOINT,null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
Gson gson = new Gson();
Type listType = new TypeToken<List<Order>>() {}.getType();
try {
List<Order> o = new ArrayList<>();
o = gson.fromJson(response.getJSONArray("orders").toString(), listType);
if(o != null && !o.isEmpty()){
modelData.addAll(o);
adapter.notifyDataSetChanged();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
}
});
requestQueue.add(jsObjRequest);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.