当前位置: 首页 > 知识库问答 >
问题:

GSON:在反序列化时删除不必要的父对象

舒浩邈
2023-03-14

我正在尝试使用GSON反序列化JSON数组。我的所有嵌套对象都嵌入到“嵌入”对象中。

{
    "Book": {
        "name": "Book 1",
        "published": 1999,
        "links": {
          "url": "www.book1.com"
        },
        "embedded": {
            "Author": {
                "name": "John Doe",
                "links": {
                    "url": "www.johndoe.com"
                }
            }
        }
    }
}

我也可能遇到这样的情况:

{
    "Book": {
        "name": "Book 1",
        "published": 1999,
        "links": {
          "url": "www.book1.com"
        },
        "embedded": {
            "Publisher": {
                "name": "Publishing Company",
                "links": {
                    "url": "www.publishingcompany.com"
                }
            }
        }
    }
}

这是一个极其简单的例子。我的一些对象可能嵌套了2或3层深,并且都在一个“嵌入式”对象中。此外,每个对象在“链接”对象内都有一个嵌套的“网址”。我有大约20个不同的模型对象,每个都有几个字段,每个都有“嵌入”对象。我开始为每个模型编写自定义反序列化器,但这似乎忽略了使用gson的全部意义,而且我可能并不总是知道嵌入的对象是什么。

我找到了这个答案,但它是用于序列化对象的。我已经试着弄明白这一点有一段时间了,但还没有找到任何有效的方法。

我的图书模型如下所示:

public class Book {
    String name;
    int published;
    String url;
    Author author;
    Publisher publisher;
}

作者类别:

public class Author {
    String name;
    String url;
}

出版商类别:

public class Publisher {
    String name;
    String url;
}

以下是我目前为止的图书反序列化程序:

public class BookDeserializer implements JsonDeserializer<Book> {
    @Override
    public Book deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        final JsonObject jsonObject = json.getAsJsonObject();

        Book book = new Book();
        book.setName(jsonObject.get("name").getAsString());
        book.setPublished(jsonObject.get("published").getAsInt());
        String url = jsonObject.getAsJsonObject("links").get("url").getAsString();
        book.setUrl(url);

        // 1) How to get rid of this and skip to the "real" nested object?
        final JsonObject embeddedObject = jsonObject.getAsJsonObject("embedded");

        // 2) See what the "embedded" object actually is.
        String embeddedModel;
        Set<Map.Entry<String, JsonElement>> entrySet = embeddedObject.entrySet();
        for (Map.Entry<String, JsonElement> entry : entrySet) {

            // Author or Publisher
            embeddedModel = entry.getKey();
        }

        // We have the model's key, now add code here to deserialize whatever the object is

        return book;
    }
}

我仍然需要解析json并为Book设置每个字段。然后,我必须添加代码来确定并使用嵌套对象的正确反序列化器。看起来我仍然需要为每个对象定制一个反序列化程序来获取“url”。我对gson还比较陌生,所以可能我忽略了一些东西,但似乎我也可以手动解析所有的json,甚至不使用html" target="_blank">gson。也许有办法让json变得更简单?

有没有关于如何解析它并仍然使用gson的便利性的想法,或者这是可能的?也许杰克逊能处理得更好?

共有3个答案

欧阳杰
2023-03-14

我想你在找这样的东西:扁平化

该工具可以帮助您省略一些嵌入式类。您将拥有更少的类和更干净的代码。在你的书本课上,使用以下方法:

@Flatten("embedded::Author")
private Author author;

这样你可以折叠一层。同样的方式,你可以移动链接到作者。在你的作者课上:

@Flatten("links::url")
private String url;

如果你想走得更深,你可以用同样的方法再高两层。例如:

@Flatten("embedded::Author::name")
private String authorName;

在这里,您将在Book类中拥有作者的姓名。

希望有帮助。

孟海
2023-03-14

我的第一个想法是解析JSON并对其进行破解,但看起来GSONJsonObjects是不可变的。

因此,我将编写一个简单的流解析器,查找嵌入的”:{“链接”:{并删除它们。也运行一个简单的括号计数器来删除匹配的右括号。如果时间允许,我可能会把一个放在一起。

顺便说一句,您的示例JSON缺少一个逗号,请将其粘贴到此处进行检查。

添加:-流解析器失控了-尽管这将是更整洁的选择。如果您能找到一个JSON流解析器,就像SAX为XML所做的那样,您可能会做得更好。

第二种机制假设可以将整个JSON放入内存中的字符串中。不理想,但对大多数设置来说可能是可接受的解决方案。然后使用一个简单的正则表达式加上一个括号计数器来删除所需的部分。

/**
 * Finds the first matching close brace - assuming an open brace has just been removed from the `start` position.
 */
private int closeBrace(StringBuilder s, int start) {
    int count = 1;
    boolean inQuotes = false;
    for (int i = start; i < s.length(); i++) {
        char ch = s.charAt(i);
        // Special case escapes.
        if (ch != '\\') {
            switch (ch) {
                case '"':
                    inQuotes = !inQuotes;
                    break;
                case '{':
                    if (!inQuotes) {
                        count += 1;
                    }
                    break;
                case '}':
                    if (!inQuotes) {
                        count -= 1;
                        if (count == 0) {
                            return i;
                        }
                    }
                    break;
            }
        } else {
            // Escape character - skip the next character.
            if (i < s.length()) {
                i += 1;
            }
        }
    }
    // Failed to find
    return s.length();
}

/**
 * Removes the JSON specified.
 */
private String hack(String json, String remove) {
    // Transfer to an sb for slicing and dicing.
    StringBuilder s = new StringBuilder(json);
    // Build my pattern
    Pattern p = Pattern.compile("\"" + remove + "\"\\s*:\\s*\\{");
    // Make my Matchjer.
    Matcher m = p.matcher(s);
    // Is it there?
    while (m.find()) {
        int start = m.start();
        int end = m.end();
        // Kill the match.
        s.delete(start, end);
        // Walk forward to find the close brace.
        end = closeBrace(s, start);
        // And remove it.
        if (end < s.length()) {
            s.delete(end, end + 1);
        }
        // Rebuild the matcher.
        m = p.matcher(s);
    }
    return s.toString();
}

private void test(String json) {
    JsonParser parser = new JsonParser();
    JsonElement e = parser.parse(json);
    System.out.println(e);
}

public void test() {
    String json = "{'Book': {'name': 'Book \\'1\\'','published': 1999,'links': {'url': 'www.book1.com'},'embedded': {'Publisher': {'name': 'Publishing Company','links': {'url': 'www.publishingcompany.com'}}}}}".replace("'", "\"");
    test(json);
    json = hack(json, "embedded");
    test(json);
    json = hack(json, "links");
    test(json);
}

打印:

{"Book":{"name":"Book \"1\"","published":1999,"links":{"url":"www.book1.com"},"embedded":{"Publisher":{"name":"Publishing Company","links":{"url":"www.publishingcompany.com"}}}}}
{"Book":{"name":"Book \"1\"","published":1999,"links":{"url":"www.book1.com"},"Publisher":{"name":"Publishing Company","links":{"url":"www.publishingcompany.com"}}}}
{"Book":{"name":"Book \"1\"","published":1999,"url":"www.book1.com","Publisher":{"name":"Publishing Company","url":"www.publishingcompany.com"}}}

看起来有点像你要找的。

耿珂
2023-03-14

创建一个名为嵌入式的类,并将其添加为Book中的字段:

public class Book {
    String name;
    int published;
    Embedded embedded;
}

然后创建一个嵌入式类:

public class Embedded {
    Author Author;
    Publisher Publisher;
}

只需在JSON之后建模你的类

 类似资料:
  • 我想在Java中反序列化包含空值的json字符串。我想将对象反序列化为对象。json字符串类似于: 当我反序列化使用 由于对象中的that,我得到一个空指针异常。我如何指示Gson忽略空值的反序列化?

  • 我的目标是让这个电话“只是工作”。

  • 问题内容: 确定,所以我编辑了问题,因为它不够清楚。 编辑2 :更新了JSON文件。 我在Android应用程序中使用GSON,我需要解析来自服务器的JSON文件,这些文件有点太复杂了。我不想让我的对象结构太沉重,所以我想简化内容: 所以我的对象的结构将不是JSON文件的结构。 例如,如果在JSON中,我有以下内容: 我不想保留我当前的对象结构,即一个对象,其中包含一个和一个“总计”。但是我只想将

  • 我真的不知道如何说出这个问题的标题,所以如果有人有更好的标题,请建议。我正在尝试编码/解码s的ArrayList,并且每个会话都有一个s的ArrayList。我遇到的问题是,当我尝试对会话列表进行编码时,Gson不会深入研究每个会话的Shot数组并对ArrayList进行编码,而只是留下一个空数组: 会话类 快照类 构建json字符串: 在进一步研究之后,当我重建对象时,数据正在丢失,而不是在序列

  • 以下代码导致此异常: 所以问题是:如何在GSON序列化和反序列化的泛型HashMap中获得正确的实例?

  • 主要内容:示例我们将一个Java对象序列化为一个Json文件,然后读取该Json文件以获取对象。 在这个例子中,创建一个类。 然后将对象列化后存储在文件中,该文件将具有对象的json表示形式。 示例 在中创建一个名为的Java类文件,参考以下代码 - 执行上面示例代码,得到以下结果 -