31

我找不到在 Gson 序列化期间添加自定义字段的简单方法,我希望其他人可以提供帮助。

这是一个示例类来显示我的问题:

public class A {
  String id;
  String name;
  ...
}

当我序列化类时,AI 想返回如下内容:

{ "id":"123", "name":"John Doe", "url_to_user":"http://www.example.com/123" }

其中 url_to_user 未存储在我的 A 类实例中,但可以使用 A 类实例中的数据生成。

有没有一种简单的方法可以做到这一点?我宁愿避免仅仅为了添加一个字段而编写整个序列化程序。

4

2 回答 2

57

用于Gson.toJsonTree获取JsonElement,您可以与之动态交互。

A a = getYourAInstanceHere();
Gson gson = new Gson();
JsonElement jsonElement = gson.toJsonTree(a);
jsonElement.getAsJsonObject().addProperty("url_to_user", url);
return gson.toJson(jsonElement);
于 2012-10-23T07:11:02.920 回答
0

好吧,当你没有太多时间的时候,评价最高的答案是一个相当快的答案,而且基本上还不错,但问题是:没有适当的关注点分离

您正在编写业务逻辑的同一位置修改序列化 JSON。您应该在 aTypeAdapter或 a中进行所有序列化JsonSerializer

我们如何保持适当的关注点分离?

答案包含一些额外的复杂性,但架构需要它。我们开始吧(取自我的另一个答案):

首先,我们将为该类型使用自定义序列化程序。其次,我们必须在基类和包装子类中创建一个复制构造函数,如下所示:

注意:自定义序列化器可能看起来有点矫枉过正,但相信我,从长远来看,它会为可维护性带来回报。 .

// Lets say the base class is named Cat
public class Cat {

    public String name;

    public Cat(String name) {
        super();
        this.name = name;
    }
    // COPY CONSTRUCTOR
    public Cat(Cat cat) {
        this.name = cat.name;
    }

    @Override
    public String sound() {
        return name + " : \"meaow\"";
    };
}



    // The wrapper subclass for serialization
public class CatWrapper extends Cat{


    public CatWrapper(String name) {
        super(name);
    }

    public CatWrapper(Cat cat) {
        super(cat);
    }
}

以及类型的序列化程序Cat

public class CatSerializer implements JsonSerializer<Cat> {

    @Override
    public JsonElement serialize(Cat src, Type typeOfSrc, JsonSerializationContext context) {

        // Essentially the same as the type Cat
        JsonElement catWrapped = context.serialize(new CatWrapper(src));

        // Here, we can customize the generated JSON from the wrapper as we want.
        // We can add a field, remove a field, etc.

        // The main logic from the top rated answer now here instead of *spilling* around(Kindly ignore the cat having a url for the sake of example)
        return catWrapped.getAsJsonObject().addProperty("url_to_user", url);
    }
}

那么,为什么要使用复制构造函数?

好吧,一旦定义了复制构造函数,无论基类发生多少变化,您的包装器都将继续扮演相同的角色。其次,如果我们不定义复制构造函数而只是将基类子类化,那么我们将不得不根据扩展类来“讨论”,即CatWrapper. 您的组件很有可能是根据基类而不是包装器类型来讨论的。

于 2019-08-15T16:13:51.003 回答