I'm working on an inventory app in Kotlin for work and I became stumped when trying to populate a list view in one of my activities. For some reason, it's throwing the following error:
W/System.err: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
With the OkHttpClient, I can see my Json result:
{
"result":
[
{
"stockOutID":"22",
"skuUsageForStockOutID":"37",
"masterStockListID":"4",
"partNumber":"51220",
"altPartNumber":"Z-234",
"quantity":"2.0",
"price":"6.00","total":"12.00",
"skuType":"INVENTORY-ITEM"
}
],
"targetUrl":null,
"success":true,
"error":null,
"unAuthorizedRequest":false,
"__abp":true
}
From that, I used JsonScheme2Pojo and got the following result which I placed in a file named "StockOutItemsResponse.java":
public class Result {
@SerializedName("stockOutID")
@Expose
private String stockOutID;
@SerializedName("skuUsageForStockOutID")
@Expose
private String skuUsageForStockOutID;
@SerializedName("masterStockListID")
@Expose
private String masterStockListID;
@SerializedName("partNumber")
@Expose
private String partNumber;
@SerializedName("altPartNumber")
@Expose
private String altPartNumber;
@SerializedName("quantity")
@Expose
private String quantity;
@SerializedName("price")
@Expose
private String price;
@SerializedName("total")
@Expose
private String total;
@SerializedName("skuType")
@Expose
private String skuType;
public String getStockOutID() {
return stockOutID;
}
public void setStockOutID(String stockOutID) {
this.stockOutID = stockOutID;
}
public String getSkuUsageForStockOutID() {
return skuUsageForStockOutID;
}
public void setSkuUsageForStockOutID(String skuUsageForStockOutID) {
this.skuUsageForStockOutID = skuUsageForStockOutID;
}
public String getMasterStockListID() {
return masterStockListID;
}
public void setMasterStockListID(String masterStockListID) {
this.masterStockListID = masterStockListID;
}
public String getPartNumber() {
return partNumber;
}
public void setPartNumber(String partNumber) {
this.partNumber = partNumber;
}
public String getAltPartNumber() {
return altPartNumber;
}
public void setAltPartNumber(String altPartNumber) {
this.altPartNumber = altPartNumber;
}
public String getQuantity() {
return quantity;
}
public void setQuantity(String quantity) {
this.quantity = quantity;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
public String getTotal() {
return total;
}
public void setTotal(String total) {
this.total = total;
}
public String getSkuType() {
return skuType;
}
public void setSkuType(String skuType) {
this.skuType = skuType;
}
}
Because the response has a "result" as the root, I added the following to a file named "StockOutItemResult.java" that also came from JsonSchema2Pojo:
@SerializedName("result")
@Expose
private List<StockOutItemsResponse> result = null;
@SerializedName("targetUrl")
@Expose
private Object targetUrl;
@SerializedName("success")
@Expose
private Boolean success;
@SerializedName("error")
@Expose
private Object error;
@SerializedName("unAuthorizedRequest")
@Expose
private Boolean unAuthorizedRequest;
@SerializedName("__abp")
@Expose
private Boolean abp;
public List<StockOutItemsResponse> getResult() {
return result;
}
public void setResult(List<StockOutItemsResponse> result) {
this.result = result;
}
public Object getTargetUrl() {
return targetUrl;
}
public void setTargetUrl(Object targetUrl) {
this.targetUrl = targetUrl;
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public Object getError() {
return error;
}
public void setError(Object error) {
this.error = error;
}
public Boolean getUnAuthorizedRequest() {
return unAuthorizedRequest;
}
public void setUnAuthorizedRequest(Boolean unAuthorizedRequest) {
this.unAuthorizedRequest = unAuthorizedRequest;
}
public Boolean getAbp() {
return abp;
}
public void setAbp(Boolean abp) {
this.abp = abp;
}
My request is named, "StockOutItemsRequest" and it looks like this:
public class StockOutItemsRequest {
public String companyID;
public String warehouseID;
public StockOutItemsRequest(String companyID, String warehouseID) {
this.companyID = companyID;
this.warehouseID = warehouseID;
}
}
Then comes my adapter for the list view, named "StockOutItemsAdapter.java":
public class StockOutItemsAdapter extends ArrayAdapter<StockOutItemsResult> {
public StockOutItemsAdapter(Context context, int resource, ArrayList<StockOutItemsResult> objects) {
super(context, resource, objects);
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
StockOutItemsResult stockOutItemsResult = getItem(position);
if(convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.stockout_adapter_view_layout, parent, false);
}
// Lookup view for data population
TextView tv_sku_id = (TextView) convertView.findViewById(R.id.txt_sku_id);
TextView tv_sku = (TextView) convertView.findViewById(R.id.txt_sku);
TextView tv_alt_sku = (TextView) convertView.findViewById(R.id.txt_alt_sku);
TextView tv_quantity = (TextView) convertView.findViewById(R.id.txt_quantity);
TextView tv_price = (TextView) convertView.findViewById(R.id.txt_price);
TextView tv_total = (TextView) convertView.findViewById(R.id.txt_total);
tv_sku_id.setText(stockOutItemsResult.skuUsageForStockOutID);
tv_sku.setText(stockOutItemsResult.partNumber);
tv_alt_sku.setText(stockOutItemsResult.altPartNumber);
tv_quantity.setText(stockOutItemsResult.quantity);
tv_price.setText(stockOutItemsResult.price);
tv_total.setText(stockOutItemsResult.total);
return convertView;
}
}
And my interface:
@GET("getStockOutItems")
Call<ArrayList<StockOutItemsResult>> getStockOutItems(
@Query("companyID") String companyID,
@Query("warehouseID") String warehouseID);
I also pass some headers with that.
I then placed the following in my StockOutActivity.kt:
// global arrayList
private var skuItems: ArrayList<StockOutItemsResult>? = null
using Retrofit2, I call the API:
call.enqueue(object : Callback<ArrayList<StockOutItemsResult>> {
@RequiresApi(Build.VERSION_CODES.KITKAT)
@SuppressLint("SetTextI18n")
override fun onResponse(
call: Call<ArrayList<StockOutItemsResult>>,
response: Response<ArrayList<StockOutItemsResult>>
) {
if (response.isSuccessful) {
val responseString: ArrayList<StockOutItemsResult>? = response.body()
// store values to access later
skuItems = responseString
if (responseString != null) {
val skuList = ArrayList(responseString)
var adapter = StockOutItemsAdapter(
this@StockOutActivity,
R.layout.stockout_adapter_view_layout,
skuList
)
mListViewLayout.adapter = adapter
swipeMenu()
}
} else {
}
}
override fun onFailure(
call: Call<ArrayList<StockOutItemsResult>>,
t: Throwable
) {
t.printStackTrace()
Toast.makeText(this@StockOutActivity, "error :(", Toast.LENGTH_SHORT).show()
}
})
When I run the app in the simulator, all of my other calls work fine, but when I get to this part, that is what throws the error.
My resultset shows one record, but it will, on most occasions have multiple ones so that's why I need to convert it to a list.
Can someone show me the problem and what I need to do to fix it because I have about 4 more activities to develop and I will learn from this one.
Thanks
Edit: Below is the log which shows what's happening after receiving the json results:
I/okhttp.OkHttpClient: {"result":[{"stockOutID":"22","skuUsageForStockOutID":"37","masterStockListID":"4","partNumber":"51220","altPartNumber":"Z-234","quantity":"2.0","price":"6.00","total":"12.00","skuType":"INVENTORY-ITEM"},{"stockOutID":"22","skuUsageForStockOutID":"38","masterStockListID":"81","partNumber":"3950TKS","altPartNumber":"","quantity":"1.0","price":"275.00","total":"275.00","skuType":"NON-INVENTORY-ITEM"}],"targetUrl":null,"success":true,"error":null,"unAuthorizedRequest":false,"__abp":true} <-- END HTTP (489-byte body) W/System.err: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $ W/System.err: at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350) at Z4D236D9A2D102C5FE 6AD1C50DA4BEC50Z.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80) W/System.err: at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:40) at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27) at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243) at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:153) at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519) W/System.err: at Z93F725A07423FE1C889 F448B33D21F46Z.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923)
I'm calling my service this way:
@GET("api/mobistock/getStockOutItems")
Call<StockOutItemsResult> getStockOutItems(
@Query("companyID") String companyID,
@Query("warehouseID") String warehouseID,
@Header("Authorization") String token,
@Header("Content-Type") String cType,
@Header("Abp.TenantId") String tenantId);
and in my activity...
call.enqueue(object : Callback<StockOutItemsResult> {
override fun onResponse(
call: Call<StockOutItemsResult>, response: Response<StockOutItemsResult>
) {
if(response.isSuccessful) {
**//stockOutItems_Array = response.body() asArrayList<StockOutItemsResult> ** //<--- was trying to see what was being returned, but it errors out.
}
else {
//Log.e("Response Error", "Something went wrong")
}
}
override fun onFailure(call: Call<StockOutItemsResult>, t: Throwable) {
Log.e("Response Failure Error", "Something went wrong")
}
})
Your JSON response from the server is not valid. Try this online JSON validator with your response from the server and verify that it's valid.
EDIT
From your request:
@GET("getStockOutItems")
Call<ArrayList<StockOutItemsResult>> getStockOutItems(
@Query("companyID") String companyID,
@Query("warehouseID") String warehouseID);
You expect an array to be returned, but the server sends an object. So if StockOutItemsResult
is the object that represents your response you should write your method like here:
@GET("getStockOutItems")
Call<StockOutItemsResult> getStockOutItems(
@Query("companyID") String companyID,
@Query("warehouseID") String warehouseID);
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.