簡體   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