【问题标题】:Reference parent object while deserializing a JSON using Gson使用 Gson 反序列化 JSON 时引用父对象
【发布时间】:2016-01-20 13:30:06
【问题描述】:

鉴于以下 JSON:

{
    "authors": [{
        "name": "Stephen King",
        "books": [{
            "title": "Carrie"
        }, {
            "title": "The Shining"
        }, {
            "title": "Christine"
        }, {
            "title": "Pet Sematary"
        }]
    }]
}

还有这个对象结构:

public class Author {
    private List<Book> books;
    private String name;
}

public class Book {
    private transient Author author;
    private String title;
}

有没有办法使用 Google Java 库 Gson 反序列化 JSON 并且书籍对象具有对“父”作者对象的引用?

是否可以不使用自定义反序列化程序?

  • 如果是:如何?
  • 如果不是:是否仍然可以使用自定义反序列化器来实现?

【问题讨论】:

  • Is it possible without using a custom deserializer? 考虑到 gson 反序列化的性质,我认为这是不可能的。 Is is still possible to do it with a custom deserializer? 是的,可以这样做。只需查找有关该部分的教程,stackoverflow 对此主题有几个问题和答案。
  • @Tezla 你能指点我一篇文章或一个stackoverflow来解释我如何实现这一点,因为我没有找到任何东西。这就是为什么我决定发布我的问题。这对我有很大帮助。

标签: java json gson deserialization


【解决方案1】:

在这种情况下,我将为父对象实现一个自定义 JsonDeserializer,并传播 Author 信息,如下所示:

public class AuthorDeserializer implements JsonDeserializer<Author> {
    @Override
    public Author deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        final JsonObject authorObject = json.getAsJsonObject();

        Author author = new Author();
        author.name = authorObject.get("name").getAsString();

        Type booksListType = new TypeToken<List<Book>>(){}.getType();
        author.books = context.deserialize(authorObject.get("books"), booksListType);

        for(Book book : author.books) {
            book.author = author;
        }

        return author;
    }   
}

请注意,我的示例省略了错误检查。你可以这样使用它:

Gson gson = new GsonBuilder()
    .registerTypeAdapter(Author.class, new AuthorDeserializer())
    .create();

为了展示它的工作原理,我只从你的示例 JSON 中提取了“作者”键,允许我这样做:

JsonElement authorsJson  = new JsonParser().parse(json).getAsJsonObject().get("authors");

Type authorList = new TypeToken<List<Author>>(){}.getType();
List<Author> authors = gson.fromJson(authorsJson, authorList);
for(Author a : authors) {
    System.out.println(a.name);
    for(Book b : a.books) {
        System.out.println("\t " + b.title + " by " + b.author.name);
    }
}

打印出来的:

Stephen King
     Carrie by Stephen King
     The Shining by Stephen King
     Christine by Stephen King
     Pet Sematary by Stephen King

【讨论】:

  • 就是这么简单!我怎么没想到。非常感谢
  • 但是,如果作者对象的字段数一样多,我不想手动映射它们怎么办。而且我不想每次更改 Author 对象时都更改反序列化器。你有什么建议?
  • @Thermech - 我不确定 GSON 有没有办法解决这个问题。您的另一个选择是进行默认反序列化,然后对结果进行后处理。您可以Author 创建一个构造函数,该构造函数接受JsonObject 并使用它来填充原始字段,将该逻辑保留在Author 类中。同样,您可以创建一个将所有原始类型作为参数的构造函数,这将强制您在对类进行更改时更新反序列化器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-23
  • 2017-07-31
  • 2014-10-06
  • 1970-01-01
  • 1970-01-01
  • 2021-12-08
  • 2016-09-27
相关资源
最近更新 更多