Search code examples
javaandroidgsonauto-value

How to use AutoValue to parse JSON structured as an array of objects?


I have this JSON body:

[
    {
        "id": 0,
        "field1": "10",
        "field2": "22"
    },
    {
        "id": 1,
        "field1": "11",
        "field2": "23"
    }
]

My pojoItem:

@AutoValue
public abstract class PojoItem{

    @SerializedName("field1")
    public abstract String field1();

    @SerializedName("id")
    public abstract int id();

    @SerializedName("field2")
    public abstract String field2();

}

And my pojoItemList:

@AutoValue
public abstract class PojoItemList{

    public abstract List< PojoItem > itemList();

    public static TypeAdapter<PojoItemList> typeAdapter(Gson gson) {
        return new AutoValue_PojoItemList.GsonTypeAdapter(gson);
    }
}

I have AutoValueGsonFactory:

@GsonTypeAdapterFactory
public abstract class AutoValueGsonFactory implements TypeAdapterFactory {

    // Static factory method to access the package
    // private generated implementation
    public static TypeAdapterFactory create() {
        return new AutoValueGson_AutoValueGsonFactory();
    }
}

I'm using Retrofit with RxJava. I got this exception:

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY

How can I setup my POJO to read JSON as an array of objects not as collection?


Solution

  • I could make it work by the end with/without RxJava Here are two ways:

    To make it clear I will provide API and complete Retrofit code used to achieve that goal:

    AppApi:

    public interface AppApi {
        @GET("path/path")
        Observable<List<PojoItem>> getItemsbyRxJava();
    
    
        @GET("path/path")
        Call<List<PojoItem>> getItemsbyRetrofit();
    }
    
    1. Solution with RxJava:

      GsonConverterFactory gsonConverterFactory = GsonConverterFactory.create(new GsonBuilder().registerTypeAdapterFactory(AutoValueGsonFactory.create()).create());
      OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
      Retrofit retrofitClient = new Retrofit.Builder()
              .baseUrl("http://[domain]/path/")
              .addConverterFactory(gsonConverterFactory)
              .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
              .client(httpClient.build())
              .build();
      
      AppApi appApi = retrofitClient.create(AppApi.class);
      
      appApi.getItemsbyRxJava()
              .subscribeOn(Schedulers.computation())
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe(new Subscriber<List<PojoItem>>() {
                  @Override
                  public void onCompleted() {
                      Log.d(TAG, "completed");
                  }
      
                  @Override
                  public void onError(Throwable e) {
                      Log.e(TAG, e.getMessage());
                  }
      
                  @Override
                  public void onNext(List<PojoItem> list) {
                      for (PojoItem pojoItem : list) {
                          Log.d(TAG, pojoItem.field1() + "," + pojoItem.field2());
                      }
                  }
              });
      
    2. Solution with Retrofit only:

      OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
      Retrofit retrofitClient = new Retrofit.Builder()
              .baseUrl("http://[domain]/path/")
              .addConverterFactory(GsonConverterFactory.create())
              .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
              .client(httpClient.build())
              .build();
      AppApi appApi = retrofitClient.create(AppApi.class);
      Call<List<PojoItem>> call = appApi.getItemsbyRetrofit();
      call.enqueue(new Callback<List<PojoItem>>() {
          @Override
          public void onResponse(Call<List<PojoItem>> call, Response<List<PojoItem>> response) {
              for (PojoItem pojoItem : response.body()) {
                  Log.d(TAG, pojoItem.field1() + "," + pojoItem.field2());
              }
          }
      
          @Override
          public void onFailure(Call<List<PojoItem>> call, Throwable t) {
              Log.e(TAG, t.getMessage());
          }
      });
      

    I hope that would be helpful to someone

    Good luck,'.