-3

I have a configuration file that I pick up from the server at the launch of my android app. The code for fetching the file is pretty standard

@Override
protected void onResume() {
    super.onResume();
    new ConnectionTask().execute();
}
private class ConnectionTask extends AsyncTask<String, String, String> {

    @Override
    protected void onPreExecute() {
    }

    @Override
    protected String doInBackground(String... args) {
        String result = null;
        AuthenticateConnection mAuth1 = new AuthenticateConnection();
        try {
            result = mAuth1.connection();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    @Override
    protected void onPostExecute(String str) {
        if (!isFinishing() && !isDestroyed()) {
            if (!TextUtils.isEmpty(str)) {
                Log.e("str", "" + str);
                /****** The below line crashes*******/
                BaseUrl obj = new Gson().fromJson(str, BaseUrl.class);
                /****** The above line crashes*******/
                //Some Logic here
            } 
        }
    }
}

private class AuthenticateConnection {

    public AuthenticateConnection() {
    }

    public String connection() throws Exception {
        String str = "";
        try {
            // Create a URL for the desired page
            if (!TextUtils.isEmpty(getApplicationContext().getResources().getString(R.string.configuration_url))) {
                String aUrl = getApplicationContext().getResources().getString(R.string.configuration_url);
                URL url = new URL("http://" + aUrl);
                str = convertStreamToString(url.openStream());
            } else {
                str = "";
            }
        } catch (MalformedURLException e) {
        } catch (IOException e) {
        }
        return str;
    }

    public String convertStreamToString(InputStream is) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        StringBuilder sb = new StringBuilder();

        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
        e.printStackTrace();
        } finally {
            try {
            is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
}

I am getting a strange exception while parsing the file. I and my team have not encountered this error in all our unit testing but Crashlytics reports a lot of user facing this exception, here in onPostExecute(), while parsing the json, BaseUrl obj = new Gson().fromJson(str, BaseUrl.class);

What could be the potential reasons for this exception.

Fatal Exception: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(SourceFile:200)
       at com.google.gson.Gson.fromJson(SourceFile:810)
       at com.google.gson.Gson.fromJson(SourceFile:775)
       at com.google.gson.Gson.fromJson(SourceFile:724)
       at com.google.gson.Gson.fromJson(SourceFile:696)
       at com.myapp.activity.Splash$ConnectionTask.onPostExecute(SourceFile:263)
       at com.myapp.activity.Splash$ConnectionTask.onPostExecute(SourceFile:237)
       at android.os.AsyncTask.finish(AsyncTask.java:632)
       at android.os.AsyncTask.access$600(AsyncTask.java:177)
       at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:136)
       at android.app.ActivityThread.main(ActivityThread.java:5095)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:515)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
       at dalvik.system.NativeStart.main(NativeStart.java)
Caused by java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
       at com.google.gson.stream.JsonReader.beginObject(SourceFile:387)
       at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(SourceFile:189)
       at com.google.gson.Gson.fromJson(SourceFile:810)
       at com.google.gson.Gson.fromJson(SourceFile:775)
       at com.google.gson.Gson.fromJson(SourceFile:724)
       at com.google.gson.Gson.fromJson(SourceFile:696)
       at com.myapp.activity.Splash$ConnectionTask.onPostExecute(SourceFile:263)
       at com.myapp.activity.Splash$ConnectionTask.onPostExecute(SourceFile:237)
       at android.os.AsyncTask.finish(AsyncTask.java:632)
       at android.os.AsyncTask.access$600(AsyncTask.java:177)
       at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:136)
       at android.app.ActivityThread.main(ActivityThread.java:5095)
       at java.lang.reflect.Method.invokeNative(Method.java)
       at java.lang.reflect.Method.invoke(Method.java:515)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602)
       at dalvik.system.NativeStart.main(NativeStart.java)

The reference json is that is stored in the configuration file is as below, and BaseUrl.java conforms to this json:

{ "baseUrls": [{
    "versionCode": 10,
    "baseUrl": "http://myapp.in",
    "infra": "staging"
},{
        "versionCode": 11,
        "baseUrl": "http://myapp.in",
        "infra": "production"
}]
}

Adding BaseUrl.java to the Question:

public class BaseUrl implements Parcelable {

    ArrayList<VersionControl> baseUrls;

    public ArrayList<VersionControl> getBaseUrls() {
        return baseUrls;
    }

    public void setBaseUrls(ArrayList<VersionControl> baseUrls) {
        this.baseUrls = baseUrls;
    }

    protected BaseUrl(Parcel in) {
        if (in.readByte() == 0x01) {
            baseUrls = new ArrayList<VersionControl>();
            in.readList(baseUrls, VersionControl.class.getClassLoader());
        } else {
            baseUrls = null;
        }
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        if (baseUrls == null) {
            dest.writeByte((byte) (0x00));
        } else {
            dest.writeByte((byte) (0x01));
            dest.writeList(baseUrls);
        }
    }

    @SuppressWarnings("unused")
    public static final Parcelable.Creator<BaseUrl> CREATOR = new Parcelable.Creator<BaseUrl>() {
        @Override
        public BaseUrl createFromParcel(Parcel in) {
            return new BaseUrl(in);
        }

        @Override
        public BaseUrl[] newArray(int size) {
            return new BaseUrl[size];
        }
    };
}
ichthyocentaurs
  • 2,049
  • 17
  • 30
  • add this line from logcat `Log.e("str", "" + str);` ... i bet it is `str: ` as str is empty – Selvin May 09 '16 at 13:02
  • Possible duplicate of ["Expected BEGIN\_OBJECT but was STRING at line 1 column 1"](http://stackoverflow.com/questions/28418662/expected-begin-object-but-was-string-at-line-1-column-1) – Gangaraju May 09 '16 at 13:04
  • The exception that I get is at line below the one that you mention @Selvin. It says a syntax exception BaseUrl obj = new Gson().fromJson(str, BaseUrl.class) but the json itself is a valid one. – ichthyocentaurs May 09 '16 at 13:04
  • I think you have already checked [this](http://stackoverflow.com/questions/11214720/gson-expected-begin-object-but-was-string) – Raghavendra May 09 '16 at 13:05
  • @AkshatArora check my answer below. –  May 09 '16 at 13:32

3 Answers3

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

In this case means it was expecting to see { - the start of an object, but instead it saw a string, which is most likely some sort of error warning that your webserver spurts out.

Imagine the Android client receiving a response message such as

"You are unauthorized to make this request"

instead of receiving valid JSON, that's the most likely cause here.

roarster
  • 3,785
  • 1
  • 20
  • 37
  • Which would have been valid, but the json that I posted is valid, and it is the one that is placed on our servers. With redacted urls – ichthyocentaurs May 09 '16 at 13:08
  • right @AkshatArora, I'm not saying the JSON in your question is invalid, it is perfectly valid. I'm saying that sometimes your server doesn't respond with that JSON, and instead responds with a string error message when you're actually expecting JSON. It's the assumption that you'll always receive JSON that's causing problems here - I don't know many webservers that automatically print their error messages as JSON. – roarster May 09 '16 at 13:20
  • I tried to run the above request and looped in a 100 requests to the server and always got a response with a valid json. – ichthyocentaurs May 09 '16 at 16:56
  • That means nothing. It's going to be environment specific, and most probably server related rather than client related. For example, you may have a perfectly running client-server system, and then something changes server-side that changes the server state - say the php file that responds to the request changes, and has a typo in it. Then requests just result in error messages due to the typo. That's an obvious example, but I think the error in your case is more transient, and crops up under a specific set of circumstances. – roarster May 09 '16 at 19:07
  • I think what you say makes sense, although in my case the json is just a .json file that sits on a remote server, there could be any number of issues while reading it from the input stream alone. Rather than directly parsing the contents it would make more sense to check the validity of the json syntax. What amazed me though was the IllegalStateException. – ichthyocentaurs May 09 '16 at 19:15
  • I agree, it is very unlikely that a static json file produces errors, but there can still be server misconfigurations that cause errors independent of the page being accessed. I think what some other people here have suggested is a good idea - to monitor the server (error) logs. Maybe you can pass some sort of id with requests so that when you find the error in crashlytics you can search your server logs for that same request and see if it responded with anything weird? – roarster May 09 '16 at 19:25
1

The request is not properly sent to the server. The server, instead of returning the correct json, returns some error message, which is a string. It will be better if you log server response to check what is the server returning.

Prasheel
  • 942
  • 4
  • 21
0

May be the server responses just a string instead of a valid Json, this will be checked by log the 'str'. Or may be there are some problems in your BaseUrl.java, So you'd better show it.

vesper
  • 264
  • 1
  • 10