1

我有这个 JSON 正文:

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

我的pojoItem

@AutoValue
public abstract class PojoItem{

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

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

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

}

我的pojoItemList

@AutoValue
public abstract class PojoItemList{

    public abstract List< PojoItem > itemList();

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

我有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();
    }
}

我正在使用带有 RxJava 的 Retrofit。我得到了这个例外:

java.lang.IllegalStateException:应为 BEGIN_OBJECT 但为 BEGIN_ARRAY

如何设置我的 POJO 以将 JSON 读取为对象数组而不是集合?

4

3 回答 3

2

问题是您正在itemList为您的列表命名,该名称在响应中不存在。

改造应该使用这样的东西:

public class Item {

    @SerializedName("field1")
    public String field1;

    @SerializedName("id")
    public int id;

    @SerializedName("field2")
    public String field2;

}

然后,当您定义 Retrofit 的接口时,使用如下内容:

@GET("/path")
Single<List<Item>> getItems(); 
于 2017-02-15T08:16:15.147 回答
1

AutoValue Gson 不会为数组生成 Gson 类型适配器(至少从我从其源代码中看到的)。因此 Gson 需要一个 List 实例。请注意,您的列表数据模型与 Gson 默认值以及 AutoValue Gson 生成的内容冲突。你有两个解决方案。

解决方案1:不要使用PojoItemList

为什么:数组/列表不需要像itemsList(). 我不确定您是否会在PojoItemListexcept中获得任何其他自动生成的值itemList()List<PojoItem>真的足以让它发挥作用。因此,一个可有效处理列表的原始 Gson 代码:

final Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(AutoValueGsonFactory.create())
        .create();
final TypeToken<List<PojoItem>> pojoItemListTypeToken = new TypeToken<List<PojoItem>>() {
    };
out.println(gson.<List<PojoItem>>fromJson(JSON, pojoItemListTypeToken.getType()));

据我了解,Retrofit 会将类型传递给 Gson 本身,因此,您的 Retrofitted 服务不得PojoItemList在这种情况下使用,并使用List<PojoItem>

interface IService {

    List<PojoItem> getPojoItems();

}

请注意,您必须添加一个PojoItem可以由 AutoValue Gson 生成的类型适配器:

@AutoValue
public abstract class PojoItem {

    ...

    public static TypeAdapter<PojoItem> typeAdapter(final Gson gson) {
        return new AutoValue_PojoItem.GsonTypeAdapter(gson);
    }

}

如果没有生成并注册类型适配器,Gson 将无法创建PojoItem实例:

java.lang.RuntimeException:无法调用没有参数的公共 q42240399.PojoItem()

解决方案 2:自己做 AutoValue Gson 工作

如果出于某种原因你想使用PojoItemList,那么你必须编写你的自定义TypeAdapter,因为正如我上面提到的,AutoValue Gson 不会生成数组类型适配器(beginArray虽然我看不到任何调用)。

@AutoValue
public abstract class PojoItemList {

    public abstract List<PojoItem> itemList();

    public static TypeAdapter<PojoItemList> typeAdapter(final Gson gson) {
        // Get the original PojoItem type adapter you can use below
        final TypeAdapter<PojoItem> pojoItemTypeAdapter = gson.getAdapter(PojoItem.class);
        return new TypeAdapter<PojoItemList>() {
            @Override
            public void write(final JsonWriter out, final PojoItemList pojoItemList) {
                out.beginArray();
                for ( final PojoItem pojoItem : pojoItemList.itemList() ) {
                    pojoItemTypeAdapter.write(out, pojoItem);
                }
                out.endArray();
            }

            @Override
            public PojoItemList read(final JsonReader in)
                    throws IOException {
                final List<PojoItem> pojoItems = new ArrayList<>();
                // The first token must be [
                in.beginArray();
                // And read until ] is found
                while ( in.peek() != END_ARRAY ) {
                    // Delegate parsing to the PojoItem type adapter for each array element
                    pojoItems.add(pojoItemTypeAdapter.read(in));
                }
                // The last token must be ]
                in.endArray();
                // Construct the PojoItemList value
                return new AutoValue_PojoItemList(pojoItems);
            }
        };
    }

}

您可能想询问 AutoValue Gson 扩展作者以实现符合数组的扩展。但是,我认为解决方案#1 更好,原因有几个。

两种解决方案都有效并将产生:

  • 对于List<PojoItem>
[PojoItem{field1=10, id=0, field2=22}, PojoItem{field1=11, id=1, field2=23}]
  • 对于PojoItemList
PojoItemList{itemList=[PojoItem{field1=10, id=0, field2=22}, PojoItem{field1=11, id=1, field2=23}]}
于 2017-02-15T08:51:43.530 回答
0

我可以在有/没有 RxJava 的情况下让它工作 这里有两种方法:

为了清楚起见,我将提供用于实现该目标的 API 和完整的改造代码:

应用接口:

public interface AppApi {
    @GET("path/path")
    Observable<List<PojoItem>> getItemsbyRxJava();


    @GET("path/path")
    Call<List<PojoItem>> getItemsbyRetrofit();
}
  1. 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. 仅改造解决方案:

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

我希望这对某人有帮助

祝你好运,'。

于 2017-02-15T13:47:11.943 回答