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

Spring Data CrudRepository的findAll()未返回继承派生实体问题

问题场景

我搭建了如下Spring应用,定义了名为Product的基础实体,通过继承派生出两个子实体(Product > Bike、Product > Wheel),各层代码如下:

控制器层代码

public abstract class ProductController<T extends Product> {
    @Autowired
    private ProductService<T> productService;
    @PostMapping
    public ResponseEntity post(@RequestBody T product) {
        return ResponseEntity.ok(productService.save(product));
    }
    @GetMapping
    public ResponseEntity get() {
        return ResponseEntity.ok(productService.findAll());
    }
}

@RestController
@RequestMapping("/products/categories/bikes")
public class BikeController extends ProductController<Bike> {}

@RestController
@RequestMapping("/products/categories/wheels")
public class WheelController extends ProductController<Wheel> {}

实体类定义

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    public Product() {}
    //getters and setters
}

@Entity
public class Bike extends Product {
    private String color;
    public Bike() {}
    //getters and setters
}
@Entity
public class Wheel extends Product {
    private Double diameter;
    public Wheel() {}
    //getters and setters
}

持久层Repository定义

public interface ProductRepository<T extends Product> extends CrudRepository<T, Long> {}

业务层Service定义

@Service
public class ProductService<T extends Product> {
    @Autowired
    private ProductRepository<T> productRepository;
    public T save(T product) {
        return productRepository.save(product);
    }
    public Iterable<T> findAll() { return productRepository.findAll(); }
}

异常现象

应用启动后会为三个实体分别生成对应的数据表,调用具体子类控制器的post方法时,可正常将对应实体写入对应的数据表中。但调用findAll()方法时,返回的实体并非来自具体子表,而是来自父类Product表。即便已在Repository中指定了对应的实体类型,该问题仍然存在。

问题产生原因
  • 核心冲突来自Java泛型的类型擦除机制和Spring默认单例Bean的管理逻辑。你直接在泛型类ProductService<T>上加了@Service注解,Spring容器只会为这个类创建一个全局唯一的单例Bean,不会为Bike、Wheel两个子类分别生成专属的Service实例。
  • 运行时泛型参数T会被擦除到上界类型Product,因此这个单例Service中自动注入的ProductRepository<T>,最终会被Spring绑定到根实体Product对应的Repository实现,和子类Controller上声明的具体泛型类型没有关联。
  • post接口能正常写入子表,是因为传入的请求体反序列化后本身就是具体子类的实例,Hibernate可以根据对象的实际运行类型判断要写入哪张子表;但findAll()方法没有传入任何实体参数,Repository只能按照自身绑定的根实体类型Product生成查询SQL,JOINED继承策略下查询根实体默认不会关联对应的子表,自然只能查出父表存储的基础数据,无法映射为具体子类的实例。
  • 额外的配置问题是你只定义了一个通用的泛型ProductRepository接口,没有为Bike、Wheel单独声明继承自ProductRepository的子接口,Spring Data JPA本身也不会自动为每个子实体生成专属的Repository实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 04:36:14