我正在努力使用TypeAdapter。实际上,对于json字段,我可以有一个Array(当它为空时)或一个Object(当它不为空时)。这不能改变。
以下是收到的JSON:
{
"notifications": [
{
...
}
],
"meta": {
"pagination": {
"total": 13,
"count": 13,
"per_page": 20,
"current_page": 1,
"total_pages": 1,
"links": []
}
}
}
相关字段为links
,因为您可以看到该字段位于pagination
内meta
。这就是我的问题,我不知道TypeAdapter如何在两个深度级别处理links
。
我使用此reply开始构建解决方案。这是:
我的自定义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;
}
}
My Pagination课程:
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 gson = new GsonBuilder().registerTypeAdapter(Pagination.class, new PaginationTypeAdapter()).create();
现在我的错误是:com.google.gson.JsonParseException: Unexpected token NAME
所以我知道我做得不对,因为我正在用分页来构建我的Gson。但我不知道应该如何处理。使用带有meta
的TypeAdapter?
欢迎任何帮助,谢谢!
答案 0 :(得分:1)
当您实现自定义类型适配器时,请确保您的类型适配器具有平衡的令牌读写:如果您打开复合令牌对(如[
和]
),则必须将其关闭(适用于JsonWriter
和JsonReader
)。您只是不需要这一行来解决您的问题:
jsonReader.beginObject();
因为它将JsonReader
实例移动到下一个标记,因此BEGIN_OBJECT
之后的下一个标记是NAME
或END_OBJECT
(前者在您的情况下确定)。
我建议不要使用临时Gson
对象实例 - 这不会在Gson
实例之间共享配置(例如,您的&#34;全局&#34; Gson
注册了很多自定义适配器,但是这个内部没有任何自适应,因此你的(反)序列化结果可能会非常意外。为了克服这一点,只需使用比{&#34; free&#34;更具上下文感知能力的TypeAdapterFactory
。 Gson
实例。
final class PaginationTypeAdapterFactory
implements TypeAdapterFactory {
private static final TypeAdapterFactory paginationTypeAdapterFactory = new PaginationTypeAdapterFactory();
private PaginationTypeAdapterFactory() {
}
static TypeAdapterFactory getPaginationTypeAdapterFactory() {
return paginationTypeAdapterFactory;
}
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// Classes can be compared using == and !=
if ( typeToken.getRawType() != Pagination.class ) {
// Not Pagination? Let Gson pick up the next best-match
return null;
}
// Here we get the references for two types adapters:
// - this is what Gson.fromJson does under the hood
// - we save some time for the further (de)serialization
// - you classes should not ask more than they require
final TypeAdapter<Links> linksTypeAdapter = gson.getAdapter(Links.class);
final TypeAdapter<Links[]> linksArrayTypeAdapter = gson.getAdapter(Links[].class);
@SuppressWarnings("unchecked")
final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) new PaginationTypeAdapter(linksTypeAdapter, linksArrayTypeAdapter);
return typeAdapter;
}
private static final class PaginationTypeAdapter
extends TypeAdapter<Pagination> {
private final TypeAdapter<Links> linksTypeAdapter;
private final TypeAdapter<Links[]> linksArrayTypeAdapter;
private PaginationTypeAdapter(final TypeAdapter<Links> linksTypeAdapter, final TypeAdapter<Links[]> linksArrayTypeAdapter) {
this.linksTypeAdapter = linksTypeAdapter;
this.linksArrayTypeAdapter = linksArrayTypeAdapter;
}
@Override
public void write(final JsonWriter out, final Pagination pagination)
throws IOException {
linksTypeAdapter.write(out, pagination.links);
}
@Override
public Pagination read(final JsonReader in)
throws IOException {
final JsonToken token = in.peek();
// Switches are somewhat better: you can let your IDE or static analyzer to check if you covered ALL the cases
switch ( token ) {
case BEGIN_ARRAY:
return new Pagination(linksArrayTypeAdapter.read(in));
case BEGIN_OBJECT:
return new Pagination(linksTypeAdapter.read(in));
case END_ARRAY:
case END_OBJECT:
case NAME:
case STRING:
case NUMBER:
case BOOLEAN:
case NULL:
case END_DOCUMENT:
// MalformedJsonException, not sure, might be better, because it's an IOException and the read method throws IOException
throw new MalformedJsonException("Unexpected token: " + token + " at " + in);
default:
// Maybe some day Gson adds something more here... Let be prepared
throw new AssertionError(token);
}
}
}
}
您可以使用private Links links;
对@JsonAdapter
进行注释,并将类型适配器工厂直接绑定到链接:Gson
将&#34;注入&#34; links
直接反对Pagination
个实例,因此您甚至不需要构造函数。