ModelMapper转换Set<Author>到Set<Integer>时出现空指针错误求助
问题分析
从报错栈信息来看,空指针异常(NPE)出现在map(Autor::getId)执行阶段,说明Livro实体的关联集合中存在null的Autor/Genero对象,调用getId()时触发了空指针。另外Hibernate返回的PersistentSet虽然实现了Set接口,但也可能因泛型匹配细节导致转换异常。
修复方案
方案1:在转换器中过滤null元素
修改转换器逻辑,在流式处理时先过滤掉集合中的null实体,同时额外过滤可能的null ID,避免空指针:
import java.util.Objects; // ... 其他导入 @Configuration public class MapperConfig { @Bean public ModelMapper modelMapper(){ ModelMapper modelMapper = new ModelMapper(); Converter<Set<Autor>, Set<Integer>> autoresParaAutoresId = context -> { Set<Autor> source = context.getSource(); if (source == null) { return null; } return source.stream() .filter(Objects::nonNull) // 过滤null的Autor对象 .map(Autor::getId) .filter(Objects::nonNull) // 过滤null的ID值 .collect(Collectors.toSet()); }; Converter<Set<Genero>, Set<Integer>> generosParaGenerosId = context -> { Set<Genero> source = context.getSource(); if (source == null){ return null; } return source.stream() .filter(Objects::nonNull) .map(Genero::getId) .filter(Objects::nonNull) .collect(Collectors.toSet()); }; modelMapper.typeMap(Livro.class , LivroCriadoDto.class).addMappings( src -> { src.using(autoresParaAutoresId).map(Livro::getAutores, LivroCriadoDto::setAutores); src.using(generosParaGenerosId).map(Livro::getGeneros, LivroCriadoDto::setGeneros); }); return modelMapper; } }
方案2:从源头避免集合中出现null元素
在Livro实体中添加关联对象的校验逻辑,确保不会将null对象加入集合:
public class Livro { // ... 其他字段和方法 public void addAutor(Autor autor) { if (autor != null) { this.autores.add(autor); // 如果Autor实体也维护双向关联,同步更新 autor.getLivros().add(this); } } public void addGenero(Genero genero) { if (genero != null) { this.generos.add(genero); genero.getLivros().add(this); } } }
方案3:处理Hibernate懒加载问题(若存在)
如果是因为关联集合懒加载、转换时Session已关闭导致无法访问元素,需在Service层确保集合初始化:
- 使用JPQL的
fetch join查询时直接加载关联集合:
@Query("SELECT l FROM Livro l JOIN FETCH l.autores JOIN FETCH l.generos WHERE l.id = :id") Livro findByIdWithAssociations(@Param("id") Integer id);
- 或手动触发集合初始化:
import org.hibernate.Hibernate; // ... Livro livro = livroRepository.findById(id).orElseThrow(); Hibernate.initialize(livro.getAutores()); Hibernate.initialize(livro.getGeneros());
方案4:优化转换器的类型兼容性
将转换器的源类型改为Collection,兼容Hibernate的PersistentSet及其他集合实现:
Converter<Collection<Autor>, Set<Integer>> autoresParaAutoresId = context -> { Collection<Autor> source = context.getSource(); if (source == null) { return null; } return source.stream() .filter(Objects::nonNull) .map(Autor::getId) .filter(Objects::nonNull) .collect(Collectors.toSet()); };
验证修复
修改后重新执行转换代码,确认空指针异常消失,且LivroCriadoDto中的autores和generos集合正确填充了对应实体的ID。
内容的提问来源于stack exchange,提问作者Natasha Mota
相关产品推荐
相关产品推荐

