Simon
Simon

Reputation: 1731

Parse JSON with GSON/POJO

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;
            }
        }
    }
}

Upvotes: 2

Views: 1686

Answers (3)

Sumanth Jois
Sumanth Jois

Reputation: 3234

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

Upvotes: 2

Reaz Murshed
Reaz Murshed

Reputation: 24211

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.

Upvotes: 1

HendraWD
HendraWD

Reputation: 3043

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.

Upvotes: 2

Related Questions