Компонент OmniFaces CDI @ViewScoped, развернутый в WebSphere 7 (Java EE 5), обнуляет все EJB, внедренные с помощью @EJB: NPE/NullPointerException

У меня есть простой bean-компонент OmniFaces 1.8.3 с областью видимости, успешно развернутый в WebSphere 7 (7.0.50) вместе с OpenWebBeans 1.2.8 (и Mojarra 2.1.27 BTW):

import java.io.Serializable;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.inject.Named;

import org.omnifaces.cdi.ViewScoped;

...

@Named
@ViewScoped
public class CashValueCalculationManager implements Serializable {

    private static final long serialVersionUID = 1L;

    @EJB
    private CashValueCalculationService cashValueCalculationService;

    // the list of entities to be shown in a datatable
    private List<CashValueCalculation> entities;

    @PostConstruct
    public void init() {

        // displays "this.cashValueCalculationService = null" in the log
        System.out.println("this.cashValueCalculationService = " + this.cashValueCalculationService);

        // load list of entities on init
        try {
            this.loadViewData();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public List<CashValueCalculation> getEntities() {
        return this.entities;
    }

    protected CashValueCalculationService getEntityService() {
        return this.cashValueCalculationService;
    }

    protected void loadViewData() throws Exception {

        // NPE here!
        List<CashValueCalculation> cashValueCalculations = this.getEntityService().findAll();

        this.entities = cashValueCalculations;
    }
}

Однако при открытии представления bean-компонента bean-компонент инициализируется запуском метода @PostConstruct для загрузки всех сущностей (только нескольких), но это не удается с NullPointerException в loadViewData(). Возвращенный сервис нулевой... в основном это подтверждается журналом, в котором я также нахожу строку

this.cashValueCalculationService = null

Интерфейс CashValueCalculationService имеет аннотацию @Local, а реализация CashValueCalculationServiceBean - аннотацию @Stateless:

@Local
public interface CashValueCalculationService extends EntityService<Integer, CashValueCalculation> {
    // super interface has findAll()
}

Бин:

@Stateless
public class CashValueCalculationServiceBean extends BaseEntityServiceBean<Integer, CashValueCalculation> implements CashValueCalculationService {
    // super class has findAll() implementation
}

Я успешно внедрил это в управляемые компоненты JSF до того, как попробовал OmniFaces/CDI/OpenWebBeans на WebSphere 7.

Когда приложение развертывается на сервере, появляются следующие записи в журнале:

.
.
.
[13.07.17 16:56:13:889 CEST] 00000013 WebContainerL I   OpenWebBeans Container is starting...
[13.07.17 16:56:13:894 CEST] 00000013 PluginLoader  I   Adding OpenWebBeansPlugin : [OpenWebBeansJsfPlugin]
[13.07.17 16:56:13:899 CEST] 00000013 AbstractMetaD I   added beans.xml marker: wsjar:file:/C:/IBM/WebSphere7.0/AppServer/profiles/CLDSrv7050/installedApps/srv-cld-helNode03Cell/CLD.ear/lib/omnifaces-1.8.3.jar!/META-INF/beans.xml
[13.07.17 16:56:13:901 CEST] 00000013 AbstractMetaD I   added beans.xml marker: file:/C:/IBM/WebSphere7.0/AppServer/profiles/CLDSrv7050/installedApps/srv-cld-helNode03Cell/CLD.ear/cld-web.war/WEB-INF/beans.xml
[13.07.17 16:56:15:051 CEST] 00000013 AbstractMetaD W   Ignoring class [org.omnifaces.facesviews.FacesViewsInitializer] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.ServletContainerInitializer 
[13.07.17 16:56:15:322 CEST] 00000013 AbstractMetaD W   Ignoring class [org.omnifaces.component.output.cache.CacheInitializerListener] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.FilterRegistration 
[13.07.17 16:56:15:328 CEST] 00000013 AbstractMetaD W   Ignoring class [org.omnifaces.util.Platform] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.ServletRegistration 
[13.07.17 16:56:15:581 CEST] 00000013 AbstractMetaD W   Ignoring class [org.omnifaces.facesviews.FacesViewsInitializer] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.ServletContainerInitializer 
[13.07.17 16:56:15:586 CEST] 00000013 AbstractMetaD W   Ignoring class [org.omnifaces.component.output.cache.CacheInitializerListener] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.FilterRegistration 
[13.07.17 16:56:15:588 CEST] 00000013 AbstractMetaD W   Ignoring class [org.omnifaces.util.Platform] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.ServletRegistration 
[13.07.17 16:56:16:438 CEST] 00000013 AbstractMetaD W   Ignoring class [org.omnifaces.facesviews.FacesViewsInitializer] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.ServletContainerInitializer 
[13.07.17 16:56:16:443 CEST] 00000013 AbstractMetaD W   Ignoring class [org.omnifaces.component.output.cache.CacheInitializerListener] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.FilterRegistration 
[13.07.17 16:56:16:446 CEST] 00000013 AbstractMetaD W   Ignoring class [org.omnifaces.util.Platform] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.ServletRegistration 
[13.07.17 16:56:17:199 CEST] 00000013 BeansDeployer I   All injection points were validated successfully.
[13.07.17 16:56:17:236 CEST] 00000013 WebContainerL I   OpenWebBeans Container has started, it took [3345] ms.
[13.07.17 16:56:17:291 CEST] 00000013 config        I   Mojarra 2.1.27 ( 20140108-1632 https://svn.java.net/svn/mojarra~svn/tags/2.1.27@12764) für Kontext '/cld' wird initialisiert.
[13.07.17 16:56:17:739 CEST] 00000013 application   I   JSF1048: PostConstruct/PreDestroy-Annotationen vorhanden.  Verwaltete Bean-Methoden, die mit diesen Annotationen markiert sind, lassen die entsprechenden Annotationen verarbeiten.
[13.07.17 16:56:19:334 CEST] 00000013 config        W   JSF1067: Ressource /WEB-INF/common-ui.taglib.xml, die von der Konfigurationsoption javax.faces.CONFIG_FILES angegeben wird, kann nicht gefunden werden.  Die Ressource wird ignoriert.
[13.07.17 16:56:19:336 CEST] 00000013 config        W   JSF1067: Ressource /WEB-INF/common-functions.taglib.xml, die von der Konfigurationsoption javax.faces.CONFIG_FILES angegeben wird, kann nicht gefunden werden.  Die Ressource wird ignoriert.
[13.07.17 16:56:19:475 CEST] 00000013 PostConstruct I   Running on PrimeFaces 6.0.15
[13.07.17 16:56:19:478 CEST] 00000013 VersionLogger I   Using OmniFaces version 1.8.3
[13.07.17 16:56:19:497 CEST] 00000013 lifecycle     I   JSF1027: [null Die ELResolvers für JSF wurden nicht im JSP-Container registriert.
.
.
.

Записи

Ignoring class [org.omnifaces.facesviews.FacesViewsInitializer] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.ServletContainerInitializer 
Ignoring class [org.omnifaces.component.output.cache.CacheInitializerListener] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.FilterRegistration 
Ignoring class [org.omnifaces.util.Platform] because it could not be loaded: java.lang.NoClassDefFoundError: javax.servlet.ServletRegistration 

представляются наиболее интересными.

Но что они на самом деле означают?

Конечно, несколько ясно, servlet.api классов не хватает.

<dependency org="javax.servlet" name="servlet-api" rev="2.5" />

(Извините, это синтаксис Ant/Ivy)

Однако добавление javax-servlet-api-2.5.jar к развертыванию полностью ломает приложение при входе в систему, говоря: «FacesServlet не является классом сервлета»:

В HTML:

Original Exception:
Error message: javax.servlet.UnavailableException: SRVE0201E: Servlet [javax.faces.webapp.FacesServlet] is not a servlet class.
Error code: 404
Target servlet: Faces Servlet
Stacktrace:
javax.servlet.UnavailableException: SRVE0201E: Servlet [javax.faces.webapp.FacesServlet] is not a servlet class.
     at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:535)
     at com.ibm.ws.webcontainer.servlet.ServletWrapper.handleRequest(ServletWrapper.java:503)
     at com.ibm.ws.webcontainer.servlet.ServletWrapperImpl.handleRequest(ServletWrapperImpl.java:181)
     at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3954)
     at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:276)
     at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:942)
     at com.ibm.ws.webcontainer.WSWebContainer.handleRequest(WSWebContainer.java:1592)
     at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:186)
     at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:453)
     at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewRequest(HttpInboundLink.java:515)
     at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.processRequest(HttpInboundLink.java:306)
     at com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:83)
     at com.ibm.ws.tcp.channel.impl.AioReadCompletionListener.futureCompleted(AioReadCompletionListener.java:165)
     at com.ibm.io.async.AbstractAsyncFuture.invokeCallback(AbstractAsyncFuture.java:217)
     at com.ibm.io.async.AsyncChannelFuture.fireCompletionActions(AsyncChannelFuture.java:161)
     at com.ibm.io.async.AsyncFuture.completed(AsyncFuture.java:138)
     at com.ibm.io.async.ResultHandler.complete(ResultHandler.java:204)
     at com.ibm.io.async.ResultHandler.runEventProcessingLoop(ResultHandler.java:775)
     at com.ibm.io.async.ResultHandler$2.run(ResultHandler.java:905)
     at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1646)

Мне пришлось перевести сообщение об ошибке как можно лучше. WebSphere 7 BTW - это контейнер Servlet 2.5, поэтому проблема может быть связана с загрузчиком классов...?

БОЛЬШОЙ ВОПРОС(ы):

Почему эта установка не может внедрить EJB через @EJB в основном используемом сценарии (без зависимости javax.servlet)? Похоже, что bean-компонент и менеджер bean-компонентов присутствуют, так почему же он не может внедряться через @EJB?

Как вы можете вылечить это? Можно ли это сделать вообще?


person Kawu    schedule 13.07.2017    source источник
comment
Что касается проблемы, не связанной с классом сервлета, вы не можете добавить свой собственный API-интерфейс сервлета в приложение, установленное в WebSphere. Веб-контейнер загружает API из своих собственных библиотек, а затем загружает класс реализации из вашего приложения. Если ваша реализация ссылается на другой класс API, JVM не будет считать их совместимыми (поскольку базовые классы были загружены разными загрузчиками классов) и выдаст исключение.   -  person Jarid    schedule 13.07.2017
comment
Есть ли в WAS 7 место для размещения JAR-файлов, чтобы загрузчик классов API сервлета и OpenWebBeans были одинаковыми?   -  person Kawu    schedule 17.07.2017
comment
Просто полагайтесь на версию, которая поставляется с сервером. Есть некоторые технологии Java, для которых вы можете добавить свой собственный API вместе с вашим приложением, но Servlet не входит в их число, потому что его функциональность требует взаимодействия между кодом вашего приложения и средой выполнения сервера.   -  person Jarid    schedule 17.07.2017
comment
Я понимаю, что этот комментарий не очень поможет вам с исходной проблемой, которая выглядела как проблемы с загрузкой классов для этих классов сервлетов... в этом отношении, возможно, вы включили некоторые из ваших jar-файлов приложений в путь к классу JVM сервера (а не просто упаковать их в приложение)? Вещи в пути к классу JVM не могут получить доступ к API Java EE на сервере, потому что они находятся в родительском загрузчике. Если стеки этих исключений попали куда-то в журнал, это может сказать вам, какой загрузчик использовался.   -  person Jarid    schedule 17.07.2017


Ответы (2)


Встраиваете ли вы свою собственную реализацию JSF (Myfaces) и CDI (OpenWebBeans) в свое приложение? Если вы это сделаете, прочитайте документ о том, как настроить WAS для использования вашей собственной реализации JSF. Вы не можете переопределить/использовать реализацию CDI в WAS. Также вы можете внедрить EJB способом CDI (@Inject) вместо способа EJB.. (@EJB)?

person titou10    schedule 14.07.2017

WAS-7 реализует стандарт JavaEE 5. Это еще не включает CDI. Это означает, что также нет интеграции между EJB и CDI.

Что вы можете сделать, так это написать расширение CDI, которое использует ProcessAnnotatedType, и для всех классов CDI вы создаете собственный программный компонент Bean для каждого найденного @EJB. Этот пользовательский компонент просто ищет EJB через JNDI и все.

Если вам это нужно всего несколько раз, вы также можете использовать метод @PostConstruct и получить EJB из контекста JNDI непосредственно в классе.

person struberg    schedule 25.07.2017