NullPointerException при введении EJB в Java-классе

Я думаю, эта проблема возникает, потому что я не получил что-то с EJB. У меня есть класс обслуживания для моего объекта, который является @Stateless. Когда я использую его, вводя @EJB в моей модели с ограниченной областью охвата, все в порядке. Но теперь я хотел использовать эту службу EJB в DataModel, который я перезаписал для использования в моей модели презентации:

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; 
    }
}

При выполнении я получаю исключение NullPointerException в позиции "users = service.findAllUsers();" То же самое работает, когда я перезаписываю этот DataModel в моей модели презентации:

@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 ; 
                }
        };
    }
}

Невозможно ли внедрить EJB в обычный Java-класс? Что мне делать, что мне не нужно определять DataModel в модели презентации?

Спасибо

Ответ 1

EJB вводятся только в управляемый beans. A bean управляется, когда ему управляют некоторые контейнеры для инъекций, например, через собственный JSF @ManagedBean, CDI @Named и т.д. Вы даже можете ввести EJB в другой EJB. Вы не можете вводить EJB в неуправляемый класс (вы можете вручную захватить его из JNDI, но это просто уродливо).

У вас есть в основном следующие возможности:

  • В @PostConstruct вашего управляемого bean, постройте datamodel, посредством которого вы передаете результат в качестве аргумента (обратите внимание, что это также то, как стандартные модели данных, такие как ListDataModel).

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

  • Сделайте тег LazyUserDataModel, в котором вы попросите пользователя предоставить результат.

    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();
    
    }
    

    так что анонимный класс болит меньше

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

  • Сделайте LazyUserDataModel управляемый bean и добавьте его вместо этого.

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

    с

    @Inject
    private LazyUserDataModel lazyUsers;
    

  • Создайте полнофункциональный анонимный экземпляр, как вы поняли.


Несвязанный к конкретной проблеме, нет смысла иметь LazyDataModel, в котором вы предоставляете записи all. Его цель состоит в том, что он предлагает вам возможность запрашивать только подмножество или записи с использованием полномочий SQL (LIMIT, OFFSET и друзей) на основе текущего состояния с разбивкой на страницы, чтобы вам не нужно было иметь сотни, если не тысячи записей в Java-памяти, но только десять или около того. Другими словами, если вы никогда не используете аргумент first и/или pageSize метода load(), вы, скорее всего, совершенно совершенно ошибаетесь.

Ответ 2

Вы можете вводить только beans и EJB внутри beans и EJB, которые создаются контейнером. Не внутри объектов, которые вы создаете, используя new. Контейнер не знает об объектах, которые вы создаете, и, следовательно, не может вводить что-либо в эти объекты.

Итак, просто дайте контейнеру создать экземпляр и введем объект LazyUserDataModel:

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

    ...
}