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集合时触发空指针异常。
修复方案
- 修正单个发票项DTO:将
InvoicesDTO重命名为InvoiceItemDTO(语义更清晰),移除List接口实现,仅保留发票项字段。 - 调整主DTO字段类型:在
InvoiceDTO中,将invoices字段改为List<InvoiceItemDTO>,匹配JSON数组结构。 - 业务代码适配:直接遍历修正后的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
相关产品推荐
相关产品推荐

