导论
直接看代码,项目采用 JPA ORM,在实现一对多关联的时候,需要这样设置PO
假设一个任务对应多个任务节点
任务实体TaskConfig:
1 2 3 4
| @JsonIgnoreProperties(value = {"taskPO"}) @OneToMany(mappedBy = "taskPO", fetch = FetchType.LAZY, cascade = {CascadeType.ALL}, orphanRemoval = true) private List<TaskNodeConfig> nodeConfigList;
|
任务节点实体TaskNodeConfig
1 2 3
| @ManyToOne(targetEntity = TaskConfig.class, fetch = FetchType.LAZY) @JoinColumn(name = "task_config_code", referencedColumnName = "code", foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT)) private TaskConfig taskPO;
|
上面的@JoinColumn(name = "task_config_code", referencedColumnName = "code"
用于指定我们任务节点实体表中的task_config_code
字段对应任务实体表中的code
字段作关联
这样定义才可以实现关联,但是在序列化任务实体对象的时候存在问题:
任务实体对象有nodeConfigList字段,nodeConfigList字段中每一个元素又都有各自的taskPO字段;taskPO字段中又有nodeConfigList字典,因此如果不在序列化的时候忽略taskPO字段,则会子子孙孙无穷匮也
忽略字段实现
GOSN中提供了三种方式来实现字段的忽略:
- transient关键字
- @Expose注解指定哪些字段【要】序列化
- 实例化Gson对象时指定策略
三种方式各有具体的使用场景以及限制,下面展开描述
transient关键字
对于想要忽略的字段使用 transient 关键字进行修饰
但是在上面的例子中并不适用,因为要忽略的 taskPO 字段是需要给 JPA 作为关联表关联键的,如果设置为 transient 修饰,启动会报 JPA 的错,说 field not found
@Expose
这种方式是忽略的反方向,指定哪些字段要序列化
但是此处我们只想忽略这一个字段,如果对象中剩下的字段较多,这种方式也不合适
顺带一提,如果选择使用@Expose
的方式,在序列化的时候应该调用像下面这样的GSON实例的toJSONString函数
1 2 3 4 5 6 7 8 9 10
| private static final Gson gsonExclude = getExcludeGsonBuilder().create();
private static GsonBuilder getExcludeGsonBuilder() { return new GsonBuilder() .setDateFormat("yyyy-MM-dd HH:mm:ss") .disableInnerClassSerialization() .excludeFieldsWithoutExposeAnnotation() .disableHtmlEscaping(); }
|
自定义排除策略
我们新建一个自定义注解
1 2 3 4 5 6 7
| import java.lang.annotation.*;
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface IgnoreGsonField { }
|
将注解打在想要忽略的字段上,例如之前的任务节点类
1 2 3 4
| @IgnoreGsonField @ManyToOne(targetEntity = TaskConfig.class, fetch = FetchType.LAZY) @JoinColumn(name = "task_config_code", referencedColumnName = "code", foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT)) private TaskConfig taskPO;
|
在实例化GSON对象的时候,实现ExclusionStrategy
来指定排除策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| private static final Gson gsonAnnotationExclude = getExcludeAnnotationGsonBuilder().create();
private static GsonBuilder getExcludeAnnotationGsonBuilder() { return new GsonBuilder() .setExclusionStrategies(new ExclusionStrategy() { @Override public boolean shouldSkipField(FieldAttributes fieldAttributes) { return fieldAttributes.getAnnotation(IgnoreGsonField.class) != null; }
@Override public boolean shouldSkipClass(Class<?> clazz) { return clazz.isAnnotationPresent(IgnoreGsonField.class); } }) .serializeNulls() .setDateFormat("yyyy-MM-dd HH:mm:ss") .disableInnerClassSerialization() .disableHtmlEscaping(); }
|
总结
如果只希望在序列化和反序列化的时候暴露指定字段,使用@Expose
并结合GsonBuilder.excludeFieldsWithoutExposeAnnotation()
实例化支持Expose注解的GSON实例使用
如果希望忽略个别字段(如本文场景),可以使用自定义注解,结合GsonBuilder.setExclusionStrategies()
实例化排除指定注解修饰字段的GSON实例使用