简体   繁体   中英

Android Studio ArrayList Error: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM