繁体   English   中英

如何使用 Gson、Retrofit、Active Android 将嵌套的 JSON 对象反序列化为字符串

[英]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"
  }]
}

明智的方法是在AuthorArticle类之间使用有很多关系,但是作者没有被保存到数据库中,因为他们在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 作为ArticleAuthor之间的关系可能更有意义,ActiveAndroid 不支持这种关系并且需要一个连接表,如 github 上的这个问题中所述

一种可能的解决方案。

  1. 只需将字段声明为 Object,然后 Gson 会将其反序列化为LinkedTreeMap

  2. 尝试将 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM