Gson:如何在没有注释的情况下从序列化中排除特定字段
我正在努力学习 Gson,但我正在与字段排除作斗争。这是我的类,
public class Student {
private Long id;
private String firstName = "Philip";
private String middleName = "J.";
private String initials = "P.F";
private String lastName = "Fry";
private Country country;
private Country countryOfBirth;
}
public class Country {
private Long id;
private String name;
private Object other;
}
我可以使用 GsonBuilder 并为 firstName
或 country
等字段名称添加 ExclusionStrategy,但我似乎无法设法排除某些字段的属性,例如国家/地区.名称
。
使用 public boolean shouldSkipField(FieldAttributes fa)
方法时,FieldAttributes 未包含足够的信息来将字段与 country.name
等过滤器相匹配。
PS:我想避免注释,因为我想改进这一点并使用正则表达式来过滤字段。
编辑:我试图看看是否可以模拟 Struts2 JSON 插件
使用 Gson
<interceptor-ref name="json">
<param name="enableSMD">true</param>
<param name="excludeProperties">
login.password,
studentList.*\.sin
</param>
</interceptor-ref>
编辑: 我重新打开了这个问题,添加了以下内容:
我添加了第二个具有相同类型的字段来进一步澄清这个问题。基本上我想排除 country.name
但不排除 countrOfBirth.name
。我也不想排除国家作为一种类型。 所以类型是相同的,这是我想要查明和排除的对象图中的实际位置。
I'm trying to learn Gson and I'm struggling with field exclusion. Here are my classes
public class Student {
private Long id;
private String firstName = "Philip";
private String middleName = "J.";
private String initials = "P.F";
private String lastName = "Fry";
private Country country;
private Country countryOfBirth;
}
public class Country {
private Long id;
private String name;
private Object other;
}
I can use the GsonBuilder and add an ExclusionStrategy for a field name like firstName
or country
but I can't seem to manage to exclude properties of certain fields like country.name
.
Using the method public boolean shouldSkipField(FieldAttributes fa)
, FieldAttributes doesn't contain enough information to match the field with a filter like country.name
.
P.S: I want to avoid annotations since I want to improve on this and use RegEx to filter fields out.
Edit: I'm trying to see if it's possible to emulate the behavior of Struts2 JSON plugin
using Gson
<interceptor-ref name="json">
<param name="enableSMD">true</param>
<param name="excludeProperties">
login.password,
studentList.*\.sin
</param>
</interceptor-ref>
Edit:
I reopened the question with the following addition:
I added a second field with the same type to futher clarify this problem. Basically I want to exclude country.name
but not countrOfBirth.name
. I also don't want to exclude Country as a type.
So the types are the same it's the actual place in the object graph that I want to pinpoint and exclude.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(17)
一般情况下,您不希望序列化的任何字段都应该使用“transient”修饰符,这也适用于 json 序列化器(至少它适用于我使用过的一些序列化器,包括 gson)。
如果您不希望名称显示在序列化的 json 中,请给它一个瞬态关键字,例如:
Gson 文档中的更多详细信息
Any fields you don't want serialized in general you should use the "transient" modifier, and this also applies to json serializers (at least it does to a few that I have used, including gson).
If you don't want name to show up in the serialized json give it a transient keyword, eg:
More details in the Gson documentation
Nishant 提供了一个很好的解决方案,但还有一种更简单的方法。只需使用 @Expose 注解标记所需的字段,例如:
忽略任何不想序列化的字段。然后以这种方式创建你的 Gson 对象:
Nishant provided a good solution, but there's an easier way. Simply mark the desired fields with the @Expose annotation, such as:
Leave out any fields that you do not want to serialize. Then just create your Gson object this way:
因此,您想要排除
firstName
和country.name
。这是您的ExclusionStrategy
的样子。如果您仔细观察,它会为
Student.firstName
和Country.name
返回true
>,这是您要排除的内容。您需要像这样应用此
ExclusionStrategy
,这将返回:
我假设国家对象是在学生班级中使用
id = 91L
初始化的。你可能会喜欢。例如,您不想序列化名称中包含“name”字符串的任何字段。执行此操作:
这将返回:
编辑:根据要求添加了更多信息。
此
ExclusionStrategy
可以完成此操作,但您需要传递“完全限定字段名称”。见下文:这是我们如何通用地使用它。
它返回:
So, you want to exclude
firstName
andcountry.name
. Here is what yourExclusionStrategy
should look likeIf you see closely it returns
true
forStudent.firstName
andCountry.name
, which is what you want to exclude.You need to apply this
ExclusionStrategy
like this,This returns:
I assume the country object is initialized with
id = 91L
in student class.You may get fancy. For example, you do not want to serialize any field that contains "name" string in its name. Do this:
This will return:
EDIT: Added more info as requested.
This
ExclusionStrategy
will do the thing, but you need to pass "Fully Qualified Field Name". See below:Here is how we can use it generically.
It returns:
在阅读了所有可用的答案后,我发现,就我而言,最灵活的是使用自定义
@Exclude
注释。因此,我为此实现了简单的策略(我不想使用 @Expose 标记所有字段,也不想使用与应用程序中的Serialized 冲突的
序列化):transient
注释:
策略:
用法:
After reading all available answers I found out, that most flexible, in my case, was to use custom
@Exclude
annotation. So, I implemented simple strategy for this (I didn't want to mark all fields using@Expose
nor I wanted to usetransient
which conflicted with in appSerializable
serialization) :Annotation:
Strategy:
Usage:
我遇到了这个问题,其中我只想从序列化中排除少量字段,因此我开发了一个相当简单的解决方案,该解决方案使用 Gson 的
@Expose
注释和自定义排除策略。使用
@Expose
的唯一内置方法是通过设置GsonBuilder.excludeFieldsWithoutExposeAnnotation()
,但正如名称所示,没有显式@Expose
的字段代码> 被忽略。由于我只有几个想要排除的字段,因此我发现向每个字段添加注释的前景非常麻烦。我实际上想要相反的情况,其中包含所有内容,除非我明确使用 @Expose 来排除它。我使用以下排除策略来实现此目的:
现在我可以使用
@Expose(serialize = false)
或@Expose(deserialize = false)
注释轻松排除一些字段(请注意,两个@Expose
属性的默认值为true
)。您当然可以使用 @Expose(serialize = false, deserialize = false) ,但是通过声明字段transient
可以更简洁地实现这一点(它仍然在以下情况下生效)这些自定义排除策略)。I ran into this issue, in which I had a small number of fields I wanted to exclude only from serialization, so I developed a fairly simple solution that uses Gson's
@Expose
annotation with custom exclusion strategies.The only built-in way to use
@Expose
is by settingGsonBuilder.excludeFieldsWithoutExposeAnnotation()
, but as the name indicates, fields without an explicit@Expose
are ignored. As I only had a few fields I wanted to exclude, I found the prospect of adding the annotation to every field very cumbersome.I effectively wanted the inverse, in which everything was included unless I explicitly used
@Expose
to exclude it. I used the following exclusion strategies to accomplish this:Now I can easily exclude a few fields with
@Expose(serialize = false)
or@Expose(deserialize = false)
annotations (note that the default value for both@Expose
attributes istrue
). You can of course use@Expose(serialize = false, deserialize = false)
, but that is more concisely accomplished by declaring the fieldtransient
instead (which does still take effect with these custom exclusion strategies).您可以使用 gson 探索 json 树。
尝试这样的事情:
您还可以添加一些属性:
使用 gson 2.2.4 进行测试。
You can explore the json tree with gson.
Try something like this :
You can add some properties also :
Tested with gson 2.2.4.
我想出了一个类工厂来支持此功能。传递您想要排除的字段或类的任意组合。
要使用,请创建两个列表(每个列表都是可选的),然后创建 GSON 对象:
I came up with a class factory to support this functionality. Pass in any combination of either fields or classes you want to exclude.
To use, create two lists (each is optional), and create your GSON object:
我通过自定义注释解决了这个问题。
这是我的“SkipSerialization”注释类:
这是我的 GsonBuilder:
示例:
I solved this problem with custom annotations.
This is my "SkipSerialisation" Annotation class:
and this is my GsonBuilder:
Example :
Kotlin 的
@Transient
注解显然也能达到这个目的。输出:
Kotlin's
@Transient
annotation also does the trick apparently.Output:
或者可以说什么字段不会公开:
在您的类属性上:
Or can say whats fields not will expose with:
on your class on attribute:
我使用了这个策略:
我排除了每个未标记有@SerializedName注释的字段,即:
它返回
I used this strategy:
i excluded every field which is not marked with @SerializedName annotation, i.e.:
It returns
另一种方法(如果您需要在运行时决定排除某个字段,则特别有用)是向您的 gson 实例注册 TypeAdapter。下面的示例:
在下面的情况下,服务器将期望两个值之一,但由于它们都是整数,因此 gson 会将它们都序列化。我的目标是省略发布到服务器的 json 中任何为零(或更少)的值。
Another approach (especially useful if you need to make a decision to exclude a field at runtime) is to register a TypeAdapter with your gson instance. Example below:
In the case below, the server would expect one of two values but since they were both ints then gson would serialize them both. My goal was to omit any value that is zero (or less) from the json that is posted to the server.
在 kotlin 中可以使用 @Transient 来忽略该字段...例如。
in kotlin can use @Transient to ignore the field... eg.
我只是通过添加 @Expose 注释来工作,这里是我
在 Model 类中使用的版本:
在 Adapter 类中:
I'm working just by putting the
@Expose
annotation, here my version that I useIn
Model
class:In the
Adapter
class:我有 Kotlin 版本
以及如何将其添加到 Retrofit GSONConverterFactory:
I have Kotlin version
and how You can add this to Retrofit GSONConverterFactory:
这是我经常使用的:
Gson 中实现的默认行为是忽略空对象字段。
意味着 Gson 对象不会将空值字段序列化为 JSON。如果 Java 对象中的某个字段为 null,Gson 会将其排除。
您可以使用此函数将某些对象转换为 null 或由您自己设置
This what I always use:
The default behaviour implemented in Gson is that null object fields are ignored.
Means Gson object does not serialize fields with null values to JSON. If a field in a Java object is null, Gson excludes it.
You can use this function to convert some object to null or well set by your own
对缓存对象使用不同的 DTO。
例如,您可以创建 UserCached 类并仅保留您需要的字段。
之后,创建映射器以将对象映射回来并进行映射。四。
Mapstruct
对此很有用。这种方法可以解决问题,解耦应用程序,并使主 DTO 中的更改更安全。
Use different DTO for cached object.
For example, you can create
UserCached
class and keep there only fields you need.After that, create mapper to map objects back & forth.
Mapstruct
is good for that.Such approach solves the problem, decouples your application, and makes changes in your primary DTO more safe to make.