0

I am really new in this "parsing world" and I know that there are already a lot of discussion about this problem (so I am sorry if it can be a reepetitive question) , but, even following some guide and reading some answer, I could not find a solution to my problem.

the error that I have is

Expected BEGIN_OBJECT but was STRING at line 1 column 1

and the JSON I need to parse it is the following:

[ 
   { 
      "id":1,
      "name":"first",
      "filename":"36ba664b-769c-404f-87e2-4ee8b9ac20a2.png",
      "floor":3,
      "north":48.31202,
      "south":48.310677,
      "east":10.1578865,
      "west":10.155078,
      "opacity":1.0,
      "level":0
   },
   { 
      "id":2,
      "name":"second",
      "filename":"522f79d4-0dd4-4425-9f81-70a73bdfebc6.png",
      "floor":0,
      "north":48.31202,
      "south":48.310677,
      "east":10.1578865,
      "west":10.155078,
      "opacity":1.0,
      "level":0
   },
   { 
      "id":3,
      "name":"third",
      "filename":"00e10310-739a-407e-86b0-373ba71144e1.png",
      "floor":0,
      "north":53.02099,
      "south":53.02067,
      "east":-1.4836869,
      "west":-1.4843831,
      "opacity":1.0,
      "level":0
     }
]

so, following this guide: http://www.androiddeft.com/retrofit-android/ I created two classes:

Data and DataList:

public class Data{

    @SerializedName("id")
    @Expose
    private Integer id;
    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("filename")
    @Expose
    private String filename;
    @SerializedName("floor")
    @Expose
    private Integer floor;
    @SerializedName("north")
    @Expose
    private Double north;
    @SerializedName("south")
    @Expose
    private Double south;
    @SerializedName("east")
    @Expose
    private Double east;
    @SerializedName("west")
    @Expose
    private Double west;
    @SerializedName("opacity")
    @Expose
    private Double opacity;
    @SerializedName("level")
    @Expose
    private Integer level;  
}

public class DataList{

    private ArrayList<Data> data = null;

    public ArrayList<Data> getData() {
        return data;
    }
}

And after I created the API service and the Retrofit Client:

public interface DataApiService {

    @GET("/")
    Call<DataList> getMyJSON();
}

public class DataRequestManager {

    private static String baseUrl = "mylink";

    private static Retrofit getRetrofitInstance() {

        Gson gson = new GsonBuilder()
                .setLenient()
                //.enableComplexMapKeySerialization()
                .create();

        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        // set your desired log level
        if (BuildConfig.DEBUG) {
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        } else {
            logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
        }

        OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.connectTimeout(10, TimeUnit.SECONDS);
        httpClient.readTimeout(20, TimeUnit.SECONDS);
        httpClient.writeTimeout(20, TimeUnit.SECONDS);
        httpClient.addInterceptor(logging);
        OkHttpClient debuggclient = httpClient.build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(new NullOnEmptyConverterFactory())
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(debuggclient).build();


        return retrofit;
    }

    public static DataApiService getApiService() {
        return getRetrofitInstance().create(DataApiService.class);
    }
}

But when I do:

        private static List<Data> dataList;

        DataApiService api = DataRequestManager.getApiService();

        Call<DataList> call = api.getMyJSON();

        call.enqueue(new Callback<DatasList>() {
            @Override
            public void onResponse(Call<DatasList> call, Response<DatasList> response) {

                if (response.isSuccessful()) {
                    //Got Successfully
                    dataList = response.body().getData();
                }
            }

            @Override
            public void onFailure(Call<DataList> call, Throwable t) {
                Toast.makeText(context, "Parsing Data Failed"+t.getMessage(),
                        Toast.LENGTH_LONG).show();
            }
        });

The application gives me the JsonSyntaxEception:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $

TheOldBlackbeard
  • 395
  • 4
  • 22

3 Answers3

2

What you are trying to do is incorrect, since your response is just an array. The json that would be acceptable for your DataList should be:

data : [
   { 
      "id":1,
      "name":"first",
      "filename":"36ba664b-769c-404f-87e2-4ee8b9ac20a2.png",
      "floor":3,
      "north":48.31202,
      "south":48.310677,
      "east":10.1578865,
      "west":10.155078,
      "opacity":1.0,
      "level":0
   },...
]

This happens because when serializing it sees DataList as nested objects, since in order to access array, you do dataList.data.

The solution to your problem is to just replace DataList class with List<Data>:

Call<List<Data>> call = api.getMyJSON();
Daniel
  • 2,320
  • 1
  • 14
  • 27
2

You are doing a very basic mistake you have to update your interface according to your json as:

public interface DataApiService {

    @GET("/")
    Call<List<Data>> getMyJSON();
}

You are expecting the response and parsing it like this:

{
  "data": [
    { .. }
  ]
}

But Actual response is like this:

 [
    { .. }
 ]

Update:

In your error Expected BEGIN_ARRAY but was STRING at line 1 column 1, clearly means you are getting response this like as:

"[

  {
    ...
  }

 ]"

Instead of this:

 [

      {
        ...
      }

]

I have paste your Json in editor:

enter image description here

As you can see at the bottom left Ln: 1 Col: 1 and see the cursor at the start of Json which is here [, you are getting error because you expecting array like [{...}] but actual response is"[{...}]"

Just to prove my point update your interface like this:

public interface DataApiService {

    @GET("/")
    Call<String> getMyJSON();
}

You will not get the error.

More information can be found here

Muazzam A.
  • 647
  • 5
  • 17
  • I change my interface like you suggested: `public interface DataApiService { @GET("/") Call> getMyJSON(); }` but now I have the Exception : `java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING` – TheOldBlackbeard Sep 19 '19 at 07:16
  • 1
    @TheOldBlackbeard Can you please share your json. – Muazzam A. Sep 19 '19 at 07:21
  • and of course I also changed `private static List dataList; DataApiService api = DataRequestManager.getApiService(); Call> call = api.getMyJSON(); call.enqueue(new Callback>() { @Override public void onResponse(Call>call, Response>response) ` ecc. ecc. – TheOldBlackbeard Sep 19 '19 at 07:21
  • I wrote the JSON in the question – TheOldBlackbeard Sep 19 '19 at 07:24
  • 1
    @TheOldBlackbeard are you getting the Json like this "[ {...} ]" – Muazzam A. Sep 19 '19 at 07:29
  • @TheOldBlackbeard the error is in your Json currently the error you have clearly explains you are expecting an array but found String because the Json you are trying to parse is like this "[ {...} ]" it has to be like this [ {...} ] – Muazzam A. Sep 19 '19 at 07:34
  • I don't understand what do you mean, because actually is like like that [ {...} ]...or do you mean that I should change something in the code? – TheOldBlackbeard Sep 19 '19 at 07:39
  • @TheOldBlackbeard you don't have to change anything just ask the backend developer to look into that you are receiving response like this "[ {...} ]" instead of [ {...} ] – Muazzam A. Sep 19 '19 at 07:45
  • Just to prove my point update your interface like this: public interface DataApiService { @GET("/") Call getMyJSON(); } You will not get the error. – Muazzam A. Sep 19 '19 at 08:00
  • You were right. I also noticed that I forget to divide the link in Base URL and endpoint(path). So i put in baseUrl the Base URL and in the interface @GET("/api/data") and now I have a "Response{protocol=http/1.1, code=401, message=Unauthorized, " message...probably it could be the problem (because I needed an user and pass to access to the JSON)..but I don't know how to do that..i though that was enouth to use the ` httpClient.addInterceptor(logging);` . – TheOldBlackbeard Sep 19 '19 at 10:14
  • First check the API in PostMan and then call in your Android app – Muazzam A. Sep 19 '19 at 10:27
0

I found the solution! As the main problem was the authentication, I changed my Retrofit Client code as follows:

public class DataRequestManager {

    private static String baseUrl = "mylink";

    //Get Retrofit Instance
    private static Retrofit getRetrofitInstance(Context context) {

        OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();

        //Basic Auth
        String username="myUsername";
        String password="myPassword";
        String authToken = null;

        if (!TextUtils.isEmpty(username)
                && !TextUtils.isEmpty(password)) {
            authToken = Credentials.basic(username, password);
        }

        //Create a new Interceptor.
        final String finalAuthToken = authToken;
        Interceptor headerAuthorizationInterceptor = new Interceptor() {
            @Override
            public okhttp3.Response intercept(Chain chain) throws IOException {
                okhttp3.Request request = chain.request();
                Headers headers = request.headers().newBuilder().add("Authorization", finalAuthToken).build();
                request = request.newBuilder().headers(headers).build();
                return chain.proceed(request);
            }
        };

        //Add the interceptor to the client builder.
        clientBuilder.addInterceptor(headerAuthorizationInterceptor);

        return new Retrofit.Builder().baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .client(clientBuilder.build())
                .build();
    }

    //Get API Service
    public static FloorplansApiService getApiService(Context context) {
        return getRetrofitInstance(context).create(FloorplansApiService.class);
    }
}

and now it works! Thank you all guys!

TheOldBlackbeard
  • 395
  • 4
  • 22