You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

一对一关联下contactFrequency属性无法序列化问题求助

问题分析与解决方案

核心问题定位

从错误日志和代码来看,触发500错误的原因有三个:

  1. 空指针异常:当未找到对应ContactFrequency记录时,后续代码直接调用policyDocument.getContactFrequency()会触发空指针,导致序列化失败
  2. 循环引用导致序列化死循环:PolicyDocument与ContactFrequency的双向一对一关联,在JSON序列化时会形成无限递归
  3. DTO映射逻辑错误:toFrequencyDto方法中错误地将DTO自身的frequencyDays赋值给自己,导致数据丢失或异常

具体解决方案

1. 修复空指针与DTO映射错误

修改findById API方法,先判断contactFrequency是否为null,避免空指针;同时修正DTO映射的逻辑错误:

修改API代码

@Override
@GET
@Path("{id}")
public PolicyDocument findById(@PathParam("id") Long id) throws NotFoundAppException {
    PolicyDocument policyDocument = policyFinder.retrievePolicyDocument(id);
    ContactFrequency contactFrequency = searchContactFrequency.findContactFrequencyByDocumentId(policyDocument);
    
    // 处理contactFrequency为null的情况
    if (contactFrequency != null) {
        ContactFrequencyDto contactFrequencyDto = searchContactFrequency.toFrequencyDto(contactFrequency);
        if (contactFrequencyDto.getFrequencyDays() != null) {
            contactFrequencyDto.setId(null);
            pmLogger.info("Policy Document's contact frequency: " + contactFrequencyDto);
        }
        policyDocument.setContactFrequency(contactFrequency);
    } else {
        pmLogger.info("No contact frequency found for policy document: " + id);
        // 设置空对象避免后续空指针
        policyDocument.setContactFrequency(new ContactFrequency());
    }
    
    pmLogger.info("Policy Document with contactFrequency: " + policyDocument);

    if (PolicyDocumentStatus.DRAFT.equals(policyDocument.getStatus())
        && (currentEnvironmentUserRoles.hasAnyRole(Roles.Use_PM2_POLICY_APPROVER)
        && !currentEnvironmentUserRoles.hasAnyRole(Roles.Use_PM2_POLICY_USER, Roles.Use_PM2_POLICY_ADMIN, Roles.Use_PM2_GLOBAL_ADMIN))) {
        throw new NotFoundAppException("You do not have the permission to access the document");
    }
    return policyDocument;
}

修正toFrequencyDto方法

public ContactFrequencyDto toFrequencyDto(ContactFrequency contactFrequency) {
    if (contactFrequency == null) {
        return new ContactFrequencyDto(); // 返回空DTO避免空指针
    }
    ContactFrequencyDto contactFrequencyDto = new ContactFrequencyDto();
    contactFrequencyDto.setId(contactFrequency.getId());
    // 修正:使用实体的frequencyDays赋值给DTO
    contactFrequencyDto.setFrequencyDays(contactFrequency.getFrequencyDays());
    pmLogger.info("Mapping entity to dto completed successfully: " + contactFrequencyDto);
    return contactFrequencyDto;
}

2. 解决循环引用序列化问题

由于项目使用Yasson(Eclipse JSON-B)进行序列化,通过以下方式解决双向关联的循环引用:

在ContactFrequency的policyDocument字段添加忽略注解

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "policy_document_id", referencedColumnName = "id", nullable = false)
@JsonbTransient // 序列化时忽略该字段,避免循环引用
private PolicyDocument policyDocument;

或者使用JSON-B双向引用注解:

// 在PolicyDocument的contactFrequency字段添加
@OneToOne(mappedBy ="policyDocument", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@Nullable
@JsonbManagedReference
protected ContactFrequency contactFrequency;

// 在ContactFrequency的policyDocument字段添加
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "policy_document_id", referencedColumnName = "id", nullable = false)
@JsonbBackReference
private PolicyDocument policyDocument;

3. 优化JPA关联查询(可选)

为避免N+1查询问题,修改retrievePolicyDocument方法的查询逻辑,添加JOIN FETCH直接关联查询ContactFrequency:

// 示例JPQL查询
SELECT p FROM PolicyDocument p JOIN FETCH p.contactFrequency WHERE p.id = :id

内容的提问来源于stack exchange,提问作者Yiğit Güneş

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 14:27:36