[英]How do I parse a field from a deep nested json object using Gson and retrofit in android?
[英]How to deserialize a nested JSON object as a String with Gson, Retrofit, Active Android
我正在使用 ActiveAndroid 来缓存来自 Retrofit 网络调用的响应。
我做了一个看起来像的课程:-
class Article extends Model {
@Column(name = "title")
@SerializedName("title")
@Expose
public String title;
@Column(name = "authors")
@SerializedName("authors")
@Expose
private String authors;
}
相应的 JSON 类似于:-
{
"title":"Some title",
"authors": [{
"name": "Name",
"twitter":"@whatever"
}]
}
明智的方法是在Author
和Article
类之间使用有很多关系,但是作者没有被保存到数据库中,因为他们在Article
类中没有@Expose
注释(甚至变量),并且没有办法拥有该注释,因为有很多调用将是一个返回List<Author>
的方法调用。
// This will not work
@Expose
public List<Author> authors() {
return getMany(Author.class, "Article");
}
所以我认为的另一种方法是将 JSON 对象作为字符串存储在数据库中并序列化/反序列化以供访问。
这要求我让authors
变量成为List<Author>
类,并为其提供 类型序列化程序。
这种方法的问题是我无法知道正在保存到数据库中的 Generic 类型。 我不能返回List<Author>
类型,因为就像作者一样,在整个 JSON 中有更多的 JSON 数组。
所以我想到的最终解决方案是将其存储为字符串,将其视为字符串并制作一种反序列化以供访问的方法。 像这样 :-
private List<Author> _authors;
public List<Author> authors() {
if (_authors == null) {
Gson gson = ServiceGenerator.gsonBuilder.create();
Type type = new TypeToken<List<Author>>(){}.getType();
_authors = gson.fromJson(authors, type);
}
return _authors;
}
但是当我尝试这样做时,GSON 会抛出一个错误:-
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY
基本上是说我试图将 JSON 数组视为字符串。
所以我的问题是如何使用 GSON 转换器将一些 JSON 数组视为字符串。
我正在使用的 Retrofit Builder 是:-
public static final GsonBuilder gsonBuilder = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.excludeFieldsWithoutExposeAnnotation();
private static final Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gsonBuilder.create()));
谢谢参观!
如果有人仍然想将嵌套对象保留为字符串,那么您可以对应该保留字符串的字段使用 @JsonAdapter 注释。
@JsonAdapter(RawStringTypeAdapter.class)
private String Authors;
和 RawStringTypeAdapter:
public final class RawStringTypeAdapter<T>
implements JsonDeserializer<T> {
private RawStringTypeAdapter() {
}
@Override
public T deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
return (T) jsonElement.toString();
}
}
你可以使用 JsonDeserializer,在文章中注册
public class ArticleDeserializer implements JsonDeserializer<Article> {
@Override
public Article deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
throws JsonParseException {
Article article = context.deserialize(json, Article.class);
JsonArray authors = json.getAsJsonObject().getAsJsonArray("authors");
// convert authors as string and set it to artile
return article;
}
你必须将它注册到 gson
gsonBuilder.registerTypeHierarchyAdapter(Article.class, new ArticleDeseriazer())
Blackbelt 所说的,用于存储为字符串。
明智的做法是先创建一个Author
类,然后再创建一个 1:n。 据我了解,编写关系数据是手动的,所以你在保存Article
时必须自己保存关系。 所以假设你有Author
类
@Table(name = "Authors")
public class Author extends Model {
@Column(name = "Name")
public String name;
@Column(name = "Twitter")
public String twitter;
}
和领域
private List<Author> authors;
在Article
类中,你会像这样保存作者
article.save();
for (author: Author in arcticle.authors) {
author.article = article;
author.save();
}
然后您可以添加用于访问Article
的作者的方法,如文档所示:
public List<Author> getAuthors() {
return getMany(Author.class, "Author");
}
因此,GSON 将作者存储在字段作者中,保存作者时会插入到他们自己的表中,并且getAuthors()
从数据库中读取它们。
注意: m:n 作为Article
和Author
之间的关系可能更有意义,ActiveAndroid 不支持这种关系并且需要一个连接表,如 github 上的这个问题中所述
一种可能的解决方案。
只需将字段声明为 Object,然后 Gson 会将其反序列化为LinkedTreeMap
尝试将 LinkedTreeMap 转换为 JsonObject,如下所示
LinkedTreeMap<?,?> yourMap = ...; JsonObject jsonObject = gson.toJsonTree(yourMap).getAsJsonObject();
使用自定义JsonDeserializer<Article>
覆盖标准操作。 对关键authors
调用toString()
public class CustomDeserializer implements JsonDeserializer<Article> {
@Override
public Article deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if(json.isJsonObject()) {
JsonObject jsonObj = json.getAsJsonObject();
Article item = context.deserialize(json, Article.class);
if(jsonObj.has("authors")) {
item.setAuthors(jsonObj.get("authors").toString());
}
return item;
}
return null;
}
}
并注册自定义解串器
Gson gson = new GsonBuilder().registerTypeAdapter(Article.class, new CustomDeserializer()).create();
并且不要忘记使用@Expose
注释或addDeserializationExclusionStrategy()
从 gson 反序列化中排除关键作者
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.