基 class 的 Gson 自定义反序列化器
Gson custom deserializer for base class
我需要使用 REST API 并且我正在使用 Gson,如果我的模型中的几十个 类 不需要自定义 Gson 反序列化器,那就太好了。
我认为我应该使用自定义 TypeAdapterFactory,但文档很差,我很难过。
我感兴趣的 类 或多或少遵循以下模式:
public class APIResource {
@SerializedName("id")
private Integer id;
//Constructor and getter
}
public class B extends APIResource {
@SerializedName("field")
String field;
@SerializedName("resources")
List<APIResource> resourceList;
//Constructor and getter
}
public class C extends B {
@SerializedName("other_fields")
List<Object> otherFieldList;
@SerializedName("resource")
APIResource resource;
@SerializedName("b_list")
List<B> bList;
//Constructor and getter
}
有时 id
作为一个名为 "url"
的字符串包含在 JSON 中,我必须对其进行解析。
JSON非常复杂,包含多个对象和数组,它们的结构几乎是随机的。
"url"
名称可以在 JSON 中的任何位置,我无法使用 beginObject()
和 beginArray()
使其工作
我认为我的自定义 TypeAdapterFactory 应该是这样的
public class ResourceTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, @NonNull TypeToken<T> type) {
if (!APIResource.class.isAssignableFrom(type.getRawType())) {
return null;
}
TypeAdapter<T> defaultTypeAdapter = gson.getDelegateAdapter(this, type);
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
defaultTypeAdapter.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
//if the name is "url" use the urlToId method, else
return defaultTypeAdapter.read(in);
}
}.nullSafe();
}
Integer urlToId(String url) {
Matcher matcher = Pattern
.compile("/-?[0-9]+/$")
.matcher(url);
return matcher.find() ?
Integer.valueOf(matcher.group().replace("/","")):
null;
}
}
我解决了,如果有人遇到同样的问题,这就是我的解决方案
public class ResourceTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, @NonNull TypeToken<T> type) {
if (!APIResource.class.isAssignableFrom(type.getRawType())) {
return null;
}
final TypeAdapter<T> delegateAdapter = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
delegateAdapter.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
JsonElement tree = elementAdapter.read(in);
afterRead(tree);
return delegateAdapter.fromJsonTree(tree);
}
protected void afterRead(@NonNull JsonElement jsonElement) {
if(jsonElement instanceof JsonObject) {
JsonObject jsonObject = ((JsonObject)jsonElement);
for(Map.Entry<String,JsonElement> entry : jsonObject.entrySet()){
if(entry.getValue() instanceof JsonPrimitive) {
if(entry.getKey().equalsIgnoreCase("url")) {
String val = jsonObject.get(entry.getKey()).toString();
jsonObject.addProperty("id", urlToId(val));
}
} else {
afterRead(entry.getValue());
}
}
}
}
}.nullSafe();
}
Integer urlToId(@NonNull String url) {
Matcher matcher = Pattern
.compile("/-?[0-9]+/$")
.matcher(url.replace("\"", ""));
return matcher.find() ?
Integer.valueOf(matcher.group().replace("/","")):
null;
}
}
我需要使用 REST API 并且我正在使用 Gson,如果我的模型中的几十个 类 不需要自定义 Gson 反序列化器,那就太好了。
我认为我应该使用自定义 TypeAdapterFactory,但文档很差,我很难过。
我感兴趣的 类 或多或少遵循以下模式:
public class APIResource {
@SerializedName("id")
private Integer id;
//Constructor and getter
}
public class B extends APIResource {
@SerializedName("field")
String field;
@SerializedName("resources")
List<APIResource> resourceList;
//Constructor and getter
}
public class C extends B {
@SerializedName("other_fields")
List<Object> otherFieldList;
@SerializedName("resource")
APIResource resource;
@SerializedName("b_list")
List<B> bList;
//Constructor and getter
}
有时 id
作为一个名为 "url"
的字符串包含在 JSON 中,我必须对其进行解析。
JSON非常复杂,包含多个对象和数组,它们的结构几乎是随机的。
"url"
名称可以在 JSON 中的任何位置,我无法使用 beginObject()
和 beginArray()
我认为我的自定义 TypeAdapterFactory 应该是这样的
public class ResourceTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, @NonNull TypeToken<T> type) {
if (!APIResource.class.isAssignableFrom(type.getRawType())) {
return null;
}
TypeAdapter<T> defaultTypeAdapter = gson.getDelegateAdapter(this, type);
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
defaultTypeAdapter.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
//if the name is "url" use the urlToId method, else
return defaultTypeAdapter.read(in);
}
}.nullSafe();
}
Integer urlToId(String url) {
Matcher matcher = Pattern
.compile("/-?[0-9]+/$")
.matcher(url);
return matcher.find() ?
Integer.valueOf(matcher.group().replace("/","")):
null;
}
}
我解决了,如果有人遇到同样的问题,这就是我的解决方案
public class ResourceTypeAdapterFactory implements TypeAdapterFactory {
@Override
public <T> TypeAdapter<T> create(Gson gson, @NonNull TypeToken<T> type) {
if (!APIResource.class.isAssignableFrom(type.getRawType())) {
return null;
}
final TypeAdapter<T> delegateAdapter = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
delegateAdapter.write(out, value);
}
@Override
public T read(JsonReader in) throws IOException {
JsonElement tree = elementAdapter.read(in);
afterRead(tree);
return delegateAdapter.fromJsonTree(tree);
}
protected void afterRead(@NonNull JsonElement jsonElement) {
if(jsonElement instanceof JsonObject) {
JsonObject jsonObject = ((JsonObject)jsonElement);
for(Map.Entry<String,JsonElement> entry : jsonObject.entrySet()){
if(entry.getValue() instanceof JsonPrimitive) {
if(entry.getKey().equalsIgnoreCase("url")) {
String val = jsonObject.get(entry.getKey()).toString();
jsonObject.addProperty("id", urlToId(val));
}
} else {
afterRead(entry.getValue());
}
}
}
}
}.nullSafe();
}
Integer urlToId(@NonNull String url) {
Matcher matcher = Pattern
.compile("/-?[0-9]+/$")
.matcher(url.replace("\"", ""));
return matcher.find() ?
Integer.valueOf(matcher.group().replace("/","")):
null;
}
}