java Gson 在序列化期间添加字段
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13024749/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Gson add field during serialization
提问by joncalhoun
I can't find a simple way to add a custom field during serialization in Gson and I was hoping someone else may be able to help.
我找不到在 Gson 序列化期间添加自定义字段的简单方法,我希望其他人能够提供帮助。
Here is a sample class to show my issue:
这是一个示例类来显示我的问题:
public class A {
String id;
String name;
...
}
When I serialize class A I would like to return something like:
当我序列化类 AI 想返回如下内容:
{ "id":"123", "name":"John Doe", "url_to_user":"http://www.example.com/123" }
where url_to_user is not stored in my instance of class A, but can be generated with data in the instance of class A.
其中 url_to_user 未存储在我的 A 类实例中,但可以使用 A 类实例中的数据生成。
Is there a simple way of doing this? I would prefer to avoid writing an entire serializer just to add one field.
有没有一种简单的方法可以做到这一点?我宁愿避免编写整个序列化程序只是为了添加一个字段。
回答by Jeff Bowman
Use Gson.toJsonTree
to get a JsonElement
, with which you can interact dynamically.
用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);
回答by pulp_fiction
Well, the top rated answer is quite a quick one and not essentially badwhen you are lacking much time but here is the problem: There is no proper separation of concern
嗯,评分最高的答案是相当快的,当您没有太多时间时,基本上不是很糟糕,但问题是:没有适当的关注点分离
You are modifying the serialized JSON at the same place where you are writing your business logic. You should be doing all the serialization inside of a TypeAdapter
or a JsonSerializer
.
您正在编写业务逻辑的同一位置修改序列化的 JSON。您应该在 aTypeAdapter
或 a 中进行所有序列化JsonSerializer
。
How can we maintain a proper separation of concern?
我们如何才能保持适当的关注点分离?
The answer wraps around a bit of additional complexity but the architecture demands it. Here we go(taken from my other answer):
答案包含一些额外的复杂性,但架构需要它。我们开始(取自我的另一个答案):
First, we would be using a custom serializer for the type. Second, we would have to create a copy constructorinside the base class and a wrapper subclass as follows:
首先,我们将为该类型使用自定义序列化程序。其次,我们必须在基类和包装子类中创建一个复制构造函数,如下所示:
Note: The custom serializer might seem like an overkill but trust me, it pays off in long run for maintainability..
注意:自定义序列化程序可能看起来有点矫枉过正,但相信我,从长远来看,它会为可维护性带来回报。.
// 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);
}
}
And the serializer for the type 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);
}
}
So, why a copy constructor?
那么,为什么要复制构造函数呢?
Well, once you define the copy constructor, no matter how much the base class changes, your wrapper will continue with the same role. Secondly, if we don't define a copy constructor and simply subclass the base class then we would have to "talk" in terms of the extended class, i.e, CatWrapper
. It is quite possible that your components talk in terms of the base class and not the wrapper type.
好吧,一旦您定义了复制构造函数,无论基类发生了多少变化,您的包装器都将继续扮演相同的角色。其次,如果我们不定义复制构造函数并简单地将基类子类化,那么我们将不得不根据扩展类“交谈”,即CatWrapper
. 您的组件很可能根据基类而不是包装器类型进行讨论。