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

使用@Query投影至自定义类时无法正常工作的问题

解决Spring Data JPA @Query投影时的ConverterNotFoundException问题

我之前也踩过这个坑!当用Spring Data JPA做投影时,派生查询(比如findPersonSummaryById(long id))不管是接口投影还是带兼容构造方法的类投影都能正常工作,但一旦用@Query写自定义字段查询,就会出现ConverterNotFoundException,本质是Spring Data处理这两种查询的投影逻辑不一样。

问题根源

  • 派生查询(由方法名自动生成SQL的那种):Spring Data会自动识别投影类型,如果是类投影,会直接调用对应的构造方法来实例化对象;如果是接口,会动态生成代理类实现接口并映射字段。
  • 自定义@Query查询:当你写SELECT name AS name, age AS age FROM Person...时,JPA默认会返回一个HashMap<String, Object>来存储字段名和对应的值,这时候Spring Data不知道要把这个Map转换成你的PersonSummary类,所以会抛出转换器找不到的异常。

几种解决方案

1. 改用接口投影(最省心)

如果你的投影只是用来获取数据,不需要修改,直接把PersonSummary改成接口形式:

public interface PersonSummary {
    String getName();
    int getAge();
}

不管是派生查询还是自定义@Query查询,Spring Data都会动态生成代理类实现这个接口,自动把查询结果映射到接口的getter方法上,完美解决问题。

2. 在@Query中直接调用类的构造方法(适合类投影)

如果一定要用类投影,直接在JPQL语句里显式调用PersonSummary的构造方法,注意要写全类名:

@Query("SELECT new com.example.PersonSummary(p.name, p.age) FROM Person p WHERE p.id = :id")
PersonSummary findPersonSummaryByIdQuery(@Param("id") long id);

需要确保构造方法的参数顺序、类型和SELECT中字段的顺序、类型完全匹配,这样JPA会直接创建PersonSummary实例,不会返回Map。

3. 注册自定义转换器(复杂场景适用)

如果不想修改JPQL语句,可以自定义一个转换器,把HashMap转换成PersonSummary,然后注册到Spring容器中:

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.util.Map;

@Component
public class MapToPersonSummaryConverter implements Converter<Map<String, Object>, PersonSummary> {
    @Override
    public PersonSummary convert(Map<String, Object> source) {
        PersonSummary summary = new PersonSummary();
        summary.setName((String) source.get("name"));
        summary.setAge((Integer) source.get("age"));
        return summary;
    }
}

这样Spring Data在遇到需要把Map转成PersonSummary的场景时,会自动使用这个转换器。

补充说明

这个问题其实是Spring Data JPA的一个已知问题,对应编号DATAJPA-1003。虽然后续版本优化了部分投影场景,但自定义@Query的类投影还是需要通过上面的方法来处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:30:09