How to parse list of JSON objects surrounded by [] using Retrofit and GSON? How to parse list of JSON objects surrounded by [] using Retrofit and GSON? json json

How to parse list of JSON objects surrounded by [] using Retrofit and GSON?


Recently I just finish one project related to retrofit2. Based on my source, I copy all your stuff into my project to give a try, making some minor change, it works well on my side.

In your build.gradle, add those:

 compile 'com.squareup.retrofit2:retrofit:2.0.1' compile 'com.google.code.gson:gson:2.6.2' compile 'com.squareup.okhttp3:okhttp:3.1.2' compile 'com.squareup.retrofit2:converter-gson:2.0.1' compile 'com.squareup.okhttp3:logging-interceptor:3.2.0'

Model: (UPDATE: Follow tommus's case, createdAt and updatedAt is now shown in his json response sample, these two values needs annotation due to the name in the model is different from json respone)

public class Size {    private int id;    private String name;    private boolean active;    @SerializedName("created_at")    private String createdAt;    @SerializedName("updated_at")    private String updatedAt;}

Service: (Exactly same as what you have)

public interface service {    @GET("sizes")    Call<List<Size>> loadSizes();    }

RestClient: (I add log here, so that you can see all the request info and response info, be careful not using Localhost but your server ip address in the URL )

import com.google.gson.Gson;import com.google.gson.GsonBuilder;import com.xiaoyaoworm.prolificlibrary.test.Service;import okhttp3.OkHttpClient;import okhttp3.logging.HttpLoggingInterceptor;import retrofit2.Retrofit;import retrofit2.converter.gson.GsonConverterFactory;public class RestClient {    private static Service service;    public static Service getClient() {        if (service == null) {            Gson gson = new GsonBuilder()                    .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")                    .create();            // Add logging into retrofit 2.0            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();            logging.setLevel(HttpLoggingInterceptor.Level.BODY);            OkHttpClient.Builder httpClient = new OkHttpClient.Builder();            httpClient.interceptors().add(logging);            Retrofit retrofit = new Retrofit.Builder()                    .baseUrl("http://YOURSERVERIPNOTLOCALHOST:3000/")                    .addConverterFactory(GsonConverterFactory.create(gson))                    .client(httpClient.build()).build();            service = retrofit.create(Service.class);        }        return service;    }}

On your activity, add this function to run your code: (exactly same as what you have done. The response will be your list of size)

   private void loadSize() {        Service serviceAPI = RestClient.getClient();        Call<List<Size>> loadSizeCall = serviceAPI.loadSizes();        loadSizeCall.enqueue(new Callback<List<Size>>() {            @Override            public void onResponse(Call<List<Size>> call, Response<List<Size>> response) {                for(Size size: response.body()) {                    System.out.println(size.toString());                }            }            @Override            public void onFailure(Call<List<Size>> call, Throwable t) {                System.out.println(t.getMessage());            }        });    }

Running this you will see the info you want to print out:enter image description here

Here is my github repo which I use retrofit2.0 to make simple GET POST PUT DELETE work. You can use this as reference. My Github retrofit2.0 repo


Please use the following:

build.gradle file:

dependencies {    ...    compile 'com.squareup.retrofit2:retrofit:2.0.1'    compile 'com.squareup.retrofit2:converter-gson:2.0.1'    compile 'com.google.code.gson:gson:2.6.2'}

WebAPIService.java:

public interface WebAPIService {    @GET("/json.txt") // I use a simple json file to get the JSON Array as yours    Call<JsonArray> readJsonArray();}

Size.java:

public class Size {    @SerializedName("id")    private int id;    @SerializedName("name")    private String name;    @SerializedName("active")    private boolean active;    @SerializedName("created_At")    private String createdAt;    @SerializedName("updated_at")    private String updatedAt;}

MainActivity.java:

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    Retrofit retrofit = new Retrofit.Builder()            .baseUrl("http://...")            .addConverterFactory(GsonConverterFactory.create())            .build();    WebAPIService service = retrofit.create(WebAPIService.class);    Call<JsonArray> jsonCall = service.readJsonArray();    jsonCall.enqueue(new Callback<JsonArray>() {        @Override        public void onResponse(Call<JsonArray> call, Response<JsonArray> response) {            String jsonString = response.body().toString();            Log.i("onResponse", jsonString);            Type listType = new TypeToken<List<Size>>() {}.getType();            List<Size> yourList = new Gson().fromJson(jsonString, listType);            Log.i("onResponse", yourList.toString());        }        @Override        public void onFailure(Call<JsonArray> call, Throwable t) {            Log.e("onFailure", t.toString());        }    });}

Here is the debug screenshot:

enter image description here


UPDATE:You can also use the following option:

@GET("/json.txt")Call<List<Size>> readList();

and

    Call<List<Size>> listCall1 = service.readList();    listCall1.enqueue(new Callback<List<Size>>() {        @Override        public void onResponse(Call<List<Size>> call, Response<List<Size>> response) {            for (Size size : response.body()){                Log.i("onResponse", size.toString());            }        }        @Override        public void onFailure(Call<List<Size>> call, Throwable t) {            Log.e("onFailure", t.toString());        }    });


The funny fact is... My code is perfectly fine. At least the one presented in the question above.

I've ended up removing one line from my Size model.

As I focused on the code itself (especially Retrofit's configuration) I've totally ignored imports.

It turned out - while implementing Size model when I've started typing String class for model's fields:

  • name
  • createdAt
  • updatedAt

IntelliJ IDEA's code completion suggested me

  • not java.lang.String
  • but com.sun.org.apache.xpath.internal.operations.String

what totally messed up Gson's deserialization.

When it comes to rewards...

I've decided to mark as valid my own answer. Why?

  • To ensure that, every of those developers, who will come with exactly same trouble as me - make sure you have valid imports.

Many thanks goes to gentlmen above for their great services.

As I have only one bounty I've decided reward xiaoyaoworm as his code better match my needs (I haven't written it in my question but the idea of writing such simple service - as I've presented in my question - is to hide from the end-user implementation details and not use JsonArray and such like in BNK response).

Update 1:

The only problem with xiaoyaoworm's answer is that, he suggested the Size model do not need any annotations what is totally wrong for the quoted JSON example.

For above case, exact two fields of the Size model needs annotations - created_at and updated_at.

I've even tested few versions of the converter-gson library (I saw xiaoyaoworm have used other than me) - it hasn't changed anything. Annotations were necessary.

Otherwise - again, many thanks!