[英]How to define a method in an interface that can return a list of any type without throwing unchecked assignment warnings?
[英]How to retrieve a list of objects from generic interface without unchecked assignment?
我有以下界面:
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
行為不應該一樣嗎? 看起來似乎並不一致。
在這種情況下,如何消除原始類型? 我已經嘗試了幾件事:
從接口中刪除<T extends User>
並將其應用於這樣的方法:
<U extends User> List<U> findAll(UserCriteria userCriteria, PageDetails pageDetails);
對於該服務來說,這很好用,但是存儲庫實現現在會發出有關未檢查的覆蓋的警告(返回類型需要未檢查的轉換)。
我還嘗試過從接口和方法中刪除泛型,同時保持返回列表的泛型:
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找不到以這種方式自動連線的bean,因為JpaUserRepository是UserRepository<JpaUser>
。 服務層不知道存儲庫的實現。
如果您顯示了如何聲明userRepository
,這將有所幫助,因為缺少該聲明。 但問題是,庫具有泛型類型<T extends User>
,這是不一樣的<User>
,這就是為什么你的代碼是給予警告。
問題不是警告,而是泛型類型的正確用法。 我猜你的userRepository
聲明如下:
@Autowired
private JpaUserRepository userRepository;
但這意味着名稱不正確。 畢竟,它不是User
對象的存儲庫,而是JpaUser
對象的存儲庫。
現在,您可能會說JpaUser
是從User
派生的。 但這不是Java泛型的工作方式。 Java Generics FAQ那里有很好的資源。 確實值得一讀。
現在,我將在某種程度上進行推測,因為我認為您是在向用戶公開存儲庫,但您不想公開JpaUser
類。 但這沒有任何意義,因為存儲庫是一個非常基本的接口,您不應該在庫中公開它。
因此,在沒有所有信息的情況下,通過進行有根據的猜測,我可以看到兩種情況:
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());
}
它編譯時沒有任何警告,因為編譯器會推斷出正確的類型。 我承認我發現它缺乏一定的優雅,但它確實有效。
以下應該可以正常工作,沒有例外:
UserRepository<user> userRepository = ...
List<User> users = userRepository.findAll(userCriteria, pageDetails);
附帶說明,與您的問題無關,您可能需要考慮如下定義類:
@Repository
public class JpaUserRepository implements UserRepository<? extends JpaUser> {
public List<? extends JpaUser> findAll(UserCriteria userCriteria, PageDetails pageDetails) {
//implementation
}
public JpaUser findByEmail(String email) {
//implementation
}
}
由於返回的列表是不可修改的,因此可以在實現中提供更多的靈活性。 它允許子類返回包含JpaUser子類的列表。
因此,例如,如果有一個名為AwesomeJpaUser的子類,則該子類可以安全地返回List。 在您當前的實現中,這是不允許的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.