2013-08-02 44 views
12

Tôi nghĩ rằng vấn đề này tăng lên vì tôi đã không nhận được một cái gì đó với EJBs. Tôi có một lớp dịch vụ cho thực thể của tôi, đó là @Stateless. Khi tôi sử dụng nó bằng cách tiêm với @EJB trong phiên bản trình bày scoped phiên của tôi, tất cả đều ổn. Nhưng bây giờ tôi muốn sử dụng dịch vụ này EJB trong một DataModel Tôi đã ghi đè để sử dụng trong mô hình trình bày của tôi:NullPointerException khi tiêm EJB trong Java Class

public class LazyUserDataModel extends LazyDataModel<User> { 

    @EJB 
    private UserService service; 

    @Override 
    public List<User> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map filters) { 
     List<User> users; 
     users= service.findAllUsers(); 
     this.setRowCount(users.size()); 
     return users; 
    } 
} 

On thi tôi nhận được một NullPointerException ở vị trí "người dùng = service.findAllUsers();" Các tác phẩm tương tự, khi tôi ghi đè DataModel này trong mô hình bản trình bày của mình:

@Named 
@SessionScoped 
public class UserPM { 
    @EJB 
    private UserService service; 

    private LazyDataModel<User> lazyUsers; 

    public UserPM() { 

      // Don't works 
      //lazyUsers = new LazyUserDataModel(); 

      lazyUsers = new LazyDataModel() { 
      @Override 
       public List<User> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map filters) { 
        List<User> users; 
        users = service.findAllUsers(); 
        this.setRowCount(users .size()); 
        return users ; 
       } 
     }; 
    } 
} 

Không thể Tiêm EJB trong một lớp Java bình thường? Tôi phải làm gì mà tôi không phải định nghĩa DataModel trong mô hình trình bày?

Cảm ơn

+0

Cố gắng đưa BeanInterface của bạn vào chú thích EJB. Tôi có cùng một vấn đề một vài lần trước đây và đã sửa nó. '@EJB (beanInterface = YourInterface.class)' – ZeusNet

Trả lời

13

EJB chỉ được tiêm trong đậu được quản lý. Một bean được quản lý khi nó được quản lý bởi một số container tiêm, chẳng hạn như thông qua JSF của riêng @ManagedBean, của CDI @Named, vv Bạn thậm chí có thể tiêm EJB vào một EJB khác. Bạn không thể tiêm một EJB trong một lớp không được quản lý (tuy nhiên bạn có thể lấy nó từ JNDI theo cách thủ công, nhưng điều đó thật xấu xí).

Bạn đã cơ bản các tùy chọn sau:

  1. Trong @PostConstruct của bean được quản lý của bạn, xây dựng DataModel nhờ đó mà bạn vượt qua kết quả như là đối số (lưu ý rằng đây cũng là mô hình dữ liệu như thế nào tiêu chuẩn như ListDataModel làm việc) .

    @PostConstruct 
    public void init() { 
        lazyUsers = new LazyUserDataModel(service.findAllUsers()); 
    } 
    

  2. Hãy LazyUserDataModel trừu tượng nhờ đó mà bạn yêu cầu người dùng cung cấp kết quả.

    public abstract class LazyUserDataModel extends LazyDataModel<User> { 
    
        @Override 
        public List<User> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map filters) { 
         List<User> users; 
         users = findAllUsers(); 
         this.setRowCount(users.size()); 
         return users ; 
        } 
    
        public abstract List<User> findAllUsers(); 
    
    } 
    

    để các lớp nặc danh đau ít

    lazyUsers = new LazyUserDataModel() { 
        @Override 
        public List<User> findAllUsers() { 
         return service.findAllUsers(); 
        } 
    }; 
    

  3. Hãy LazyUserDataModel một bean được quản lý như tốt và tiêm nó để thay thế.

    @Named @RequestScoped 
    public class LazyUserDataModel extends LazyDataModel<User> { 
        // ... 
    } 
    

    với

    @Inject 
    private LazyUserDataModel lazyUsers; 
    

  4. Tạo một trường hợp vô danh fullfledged giống như bạn hình dung.


Không liên quan cho vấn đề cụ thể, không có điểm của việc có một LazyDataModel nhờ đó mà bạn cung cấp tất cả hồ sơ. Mục đích của nó là nó cung cấp cho bạn khả năng yêu cầu chỉ một tập hợp con hoặc các bản ghi sử dụng các quyền hạn SQL (LIMIT, OFFSET và bạn bè) dựa trên trạng thái được phân trang hiện tại để bạn không cần phải có hàng trăm nếu không phải hàng nghìn bản ghi trong bộ nhớ của Java chỉ mười hay hơn. Nói cách khác, nếu bạn không bao giờ sử dụng đối số first và/hoặc pageSize của phương pháp load(), rất có thể bạn đang tiếp cận hoàn toàn sai.

+0

Cảm ơn câu trả lời chi tiết này @BalusC. Trước khi tôi thử điều này, với hai chủ đề tắt: Tôi biết LazyDataModel đó không có ý nghĩa gì theo cách này. Tôi chỉ muốn đơn giản hóa mã càng nhiều càng tốt. Nhưng những gì tôi không thực sự hiểu là tuyên bố đầu tiên của bạn: Trong những gì nhà xây dựng nên dịch vụ được null? Trong "UserPM công cộng()"? Nếu tôi đã không bỏ qua một cái gì đó thì đây chính xác là cách nó hoạt động cho tôi. – timmornYE

+0

Các phụ thuộc được tiêm không có sẵn trong constrcutor, nhưng chỉ sớm nhất trong '@ PostConstruct', vì lý do đơn giản vì các biến mẫu không thể được thiết lập trước khi cá thể được xây dựng. – BalusC

+0

Giải pháp 4 trông đẹp nhất đối với tôi và hoạt động! Cảm ơn! – timmornYE

2

Bạn chỉ có thể tiêm đậu và EJB bên trong đậu và EJB được tạo bởi vùng chứa. Không phải bên trong các đối tượng mà bạn tự khởi tạo bằng cách sử dụng new. Vùng chứa không biết các đối tượng mà bạn khởi tạo và do đó không thể tiêm bất kỳ thứ gì trong các đối tượng này.

Vì vậy, chỉ cần cho phần thuyết minh container và tiêm đối tượng LazyUserDataModel:

@Named 
@SessionScoped 
public class UserPM { 
    @Inject 
    private LazyUserDataModel lazyUsers; 

    ... 
}