2

I am using volley + OkHttp to get some data from a server.

The response is a string containing JSON, which I want to parse using GSON/POJO.

I get the error:

Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $

when trying to parse.

Caused by: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
at com.google.gson.stream.JsonReader.beginObject(JsonReader.java:388)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:209)
at com.google.gson.Gson.fromJson(Gson.java:879) 
at com.google.gson.Gson.fromJson(Gson.java:844) 
at com.google.gson.Gson.fromJson(Gson.java:793) 
at com.google.gson.Gson.fromJson(Gson.java:765) 
at test.com.example.buddy.myapplication.MainActivity$8.onResponse(MainActivity.java:192) //

Line 192 is Post component = gson.fromJson(response, Post.class);

On the other hand when I use below JSON_STRING it works as expected and I get the values using the POJO class.

String JSON_STRING = "{\"currentBalance\":{\"amount\":0.0,\"currencyCode\":\"EUR\"},\"currentBalanceDisplay\":true,\"overdueAmount\":null,\"overdueAmountDisplay\":false," +
                     "\"creditAmount\":null,\"creditAmountDisplay\":false,\"noOfBillsToShow\":3,\"recentBills\":[{\"period\":\"03 2016\",\"amount\":{\"amount\":22.76," +
                     "\"currencyCode\":\"EUR\"},\"status\":\"PAID\",\"dueDate\":\"14-03-2016\",\"sortOrder\":\"20160308\",\"periodType\":\"MONTHLY\"," +
                     "\"invoiceId\":\"277726719\",\"invoiceDate\":\"08-03-2016\"}]}";

I would be grateful if someone could help. Thank you in advance.

EDIT: I feel like a complete idiot :) It turned out I was querying the wrong URL, everything works as expected. Thanks again guys for helping me out.

String response from server:

{
  "currentBalance": {
    "amount": 0.0,
    "currencyCode": "EUR"
  },
  "currentBalanceDisplay": true,
  "overdueAmount": null,
  "overdueAmountDisplay": false,
  "creditAmount": null,
  "creditAmountDisplay": false,
  "noOfBillsToShow": 3,
  "recentBills": [
    {
      "period": "03 2016",
      "amount": {
        "amount": 12.53,
        "currencyCode": "EUR"
      },
      "status": "PAID",
      "dueDate": "14-03-2016",
      "sortOrder": "2548264",
      "periodType": "MONTHLY",
      "invoiceId": "012345678",
      "invoiceDate": "08-03-2016"
    }
  ]
}

Volley request:

private void FetchData() {

StringRequest finalrequest = new StringRequest(Request.Method.POST, FETCHURL,
      new Response.Listener<String>() {

          @Override
          public void onResponse(String response) {

                 Gson gson = new Gson();
                 Post component = gson.fromJson(response, Post.class);
                 System.out.println("JSON " + component.getRecentBills().get(0).getInvoiceDate());
                 // Output: JSON 08-03-2016 (success!)
            }
        },
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.d("ERROR", "error finalrequest => " + error.toString());
            }
        }
) {
    @Override
    public String getBodyContentType() {
        return "application/x-www-form-urlencoded; charset=utf-8";
    }

    // this is the relevant method
    @Override
    public byte[] getBody() {

        String httpPostBody = "action=GET_CUST_BILLS&" + "user=" + CustID;
        try {
            httpPostBody = httpPostBody + URLEncoder.encode("", "UTF-8");

        } catch (UnsupportedEncodingException exception) {

            Log.e("ERROR", "exception", exception);
            // return null and don't pass any POST string if you encounter encoding error
            return null;
        }
        Log.d("POSTBODY ", httpPostBody.toString());
        return httpPostBody.getBytes();
    }
};
finalrequest.setRetryPolicy(new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS * 5,
            DefaultRetryPolicy.DEFAULT_MAX_RETRIES,  DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
    TestController.getInstance().addToRequestQueue(finalrequest, "Final");
  }

POJO Post class:

public class Post {

    private CurrentBalanceBean currentBalance;
    private boolean currentBalanceDisplay;
    private Object overdueAmount;
    private boolean overdueAmountDisplay;
    private Object creditAmount;
    private boolean creditAmountDisplay;
    private int noOfBillsToShow;

    private List<RecentBillsBean> recentBills;

    public static Post objectFromData(String str) {

        return new Gson().fromJson(str, Post.class);
    }

    public static Post objectFromData(String str, String key) {

        try {
            JSONObject jsonObject = new JSONObject(str);

            return new Gson().fromJson(jsonObject.getString(str), Post.class);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static List<Post> arrayPostFromData(String str) {

        Type listType = new TypeToken<ArrayList<Post>>() {
        }.getType();

        return new Gson().fromJson(str, listType);
    }

    public static List<Post> arrayPostFromData(String str, String key) {

        try {
            JSONObject jsonObject = new JSONObject(str);
            Type listType = new TypeToken<ArrayList<Post>>() {
            }.getType();

            return new Gson().fromJson(jsonObject.getString(str), listType);

        } catch (JSONException e) {
            e.printStackTrace();
        }

        return new ArrayList();


    }

    public CurrentBalanceBean getCurrentBalance() {
        return currentBalance;
    }

    public void setCurrentBalance(CurrentBalanceBean currentBalance) {
        this.currentBalance = currentBalance;
    }

    public boolean isCurrentBalanceDisplay() {
        return currentBalanceDisplay;
    }

    public void setCurrentBalanceDisplay(boolean currentBalanceDisplay) {
        this.currentBalanceDisplay = currentBalanceDisplay;
    }

    public Object getOverdueAmount() {
        return overdueAmount;
    }

    public void setOverdueAmount(Object overdueAmount) {
        this.overdueAmount = overdueAmount;
    }

    public boolean isOverdueAmountDisplay() {
        return overdueAmountDisplay;
    }

    public void setOverdueAmountDisplay(boolean overdueAmountDisplay) {
        this.overdueAmountDisplay = overdueAmountDisplay;
    }

    public Object getCreditAmount() {
        return creditAmount;
    }

    public void setCreditAmount(Object creditAmount) {
        this.creditAmount = creditAmount;
    }

    public boolean isCreditAmountDisplay() {
        return creditAmountDisplay;
    }

    public void setCreditAmountDisplay(boolean creditAmountDisplay) {
        this.creditAmountDisplay = creditAmountDisplay;
    }

    public int getNoOfBillsToShow() {
        return noOfBillsToShow;
    }

    public void setNoOfBillsToShow(int noOfBillsToShow) {
        this.noOfBillsToShow = noOfBillsToShow;
    }

    public List<RecentBillsBean> getRecentBills() {
        return recentBills;
    }

    public void setRecentBills(List<RecentBillsBean> recentBills) {
        this.recentBills = recentBills;
    }

    public static class CurrentBalanceBean {
        private int amount;
        private String currencyCode;

        public static CurrentBalanceBean objectFromData(String str) {

            return new Gson().fromJson(str, CurrentBalanceBean.class);
        }

        public static CurrentBalanceBean objectFromData(String str, String key) {

            try {
                JSONObject jsonObject = new JSONObject(str);

                return new Gson().fromJson(jsonObject.getString(str), CurrentBalanceBean.class);
            } catch (JSONException e) {
                e.printStackTrace();
            }

            return null;
        }

        public static List<CurrentBalanceBean> arrayCurrentBalanceBeanFromData(String str) {

            Type listType = new TypeToken<ArrayList<CurrentBalanceBean>>() {
            }.getType();

            return new Gson().fromJson(str, listType);
        }

        public static List<CurrentBalanceBean> arrayCurrentBalanceBeanFromData(String str, String key) {

            try {
                JSONObject jsonObject = new JSONObject(str);
                Type listType = new TypeToken<ArrayList<CurrentBalanceBean>>() {
                }.getType();

                return new Gson().fromJson(jsonObject.getString(str), listType);

            } catch (JSONException e) {
                e.printStackTrace();
            }

            return new ArrayList();


        }

        public int getAmount() {
            return amount;
        }

        public void setAmount(int amount) {
            this.amount = amount;
        }

        public String getCurrencyCode() {
            return currencyCode;
        }

        public void setCurrencyCode(String currencyCode) {
            this.currencyCode = currencyCode;
        }
    }

    public static class RecentBillsBean {
        private String period;
        /**
         * amount : 22.76
         * currencyCode : EUR
         */

        private AmountBean amount;
        private String status;
        private String dueDate;
        private String sortOrder;
        private String periodType;
        private String invoiceId;
        private String invoiceDate;

        public static RecentBillsBean objectFromData(String str) {

            return new Gson().fromJson(str, RecentBillsBean.class);
        }

        public static RecentBillsBean objectFromData(String str, String key) {

            try {
                JSONObject jsonObject = new JSONObject(str);

                return new Gson().fromJson(jsonObject.getString(str), RecentBillsBean.class);
            } catch (JSONException e) {
                e.printStackTrace();
            }

            return null;
        }

        public static List<RecentBillsBean> arrayRecentBillsBeanFromData(String str) {

            Type listType = new TypeToken<ArrayList<RecentBillsBean>>() {
            }.getType();

            return new Gson().fromJson(str, listType);
        }

        public static List<RecentBillsBean> arrayRecentBillsBeanFromData(String str, String key) {

            try {
                JSONObject jsonObject = new JSONObject(str);
                Type listType = new TypeToken<ArrayList<RecentBillsBean>>() {
                }.getType();

                return new Gson().fromJson(jsonObject.getString(str), listType);

            } catch (JSONException e) {
                e.printStackTrace();
            }

            return new ArrayList();


        }

        public String getPeriod() {
            return period;
        }

        public void setPeriod(String period) {
            this.period = period;
        }

        public AmountBean getAmount() {
            return amount;
        }

        public void setAmount(AmountBean amount) {
            this.amount = amount;
        }

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }

        public String getDueDate() {
            return dueDate;
        }

        public void setDueDate(String dueDate) {
            this.dueDate = dueDate;
        }

        public String getSortOrder() {
            return sortOrder;
        }

        public void setSortOrder(String sortOrder) {
            this.sortOrder = sortOrder;
        }

        public String getPeriodType() {
            return periodType;
        }

        public void setPeriodType(String periodType) {
            this.periodType = periodType;
        }

        public String getInvoiceId() {
            return invoiceId;
        }

        public void setInvoiceId(String invoiceId) {
            this.invoiceId = invoiceId;
        }

        public String getInvoiceDate() {
            return invoiceDate;
        }

        public void setInvoiceDate(String invoiceDate) {
            this.invoiceDate = invoiceDate;
        }

        public static class AmountBean {
            private double amount;
            private String currencyCode;

            public static AmountBean objectFromData(String str) {

                return new Gson().fromJson(str, AmountBean.class);
            }

            public static AmountBean objectFromData(String str, String key) {

                try {
                    JSONObject jsonObject = new JSONObject(str);

                    return new Gson().fromJson(jsonObject.getString(str), AmountBean.class);
                } catch (JSONException e) {
                    e.printStackTrace();
                }

                return null;
            }

            public static List<AmountBean> arrayAmountBeanFromData(String str) {

                Type listType = new TypeToken<ArrayList<AmountBean>>() {
                }.getType();

                return new Gson().fromJson(str, listType);
            }

            public static List<AmountBean> arrayAmountBeanFromData(String str, String key) {

                try {
                    JSONObject jsonObject = new JSONObject(str);
                    Type listType = new TypeToken<ArrayList<AmountBean>>() {
                    }.getType();

                    return new Gson().fromJson(jsonObject.getString(str), listType);

                } catch (JSONException e) {
                    e.printStackTrace();
                }

                return new ArrayList();


            }

            public double getAmount() {
                return amount;
            }

            public void setAmount(double amount) {
                this.amount = amount;
            }

            public String getCurrencyCode() {
                return currencyCode;
            }

            public void setCurrencyCode(String currencyCode) {
                this.currencyCode = currencyCode;
            }
        }
    }
}
Reaz Murshed
  • 21,071
  • 12
  • 69
  • 87
Simon
  • 1,531
  • 2
  • 9
  • 24
  • There's a class called JsonRequest itself in volley, it's better you use it becasue it does everything for you you can acess the Json directly – Sumanth Jois Mar 29 '16 at 06:40
  • @Jois, thx for the response but I tried that already, same error. – Simon Mar 29 '16 at 06:41
  • try to Log your response with Log.v("json response", response); before Gson gson = new Gson(); Post component = gson.fromJson(response, Post.class); and see if the actual server response is same with your expected response. – HendraWD Mar 29 '16 at 06:45
  • @HendraWijayaDjiono done that but I got the following: V/json response: Request cannot be served without a proper action – Simon Mar 29 '16 at 06:47
  • @simon http://www.mkyong.com/java/how-do-convert-java-object-to-from-json-format-gson-api/ – Sumanth Jois Mar 29 '16 at 06:48
  • @Simon the response should be JSON string, but you get "Request cannot be served without a proper action" instead. You should check your server then. The problem is not with your app code – HendraWD Mar 29 '16 at 06:50
  • @simon gson.fromJson(response, Post.class); Post.class this is what which is caushin your problem. first send the response to postclass and put the object of post class instead of response – Sumanth Jois Mar 29 '16 at 06:51
  • @Jois it is obvious, since Gson expect JSON string, but it get "Request cannot be served without a proper action" instead. – HendraWD Mar 29 '16 at 06:53
  • @Jois, could you pls give an example what you mean? I am a little confused now. – Simon Mar 29 '16 at 06:53
  • https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/Gson.html#fromJson(com.google.gson.JsonElement, java.lang.Class) – Sumanth Jois Mar 29 '16 at 06:54
  • Is it possible to 'convert' the response to JSON STRING? When I use that string it works. Or am I on the wrong track. I don`t own the server so I need to improvise. – Simon Mar 29 '16 at 06:55
  • @Jois, Thx for the link. I don`t get this to work with my code, still same error. Could you pls give me an example code using mine to get me on track? – Simon Mar 29 '16 at 07:02
  • sure give two minutes – Sumanth Jois Mar 29 '16 at 07:20

3 Answers3

2

I will make it clear for you. The response should be:

{
  "currentBalance": {
    "amount": 0.0,
    "currencyCode": "EUR"
  },
  "currentBalanceDisplay": true,
  "overdueAmount": null,
  "overdueAmountDisplay": false,
  "creditAmount": null,
  "creditAmountDisplay": false,
  "noOfBillsToShow": 3,
  "recentBills": [
    {
      "period": "03 2016",
      "amount": {
        "amount": 12.53,
        "currencyCode": "EUR"
      },
      "status": "PAID",
      "dueDate": "14-03-2016",
      "sortOrder": "2548264",
      "periodType": "MONTHLY",
      "invoiceId": "012345678",
      "invoiceDate": "08-03-2016"
    }
  ]
}

But, you get:

"Request cannot be served without a proper action"

If you don't own the server, i suppose you use API from a provider. You should check their documentation correctly. My guess, you miss a parameter or maybe they need you to add some cookies to your request.

HendraWD
  • 2,646
  • 2
  • 27
  • 45
2

1) Store your Json in a Pojo class 2)Convert the Pojo class object to Gson.

Example:

   @Override
       public void onResponse(String response) {

           Gson gson = new Gson();
                 Post object = new Post();
                 object.setResponse(response);
          String gson = gson.fromJson(object, Post.class);//as you have overrided toString() it will return you the response you have set
           System.out.println(gson);
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                        // Handle error
                }
            }

Pojo CLASS

          public class  Post{

                  private String resposne;
              private int example;
               ....

               public void setResponse(String Response){

                  this.response = Response;
          } 

      @Override
        public String toString() {
           return  response;
            }

       } 

I hope this was helpful simon. ThankYou

Sumanth Jois
  • 2,862
  • 2
  • 21
  • 35
1

Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $

This is a common JSON parsing problem when you get HTML response from the server like this one.

<html>
<body>
<h1>404 Not Found</h1>
</body>
</html>

So the Gson is expecting a JSON object and throws this type of exception when proper format is not found.

There are several cases that might happen here. Please check each of them.

  • Your method is a POST and please check if the server side accepts body in application/x-www-form-urlencoded format. The body might be expecting application/json or text/plain etc.
  • Check if the parameters are passed correctly.
  • If nothing's wrong with your side, you might have to check the server side too. Check if it could process your request and could response with the proper data you're expecting.

Try using Postman to simulate the request and the response. This is much faster for debugging this kind of cases.

Reaz Murshed
  • 21,071
  • 12
  • 69
  • 87