Spring ConverterNotFoundException:Asset无法转换为AssetPageView
报错信息:
org.springframework.core.convert.ConverterNotFoundException: 未找到能够将类型[com.skywarelabs.runwayreporting.api.modules.asset.Asset]转换为类型[com.skywarelabs.runwayreporting.api.modules.asset.AssetPageView]的转换器
存在两个Repository方法,预期均返回Page<T>对象。调用findPageByAerodrome可正常运行,但调用findPageByFilter时触发上述错误,需要使用findPageByFilter以扩展更多过滤参数。
Repository代码:
public interface AssetRepository extends PageCrudRepository<Asset, Long> { @Query("SELECT a FROM Asset a WHERE " + "(a.aerodrome = :aerodrome)") <T> Page<T> findPageByFilter(@Param("aerodrome") Aerodrome aerodrome, Pageable pageable, Class<T> type); <T> Page<T> findPageByAerodrome(@Param("aerodrome") Aerodrome aerodrome, Pageable pageable, Class<T> type); }
原因分析
Spring Data JPA的自动生成查询方法(如findPageByAerodrome)会自动处理实体到DTO的转换逻辑,但带@Query注解的自定义查询方法不会触发该自动转换,因此直接返回的Asset实体无法被转换为AssetPageView。
解决方法
自定义查询直接构造DTO
在@Query中调用AssetPageView的构造函数,直接返回目标类型,避免后续转换:@Query("SELECT new com.skywarelabs.runwayreporting.api.modules.asset.AssetPageView(a.id, a.name, ...) " + "FROM Asset a WHERE a.aerodrome = :aerodrome") <T> Page<T> findPageByFilter(@Param("aerodrome") Aerodrome aerodrome, Pageable pageable, Class<T> type);注意:需确保
AssetPageView存在对应参数的构造函数,参数顺序要与查询中选取的字段一致。注册全局类型转换器
创建转换器类并注册到Spring容器,让框架自动完成实体到DTO的转换:@Component public class AssetToAssetPageViewConverter implements Converter<Asset, AssetPageView> { @Override public AssetPageView convert(Asset source) { AssetPageView view = new AssetPageView(); // 手动映射字段,例如 view.setId(source.getId()); return view; } }此方式适合需要全局复用转换逻辑的场景,自定义查询只需返回
Asset实体,由Spring后续自动转换。使用Spring Data投影接口
若AssetPageView是接口形式的投影,可直接修改方法返回类型,无需传递Class<T>参数:@Query("SELECT a FROM Asset a WHERE a.aerodrome = :aerodrome") Page<AssetPageView> findPageByFilter(@Param("aerodrome") Aerodrome aerodrome, Pageable pageable);前提是
AssetPageView接口的方法名与Asset实体的字段getter方法对应,Spring会自动处理投影转换。
内容的提问来源于stack exchange,提问作者Werner Reiche

