Search code examples
javaandroidandroid-asynctaskgoogle-places-apireview

Android Java Google Places GET (Pull) Reviews JSONException No value for reviews


I checked and made sure google places api for android was enabled.

At first I was using this url:

https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=34.0467359,-118.441764&radius=1000&sensor=true&key=YOUR_PLACE_API_KEY

and switched to this:

https://maps.googleapis.com/maps/api/place/details/json? reference=REFERENCE_STRING_OF_THE_PLACE&sensor=true&key=YOUR_PLACE_API_KEY

as per recommendation in

Android - Google Places API - No "reviews" Array

but still got the same error.

On https://developers.google.com/places/web-service/details

It was stated that reference was deprecated and now we have to use place_id. I changed the url to:

https://maps.googleapis.com/maps/api/place/details/json?placeid=ChIJN1t_tDeuEmsRUsoyG83frY4&key=YOUR_API_KEY

Later on I read on stackoverflow that in 2012 google places API did not have the functionality to pull reviews. Is this applicable to now? In 2016? If not, please help me decipher in my code below what I did (am doing) wrong.

If I copy and paste any of the log outputs for any of the above urls, the reviews are showing in my browser but the output in the response is not displaying the url.

I am getting this error:

W/System.err: org.json.JSONException: No value for reviews 

W/System.err:     at org.json.JSONObject.get(JSONObject.java:389) 

W/System.err:     at org.json.JSONObject.getJSONArray(JSONObject.java:584)

W/System.err:    at DownloadReviewsTask.doInBackground(DownloadReviewsTask.java:69)

W/System.err:     at DownloadReviewsTask.doInBackground(DownloadReviewsTask.java:19)

W/System.err:     at android.os.AsyncTask$2.call(AsyncTask.java:292)

W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)

W/System.err:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)  

W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 

W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 

W/System.err:     at java.lang.Thread.run(Thread.java:818)

This is my code below:

public class JSONParser {

    String charset = "UTF-8";
    HttpURLConnection conn;
    DataOutputStream wr;
    StringBuilder result = new StringBuilder();
    URL urlObj;
    JSONObject jObj = null;

    StringBuilder sbParams;
    String paramsString;

    public JSONObject makeHttpRequest(String url, String method,
                                      HashMap<String, String> params) {

        sbParams = new StringBuilder();
        int i = 0;
        for (String key : params.keySet()) {
            try {
                if (i != 0){
                    sbParams.append("&");
                }
                sbParams.append(key).append("=")
                        .append(URLEncoder.encode(params.get(key), charset));

            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            i++;
        }

        if (method.equals("POST")) {
            // request method is POST
            try {
                urlObj = new URL(url);

                conn = (HttpURLConnection) urlObj.openConnection();

                conn.setDoOutput(true);

                conn.setRequestMethod("POST");

                conn.setRequestProperty("Accept-Charset", charset);

                conn.setReadTimeout(90000);
                conn.setConnectTimeout(90000);

                conn.connect();

                paramsString = sbParams.toString();

                wr = new DataOutputStream(conn.getOutputStream());
                wr.writeBytes(paramsString);
                wr.flush();
                wr.close();

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        else if(method.equals("GET")){
            // request method is GET

            if (sbParams.length() != 0) {
                url += "?" + sbParams.toString();
            }

            try {
                urlObj = new URL(url);

                conn = (HttpURLConnection) urlObj.openConnection();

                conn.setDoOutput(false);

                conn.setRequestMethod("GET");

                conn.setRequestProperty("Accept-Charset", charset);

                conn.setConnectTimeout(90000);

                conn.connect();

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

        }

        try {
            //Receive the response from the server
            InputStream in = new BufferedInputStream(conn.getInputStream());
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));

            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }

            Log.d("JSON Parser", "result: " + result.toString());


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

        conn.disconnect();

        // try parse the string to a JSON object

        try {
            jObj = new JSONObject(result.toString());
        } catch (JSONException e) {
            Log.e("JSON Parser", "Error parsing data " + e.toString());
        }

        // return JSON Object
        return jObj;

    }

}
public class DownloadReviewsTask extends AsyncTask<String, Void, HashMap<String, List<MyModel>>> {
    //Declarations
    private Context mContext;
    public Exception mException;
    private OnEventListener<HashMap<String, List<MyModel>>> mCallBack;
    JSONArray reviews;
    String author_name;
    String text;
    //Constructor
    public DownloadReviewsTask(Context context, OnEventListener callback) {
        mCallBack = callback;
        mContext = context;
    }
    //sets and passes the review author and text for each review and sets them in the My Model
    public MyModel setPlace(JSONObject thisObject) throws JSONException {
        JSONObject results = thisObject.getJSONObject("results");
       MyModel thisMyModel = new MyModel();
        if (!results.isNull("reviews")) {
            reviews = results.getJSONArray("reviews");
            Log.e("reviews array setPlace", String.valueOf(reviews));
            for (int i = 0; i < reviews.length(); i++) {
                //if(i==reviews.length()) break;
               // if (thisObject.getJSONArray("reviews").getJSONObject(i).has("author_name")) //{
                    author_name = results.getJSONArray("reviews").getJSONObject(i).getString("author_name");//reviews.getJSONObject(i).getString("author");
                    Log.e("review_author in setup", results.getJSONArray("reviews").getJSONObject(i).getString("author_name"));
               // }
                //if (thisObject.getJSONArray("reviews").getJSONObject(i).has("text")) {
                    Log.e("review text in setup", results.getJSONArray("reviews").getJSONObject(i).getString("text"));
                    text = results.getJSONArray("reviews").getJSONObject(i).getString("text");//}

                thisMyModel.setAuthor_name(author_name);
                thisMyModel.setText(text);
            }
        }
        return thisMyModel;
    }

    @Override
    protected HashMap<String, List<MyModel>> doInBackground(String... args) {
        try {
            JSONParser jsonParser = new JSONParser();
            JSONObject json;
            String reviewUrl = args[0];
            Log.e("reviewUrl",reviewUrl);
            //Use a HashMap instead with the varargs:
            HashMap<String, String> params = new HashMap<>();
            json = jsonParser.makeHttpRequest(reviewUrl, "GET", params);
            HashMap<String, List<MyModel>> myResults = new HashMap<>();
            if(json != null) {
                Log.e("reviews result", json.toString());
                JSONArray parentArray = json.getJSONArray("reviews");
                List<MyModel> allEventsList = new ArrayList<>();
                //loops through json array
                for (int i = 0; i < parentArray.length(); i++) {
                    JSONObject finalObject = parentArray.getJSONObject(i);
                    allEventsList.add(setPlace(finalObject));
                    Log.e("allEventsList", String.valueOf(allEventsList));
                }
                myResults.put("reviews", allEventsList);
                Log.e("myResults",String.valueOf(myResults));
                return myResults;

            }else{
                return null;
            }
        }
        catch (JSONException e){
            e.printStackTrace();
        }
        return null;

    }

    @Override
    protected void onPostExecute(HashMap<String, List<MyModel>> result) {
        if (mCallBack != null) {
            if (mException == null) {
                mCallBack.onSuccess(result);
            } else {
                mCallBack.onFailure(mException);
            }
        }
    }
}
public class MyModel{
        private String reference;
        public void setReference(String reference) {
            this.reference = reference;
        }
        public String getReference() {
            return reference;
        }
    }
public class MainActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
              String reviewsUrl = "https://maps.googleapis.com/maps/api/place/details/json?reference="+reference+sensor+key;
                  DownloadReviewsTask rev = new DownloadReviewsTask(this, new OnEventListener<HashMap<String, List<MyModel>>>() {

                @Override
                public void onSuccess(HashMap<String, List<MyModel>> result) {
                    if(result != null && result.size() > 0) {
                        for (int i = 0; i < result.size(); i++){
                            Log.e("review SingleVewInit",result.get("reviews").get(0).getAuthor_name());
                            Log.e("review SingleVewInit",result.get("reviews").get(0).getText());
                        }
                    }
                }

                @Override
                public void onFailure(Exception e) {
                    //Toast.makeText(this, "ERROR: " + e.getMessage(), Toast.LENGTH_LONG).show();
                    Log.e("ERROR: " ,e.getMessage());
                }
            });
            rev.execute(reviewsUrl);
  }

}

Solution

  • Alright below is the sample code to fetch reviews. You need to understand the code and make necessary changes to work in your code.

    new Thread(new Runnable() {
            @Override
            public void run() {
    
                try {
    
                    URL url = new URL("https://maps.googleapis.com/maps/api/place/details/json?placeid=ChIJN1t_tDeuEmsRUsoyG83frY4&key=AIzaSyAAkK3AyE8Cbqb9H5MYqptjJwRhRgltoZM");
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    InputStream in = connection.getInputStream();
    
                    int ch = -1;
                    StringBuffer buffer = new StringBuffer();
                    while((ch = in.read()) != -1){
                        buffer.append((char)ch);
                    }
    
                    JSONObject jObj = new JSONObject(buffer.toString());
                    JSONObject jResult = jObj.getJSONObject("result");
                    JSONArray jReviewArray = jResult.getJSONArray("reviews");
    
                    for(int i=0; i<jReviewArray.length(); i++){
                        JSONObject jReview = jReviewArray.getJSONObject(i);
                        System.out.println( jReview.getString("author_name") +"\n"+ jReview.getString("text") +"\n\n");
                    }
    
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (JSONException e) {
                    e.printStackTrace();
                }
    
            }
        }).start();
    

    It prints the Author_Name with Review_Text.

    Update your code as below-

    1. In DownloadReviewsTask-

    change JSONArray parentArray = json.getJSONArray("reviews");

    to JSONArray parentArray = json.getJSONArray("result");

    1. change setPlace() as below-

      public MyModel setPlace(JSONObject thisObject) throws JSONException {
      
      MyModel thisMyModel = new MyModel();
      author_name = thisObject.getString("author_name");
      text = thisObject.getString("text");
      
      thisMyModel.setAuthor_name(author_name);
      thisMyModel.setText(text);
      
      return thisMyModel;
      
      }
      
    2. I didn't found setAuthor_name() and setText() methods inside MyModal so change it as below-

      public class MyModel{
      private String reference;
      private String author_name;
      private String text;
      
      public void setAuthor_name(String author_name) {
          this.author_name = author_name;
      }
      public String getAuthor_name() {
          return author_name;
      }
      
      public void setText(String text) {
          this.text = text;
      }
      public String getText() {
          return text;
      }
      
      public void setReference(String reference) {
          this.reference = reference;
      }
      public String getReference() {
          return reference;
      }
      }
      
    3. finally change the Log stmt as in MainActivity as below-

      Log.e("review SingleVewInit",result.get(i).getAuthor_name());
      Log.e("review SingleVewInit",result.get(i).getText());