【问题标题】:Spring Boot Jackson serialization for List Object列表对象的 Spring Boot Jackson 序列化
【发布时间】:2018-11-17 15:47:00
【问题描述】:

我有一个从 Spring Boot ReST 控制器返回的“人员”对象列表。输出很好,除了一个问题。

这个Personnel 对象有一个PersonnelType 对象作为它的嵌套对象之一。在序列化List中的第一个Personnel对象时,PersonnelType的整个子对象都被序列化了,这就是我想要的。

但是,如果 List 中的第二个或后续 Personnel 对象与第一个 Personnel 对象中已序列化的 PersonnelType 具有相同的 PersonnelType(相同 id),则这些后续 PersonnelType 对象仅使用“id”序列化,而不是整个对象。

例如,这里是序列化的输出:

[
    {
            "id": 2,
            "creatorUserId": null,
            "creationTime": null,
            "lastModifierUserId": null,
            "lastModificationTime": null,
            "workforceId": 9994323221,
            "workPhoneNumber": "7034563452",
            "workEmailAddress": "xxx@epa.gov",
            "currentPosition": "Developer",
            "isSponsored": false,
            "dateOfSponsorship": null,
            "sponsorPersonnelId": null,
            "isLEO": true,
            "isFERO": false,
            "requireComputerAndEmailAccess": true,
            "isPriorityCase": false,
            "building": {
                "id": 1,
                "creatorUserId": null,
                "creationTime": null,
                "lastModifierUserId": null,
                "lastModificationTime": null,
                "isActive": true,
                "buildingName": "Robert C Byrd Courthouse and FOB",
                "buildingNumber": "406",
                "displayGlobal": false,
                "facilityName": "Robert C Byrd Courthouse",
                "facilityNumber": "107",
                "handler": {},
                "hibernateLazyInitializer": {}
            },
            "personnelType": {
                "id": 1,
                "creatorUserId": null,
                "creationTime": null,
                "lastModifierUserId": null,
                "lastModificationTime": null,
                "description": "Federal Employee",
                "isActive": true,
                "handler": {},
                "hibernateLazyInitializer": {}
            }
    },

    {
            "id": 2,
            "creatorUserId": null,
            "creationTime": null,
            "lastModifierUserId": null,
            "lastModificationTime": null,
            "workforceId": 9994323221,
            "workPhoneNumber": "7034563452",
            "workEmailAddress": "xxx@epa.gov",
            "currentPosition": "Developer",
            "isSponsored": false,
            "dateOfSponsorship": null,
            "sponsorPersonnelId": null,
            "isLEO": true,
            "isFERO": false,
            "requireComputerAndEmailAccess": true,
            "isPriorityCase": false,
            "building": {
                "id": 1,
                "creatorUserId": null,
                "creationTime": null,
                "lastModifierUserId": null,
                "lastModificationTime": null,
                "isActive": true,
                "buildingName": "Robert C Byrd Courthouse and FOB",
                "buildingNumber": "406",
                "displayGlobal": false,
                "facilityName": "Robert C Byrd Courthouse",
                "facilityNumber": "107",
                "handler": {},
                "hibernateLazyInitializer": {}
            },
            "personnelType": 1          
    }

]

在上面,序列化 List 中的第一个 Personnel 对象具有序列化 PersonnelType 的完整对象,而序列化 List 中的第二个 Personnel 对象仅将 PersonnelType 作为 id 序列化,因为 PersonnelType (id = 1) 的 id 相同至于 List 中第一个 Personnel 对象中的 PersonnelType。

这是 Jackson 序列化程序的默认行为吗?我没有使用@JsonIdentityReference,因此默认情况下它是错误的。

@JsonIdentityReference 指示是否所有引用的值都被序列化为 ids 的标记(true);或者通过将第一个遇到的引用序列化为 POJO,然后将其序列化为 id (false)。

如何更改序列化,以便在列表中的每个人事对象中返回完整的 PersonnelType 子对象(即使它已经在列表中的前一个人事对象中序列化一次)?

这是我的带有注释的 Personnel 实体:

@Entity
@Table(name = "Personnel", schema = "dbo", catalog = "PSSV2Db")
@EntityListeners(AuditingEntityListener.class)
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id",resolver = EntityIdResolver.class, scope = PersonnelEntity.class)

public class PersonnelEntity extends AuditedEntity<String> {

    private Long id;
    private Long workforceId;
    private String workPhoneNumber;
    private String workEmailAddress;
    private String UPN;
    private String currentPosition;
    private Boolean isSponsored;
    private LocalDate dateOfSponsorship;
    private String sponsorPersonnelId;
    private Boolean isLEO;
    private Boolean isFERO;
    private Boolean requireComputerAndEmailAccess;
    private Boolean isPriorityCase;

    @Id
    @Column(name = "PersonnelId", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }


    @Basic
    @Column(name = "WorkforceId", nullable = false)
    public Long getWorkforceId() {
        return workforceId;
    }

    public void setWorkforceId(Long workforceId) {
        this.workforceId = workforceId;
    }

    @Basic
    @Column(name = "WorkPhoneNumber", nullable = true)
    public String getWorkPhoneNumber() {
        return workPhoneNumber;
    }

    public void setWorkPhoneNumber(String workPhoneNumber) {
        this.workPhoneNumber = workPhoneNumber;
    }

    @Basic
    @Column(name = "WorkEmailAddress", nullable = true)
    public String getWorkEmailAddress() {
        return workEmailAddress;
    }

    public void setWorkEmailAddress(String workEmailAddress) {
        this.workEmailAddress = workEmailAddress;
    }

    @Basic
    @Column(name = "UPN", nullable = true)

    public String getUPN() {
        return UPN;
    }

    public void setUPN(String UPN) {
        this.UPN = UPN;
    }

    @Basic
    @Column(name = "CurrentPosition", nullable = true)
    public String getCurrentPosition() {
        return currentPosition;
    }

    public void setCurrentPosition(String currentPosition) {
        this.currentPosition = currentPosition;
    }

    @Basic
    @Column(name = "IsSponsored", nullable = true)

    public Boolean getIsSponsored() {
        return isSponsored;
    }

    public void setIsSponsored(Boolean sponsored) {
        this.isSponsored = sponsored;
    }

    @Basic
    @Column(name = "DateOfSponsorship", nullable = true)

    public LocalDate getDateOfSponsorship() {
        return dateOfSponsorship;
    }

    public void setDateOfSponsorship(LocalDate dateOfSponsorship) {
        this.dateOfSponsorship = dateOfSponsorship;
    }

    @Basic
    @Column(name = "SponsorPersonnelId", nullable = true)

    public String getSponsorPersonnelId() {
        return sponsorPersonnelId;
    }

    public void setSponsorPersonnelId(String sponsorPersonnelId) {
        this.sponsorPersonnelId = sponsorPersonnelId;
    }

    @Basic
    @Column(name = "IsLEO", nullable = false)
    public Boolean getIsLEO() {
        return isLEO;
    }

    public void setIsLEO(Boolean LEO) {
        this.isLEO = LEO;
    }

    @Basic
    @Column(name = "IsFERO", nullable = false)

    public Boolean getIsFERO() {
        return isFERO;
    }

    public void setIsFERO(Boolean FERO) {
        this.isFERO = FERO;
    }

    @Basic
    @Column(name = "RequireComputerAndEmailAddress", nullable = false)

    public Boolean getRequireComputerAndEmailAccess() {
        return requireComputerAndEmailAccess;
    }

    public void setRequireComputerAndEmailAccess(Boolean requireComputerAndEmailAccess) {
        this.requireComputerAndEmailAccess = requireComputerAndEmailAccess;
    }

    @Basic
    @Column(name = "IsPriorityCase", nullable = false)
    public Boolean getIsPriorityCase() {
        return isPriorityCase;
    }

    public void setIsPriorityCase(Boolean isPriorityCase) {
        this.isPriorityCase = isPriorityCase;
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof PersonnelEntity)) return false;
        PersonnelEntity that = (PersonnelEntity) o;
        return Objects.equals(getId(), that.getId()) &&
                Objects.equals(getWorkforceId(), that.getWorkforceId()) &&
                Objects.equals(getWorkPhoneNumber(), that.getWorkPhoneNumber()) &&
                Objects.equals(getWorkEmailAddress(), that.getWorkEmailAddress()) &&
                Objects.equals(getUPN(), that.getUPN()) &&
                Objects.equals(getCurrentPosition(), that.getCurrentPosition()) &&
                Objects.equals(getIsSponsored(), that.getIsSponsored()) &&
                Objects.equals(getDateOfSponsorship(), that.getDateOfSponsorship()) &&
                Objects.equals(getSponsorPersonnelId(), that.getSponsorPersonnelId()) &&
                Objects.equals(getIsLEO(), that.getIsLEO()) &&
                Objects.equals(getIsFERO(), that.getIsFERO()) &&
                Objects.equals(getRequireComputerAndEmailAccess(), that.getRequireComputerAndEmailAccess()) &&
                Objects.equals(getIsPriorityCase(), that.getIsPriorityCase());
    }

    @Override
    public int hashCode() {

        return Objects.hash(getId(), getWorkforceId(), getWorkPhoneNumber(), getWorkEmailAddress(), getUPN(), getCurrentPosition(), getIsSponsored(), getDateOfSponsorship(), getSponsorPersonnelId(), getIsLEO(), getIsFERO(), getRequireComputerAndEmailAccess(), getIsPriorityCase());
    }


    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "BuildingId")
    public BuildingsEntity getBuilding() {
        return building;
    }
    public void setBuilding(BuildingsEntity building) {
        this.building = building;
    }

    private BuildingsEntity building;




    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    @JoinColumn(name = "PersonnelTypeId")
    public PersonnelTypesEntity getPersonnelType() {
        return personnelType;
    }
    public void setPersonnelType(PersonnelTypesEntity personnelType) {
        this.personnelType = personnelType;
    }

    private PersonnelTypesEntity personnelType;


}

这是带有注释的 PersonnelType 实体:

@Entity
@Table(name = "PersonnelTypes", schema = "dbo", catalog = "PSSV2Db")
@EntityListeners(AuditingEntityListener.class)
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id", resolver = EntityIdResolver.class, scope = PersonnelTypesEntity.class)

public class PersonnelTypesEntity extends AuditedEntity<String> {
    private long id;
    private String description;
    private Boolean isActive;

    @Id
    @Column(name = "PersonnelTypeId", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @Basic
    @Column(name = "Description", nullable = true, length = 8000)
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Basic
    @Column(name = "IsActive", nullable = false)
    public Boolean getIsActive() {
        return isActive;
    }

    public void setIsActive(Boolean isActive) {
        this.isActive = isActive;
    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof PersonnelTypesEntity)) return false;
        PersonnelTypesEntity that = (PersonnelTypesEntity) o;
        return getId() == that.getId() &&
                Objects.equals(getDescription(), that.getDescription()) &&
                Objects.equals(getIsActive(), that.getIsActive());
    }

    @Override
    public int hashCode() {

        return Objects.hash(getId(), getDescription(), getIsActive());
    }
}

【问题讨论】:

  • 不,这不是默认设置
  • 您能否发布 Personnel 和 PersonnelType 类以及您已应用的所有注释。
  • 我在上面添加了它们
  • 您正在使用 JsonIdentityInfo。查看它的文档

标签: java json spring serialization jackson


【解决方案1】:

我使用 JSOG 库为所有序列化输出提供 @id 和 @ref,API 使用者还需要使用 JSOG 库进行转换并在客户端获取完整的对象图。

这似乎是一个常见问题,但 Jackson 本身并没有提供解决方案。

【讨论】:

    猜你喜欢
    • 2014-03-11
    • 2019-05-10
    • 2021-02-18
    • 2019-04-03
    • 2017-09-09
    • 2021-03-30
    • 1970-01-01
    • 2021-03-31
    • 1970-01-01
    相关资源
    最近更新 更多