簡體   English   中英

如何在沒有未經檢查的分配的情況下從通用接口檢索對象列表?

[英]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類。 但這沒有任何意義,因為存儲庫是一個非常基本的接口,您不應該在庫中公開它。

因此,在沒有所有信息的情況下,通過進行有根據的猜測,我可以看到兩種情況:

  1. 您無需向用戶公開存儲庫,在這種情況下,您只需處理JpaUser對象。
  2. 您確實希望用戶使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM