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

JSON嵌套对象存入数据库报错:Iterator.hasNext()空指针异常

解决JSON嵌套数组存入数据库时的NullPointerException问题

问题背景

在将包含嵌套数组的JSON存入数据库时,持续抛出异常:

"Cannot invoke "java.util.Iterator.hasNext()" because "" is null"

JSON结构示例:

{
        "personId" : "1xxxxxxx",
        "invoiceDate" : "2020-10-12",
        "invoices":[
            {
            "invoiceAmount" :"300",
            "invoiceNumber" :"x123"
            },
        {
            "invoiceAmount" :"100",
            "invoiceNumber" :"x122"
        }
        ]   
}

当前实现中,创建了InvoiceDTO和InvoicesDTO处理嵌套数组:InvoiceDTO包含InvoicesDTO类型的invoices字段,InvoicesDTO实现了List<InvoicesDTO>接口。遍历invoices对象时触发上述错误,报错位置在for循环遍历处。

错误原因分析

核心错误在于DTO设计完全不符合JSON结构:

  • JSON中的invoices是数组,对应Java的List类型,但当前InvoiceDTO的invoices字段是单个InvoicesDTO对象,而非集合。
  • InvoicesDTO作为单个发票项的载体,错误实现了List<InvoicesDTO>接口。Jackson无法将JSON数组反序列化成这种自定义List实现类,最终导致invoiceDTO.getInvoices()返回null,遍历null集合时触发空指针异常。

修复方案

  1. 修正单个发票项DTO:将InvoicesDTO重命名为InvoiceItemDTO(语义更清晰),移除List接口实现,仅保留发票项字段。
  2. 调整主DTO字段类型:在InvoiceDTO中,将invoices字段改为List<InvoiceItemDTO>,匹配JSON数组结构。
  3. 业务代码适配:直接遍历修正后的List集合即可。

修复后代码示例

单个发票项DTO(InvoiceItemDTO)

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class InvoiceItemDTO {

    @NotNull(message = "invoice Number can't be null")
    private String invoiceNumber;

    @NotNull(message = "invoiceAmount can't be null")
    private Double invoiceAmount; 
}

主DTO(InvoiceDTO)

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class InvoiceDTO {
  @NotNull(message = "PersonId can't be null")
  @PersonId
  private String personId;

  @NotNull(message = "invoiceDate can't be null")
  @PastOrPresent
  @JsonFormat(pattern = "yyyy-MM-dd")
  private LocalDate invoiceDate;

  // 修改为List类型,匹配JSON数组
  private List<InvoiceItemDTO> invoices;
}

业务处理代码调整

try {
  Optional<Debts> debts = debtsRepository.findDebtsByPersonIdAndOrganization_id(invoiceDTO.getPersonId(), organization.get().getId());
  Optional<Madeen> madeenOptional = madeenRepository.findByPersonId(invoiceDTO.getPersonId());

  // 直接获取List集合,无需强制转换
  List<InvoiceItemDTO> invoicesDTO = invoiceDTO.getInvoices();

  // 遍历前判空,避免空指针
  if (invoicesDTO != null && !invoicesDTO.isEmpty()) {
      for (InvoiceItemDTO invoiceItem : invoicesDTO) {  
          Debts newDebt = new Debts();
          newDebt.setPersonId(invoiceDTO.getPersonId());
          newDebt.setCreatedDate(LocalDate.now());
          newDebt.setUpdatedDate(invoiceDTO.getInvoiceDate());
          newDebt.setDebtAmount(invoiceItem.getInvoiceAmount());
          newDebt.setInvoiceNumber(invoiceItem.getInvoiceNumber());
          newDebt.setOrganization(organization.get());
          debtsRepository.save(newDebt);
      }
  }
} catch (Exception e) {
  // 添加异常处理逻辑
  e.printStackTrace();
}

额外建议

  • 遍历集合前先做判空检查(invoicesDTO != null && !invoicesDTO.isEmpty()),可进一步避免空指针异常。
  • DTO命名应贴合语义,区分集合与单个实体,提升代码可读性。

内容的提问来源于stack exchange,提问作者TechNewPy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 21:51:16