简体   繁体   中英

JSON Parsing in Android using Retrofit with JsonSyntaxException

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 $

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();

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:

在此处输入图片说明

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

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM