我有以下界面:
public interface UserRepository<T extends User> {
List<T> findAll(UserCriteria userCriteria, PageDetails pageDetails);
T findByEmail(String email);
}
及其实现:
@Repository
public class JpaUserRepository implements UserRepository<JpaUser> {
public List<JpaUser> findAll(UserCriteria userCriteria, PageDetails pageDetails) {
//implementation
}
public JpaUser findByEmail(String email) {
//implementation
}
}
现在,当我调用:
User user = userRepository.findByEmail(email);
在我的服务类,一切都很好。
但是当我打电话时:
List<User> users = userRepository.findAll(userCriteria, pageDetails);
我收到未经检查的分配警告,原因是userRepository具有原始类型,因此findAll的结果被擦除。如果确实如此,
findByEmail
是否应该表现出相同的行为?看起来似乎并不一致。在这种情况下,如何消除原始类型?我已经尝试了几件事:
从接口(interface)中删除
<T extends User>
并将其应用于这样的方法:<U extends User> List<U> findAll(UserCriteria userCriteria, PageDetails pageDetails);
对于该服务而言,这很好用,但是存储库实现现在会发出有关未检查的覆盖的警告(返回类型需要未检查的转换)。
我还尝试过从接口(interface)和方法中删除泛型,同时保持返回列表的泛型:
List<? extends User> findAll(UserCriteria userCriteria, PageDetails pageDetails);
这就解决了问题,没有警告,但要求我这样编写服务:
List<? extends User> users = userRepository.findAll(userCriteria, pageDetails);
而且感觉有点笨拙(也许只是我一个人,所以请从“良好编程”的角度告诉我这是否可以接受)。
无论哪种方式,都可以在不影响存储库的情况下获得没有原始类型警告的
List<User>
吗?非常感谢您的宝贵时间。
编辑:我不是在寻找一种转换列表的方法。
编辑2:存储库声明:
private final UserRepository userRepository;
你们中的一些人建议将该声明更改为
UserRepository<User> userRepository;
,这样可以成功删除警告,但是Spring找不到以JpaUserRepository为UserRepository<JpaUser>
进行 Autowiring 的bean。服务层不知道存储库的实现。 最佳答案
如果您演示了如何声明userRepository
,这将有所帮助,因为缺少该声明。但是问题在于,存储库具有通用类型<T extends User>
,这与<User>
不同,这就是为什么您的代码发出警告的原因。
问题不仅仅在于警告,还在于泛型类型的正确用法。我猜你的userRepository
声明如下:
@Autowired
private JpaUserRepository userRepository;
但这意味着名称不正确。毕竟,它不是
User
对象的存储库,而是JpaUser
对象的存储库。现在,您可能会说
JpaUser
是从User
派生的。但这不是Java泛型的工作方式。那里有一个很好的资源Java Generics FAQ。确实值得一读。现在,我将在某种程度上进行推测,因为我认为您是在向用户公开存储库,但您不想公开
JpaUser
类。但这没有任何意义,因为存储库是一个非常基本的接口(interface),您不应该在库中公开它。因此,在没有所有信息的情况下,通过进行有根据的猜测,我可以看到两种情况:
JpaUser
对象即可。 User
对象,在这种情况下,您应该构建一个外观以隐藏存储库。 编辑:我已经快速制作了一个立面类,您可能希望将其用作起点。
public class RepositoryFacade {
private final UserRepository<? extends User> repository;
public RepositoryFacade(UserRepository<? extends User> repository) {
this.repository = repository;
}
public List<User> findAll(final UserCriteria userCriteria, final PageDetails pageDetails) {
return repository.findAll(userCriteria, pageDetails)
.stream()
.collect(Collectors.toList());
}
public User findByEmail(final String email) {
return repository.findByEmail(email);
}
}
public RepositoryFacade getJpaUserFacade() {
return new RepositoryFacade(new JpaUserRepository());
}
它在编译时不会发出任何警告,因为编译器会推断出正确的类型。我承认我发现它缺乏一定的优雅,但确实有效。