使用Room@Embedded时,如何让Gson将嵌套字段平展至父实体类?
解决方案:结合Room @Embedded与Gson扁平化反序列化
这个需求太常见了!结合Room的嵌套实体存储和Gson的扁平化JSON反序列化,不用自定义JsonAdapter也有很优雅的解决方案,优先推荐用Gson自带的注解来实现,下面给你两种可行的思路:
1. 最优方案:使用Gson的@JsonUnwrapped注解(推荐)
Gson的@JsonUnwrapped注解正好和Room的@Embedded功能对应——它会告诉Gson把嵌套对象的字段直接映射到父对象的JSON层级中,完全符合你的需求。只需要做两个小修改:
修改后的实体类代码
@Entity public class MyObject { // 必须改为静态内部类:Gson默认无法反序列化非静态内部类(依赖外部类实例) public static class GeneralInfo { public String ownerName; @PrimaryKey public long wellId; } @Embedded // Room用来将嵌套类字段嵌入数据表 @JsonUnwrapped // Gson用来扁平化JSON反序列化/序列化 public GeneralInfo generalInfo; public long objectId; // 无参构造函数:Gson反序列化必须要有 public MyObject() { this.generalInfo = new GeneralInfo(); } // 其他字段和业务方法... }
关键说明
@JsonUnwrapped:Gson会自动把JSON中平级的wellId、ownerName直接赋值给generalInfo对象的对应字段,不需要嵌套的generalInfoJSON节点。- 静态内部类:非静态内部类依赖外部
MyObject实例才能创建,Gson无法自动处理,改成静态内部类后就能正常反序列化了。 - 无参构造函数:确保Gson能正确实例化
MyObject和GeneralInfo对象。
2. 备选方案:手动映射字段的Getter/Setter
如果你因为某些原因不想用@JsonUnwrapped,可以通过添加和JSON字段对应的Getter/Setter,配合Room的@Ignore注解来实现:
代码示例
@Entity public class MyObject { public static class GeneralInfo { public String ownerName; @PrimaryKey public long wellId; } @Embedded public GeneralInfo generalInfo = new GeneralInfo(); public long objectId; // Gson直接映射JSON中的ownerName,Room忽略这个方法 @Ignore @SerializedName("ownerName") public void setOwnerName(String ownerName) { this.generalInfo.ownerName = ownerName; } // Gson直接映射JSON中的wellId,Room忽略这个方法 @Ignore @SerializedName("wellId") public void setWellId(long wellId) { this.generalInfo.wellId = wellId; } // 可选:添加Getter让Gson序列化时也能输出平级字段 @Ignore @SerializedName("ownerName") public String getOwnerName() { return this.generalInfo.ownerName; } @Ignore @SerializedName("wellId") public long getWellId() { return this.generalInfo.wellId; } public MyObject() {} }
关键说明
@SerializedName:告诉Gson这些Getter/Setter对应JSON中的平级字段。@Ignore:告诉Room不要把这些方法当成实体类的字段,避免生成多余的数据表列。- 这种方法更灵活,但代码量比第一种方案多,适合需要自定义字段映射逻辑的场景。
内容的提问来源于stack exchange,提问作者Mneckoee
相关产品推荐
相关产品推荐

