在Android上使用TypeAdapter对数组或对象进行改造,深度为两级
我正在努力使用TypeAdapter。实际上,对于json字段,我可以有一个数组(当它为空时)或一个对象(当它不为空时)。这是无法改变的 以下是收到的JSON:在Android上使用TypeAdapter对数组或对象进行改造,深度为两级,android,gson,retrofit2,Android,Gson,Retrofit2,我正在努力使用TypeAdapter。实际上,对于json字段,我可以有一个数组(当它为空时)或一个对象(当它不为空时)。这是无法改变的 以下是收到的JSON: { "notifications": [ { ... } ], "meta": { "pagination": { "total": 13, "count": 13, "
{
"notifications": [
{
...
}
],
"meta": {
"pagination": {
"total": 13,
"count": 13,
"per_page": 20,
"current_page": 1,
"total_pages": 1,
"links": []
}
}
}
相关字段是链接
,您可以看到该字段位于分页
中,该字段位于元
中。这就是我的问题,我不知道TypeAdapter如何处理两个深度级别的链接
我用它开始构建一个解决方案。这是:
我的自定义TypeAdapter类:
public class PaginationTypeAdapter extends TypeAdapter<Pagination> {
private Gson gson = new Gson();
@Override
public void write(JsonWriter out, Pagination pagination) throws IOException {
gson.toJson(pagination, Links.class, out);
}
@Override
public Pagination read(JsonReader jsonReader) throws IOException {
Pagination pagination;
jsonReader.beginObject();
if (jsonReader.peek() == JsonToken.BEGIN_ARRAY) {
pagination = new Pagination((Links[]) gson.fromJson(jsonReader, Links[].class));
} else if(jsonReader.peek() == JsonToken.BEGIN_OBJECT) {
pagination = new Pagination((Links) gson.fromJson(jsonReader, Links.class));
} else {
throw new JsonParseException("Unexpected token " + jsonReader.peek());
}
return pagination;
}
}
目前我的错误是:com.google.gson.JsonParseException:Unexpected-token-NAME
所以我知道我做得不对,因为我在用分页构建我的Gson。但我不知道该怎么处理。使用带有meta
的TypeAdapter
欢迎任何帮助,谢谢 当您实现自定义类型适配器时,请确保您的类型适配器具有均衡的令牌读写:如果您打开一个类似于[
和]
的复合令牌对,则必须将其关闭(同时适用于JsonWriter
和JsonReader
)。您不需要这一行来解决您的问题:
jsonReader.beginObject();
因为它将JsonReader
实例移动到下一个令牌,所以BEGIN\u OBJECT
之后的下一个令牌要么是NAME
要么是END\u OBJECT
(在您的情况下肯定是前者)
备选方案#1
我还建议不要使用特别的Gson
对象安装——这不会在Gson
实例之间共享配置(例如,您的“全局”Gson
注册了许多自定义适配器,但此内部适配器没有任何配置,因此您的(反)序列化结果可能非常意外)。为了克服这个问题,只需使用比“免费”Gson实例更能感知上下文的TypeAdapterFactory
final类分页TypeAdapterFactory
实现TypeAdapterFactory{
私有静态最终类型适配器工厂paginationTypeAdapterFactory=新paginationTypeAdapterFactory();
专用分页TypeAdapterFactory(){
}
静态TypeAdapterFactory getPaginationTypeAdapterFactory(){
返回paginationTypeAdapterFactory;
}
@凌驾
公共类型适配器创建(最终Gson Gson、最终TypeToken TypeToken){
//类可以使用==和进行比较=
if(typeToken.getRawType()!=Pagination.class){
//不分页?让格森挑选下一个最佳匹配
返回null;
}
//这里我们获得了两种类型适配器的引用:
//-这就是Gson.fromJson在引擎盖下的作用
//-我们为进一步(反)序列化节省了一些时间
//-您的课程要求不得超过其要求
最终类型适配器linksTypeAdapter=gson.getAdapter(Links.class);
final-TypeAdapter-linksArrayTypeAdapter=gson.getAdapter(Links[].class);
@抑制警告(“未选中”)
final TypeAdapter TypeAdapter=(TypeAdapter)新分页TypeAdapter(linksTypeAdapter,linksArrayTypeAdapter);
返回类型适配器;
}
私有静态最终类PaginationTypeAdapter
扩展类型适配器{
专用最终类型适配器链接类型适配器;
专用最终类型适配器链接RayTypeAdapter;
专用分页类型适配器(最终类型适配器链接StypeAdapter,最终类型适配器链接RayTypeAdapter){
this.linksTypeAdapter=linksTypeAdapter;
this.linksArrayTypeAdapter=linksArrayTypeAdapter;
}
@凌驾
公共无效写入(最终JsonWriter out、最终分页分页)
抛出IOException{
linksTypeAdapter.write(out,pagination.links);
}
@凌驾
公共分页读取(中的最终JsonReader)
抛出IOException{
最终JsonToken标记=in.peek();
//开关更好一些:您可以让IDE或静态分析器检查是否涵盖了所有情况
交换机(令牌){
案例开始\u数组:
返回新分页(linksArrayTypeAdapter.read(in));
案例开始对象:
返回新分页(linksTypeAdapter.read(in));
案例结束单元阵列:
案例结束对象:
案例名称:
大小写字符串:
案件编号:
大小写布尔值:
大小写为空:
案例结束文件:
//MalformedJsonException(不确定)可能更好,因为它是一个IOException,read方法抛出IOException
抛出新的MalformedJsonException(“意外标记:“+token+”位于“+in”);
违约:
//也许有一天,格森会在这里添加更多的东西……让我们做好准备
抛出新断言错误(令牌);
}
}
}
}
备选方案#2
你可以注释你的
私人链接使用@JsonAdapter
编码>并将类型适配器工厂直接绑定到链接:Gson
将links
对象直接“注入”到Pagination
实例,因此您甚至不需要在那里使用构造函数。在这里签出以了解如何处理Awesome!!只需删除一行代码就可以了。我应该更清楚TypeAdapter是如何工作的。非常感谢你的帮助。我也会检查您的备选方案:)
public class Pagination {
private int total;
private int count;
@SerializedName("per_page")
private int perPage;
@SerializedName("current_page")
private int currentPage;
@SerializedName("total_pages")
private int totalPages;
private Links links;
Pagination(Links ... links) {
List<Links> linksList = Arrays.asList(links);
this.links = linksList.get(0);
}
}
Gson gson = new GsonBuilder().registerTypeAdapter(Pagination.class, new PaginationTypeAdapter()).create();