Kirjautuminen

Haku

Tehtävät

Keskustelu: Nettisivujen teko: Java EE ongelma : JSF EJB

Sivun loppuun

Wizand [01.04.2011 14:12:27]

#

Terve.

Törmäsin seuraavanlaiseen ongelmaan, enkä osaa selittää sitä (tai täsmentää riittävän tarkasti jotta osaisin etsiä kirjoista) joten ajattelin josko täältä löytyisi rautaisia osaajia jotka tuntevat Java EE tekniikan salat.

Eli pseudona näin:
JSF-sivu kutsuu Managed Beanin metodia joka kutsuu toisen luokan metodia. Tämän toisen luokan pitäisi käyttää EJB:tä mutta jostain syystä tämä ei onnistu (null pointer)

Rakensin seuraavanlaisen testiprojektin jonka toivon selkeyttävän ongelmaa. Siinä yksinkertaisesti rakennetaan metodiketju sivun kautta mb:iin pojon kautta ejb:hen.

index.xhtml
TULOSTAA VAIN "TESTI" LINKIN JOLLA KUTSUTAAN MANAGEDBEANIN METODIA testi()

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head />

    <h:body>

        <h:form>
            <h:commandLink action="#{managedBean.testi()}">TESTI</h:commandLink>
        </h:form>
    </h:body>
</html>

ManagedBean -luokka:

package beans;

import javax.faces.bean.SessionScoped;
import javax.inject.Named;
//import javax.enterprise.context.SessionScoped;

@Named(value="managedBean")
@SessionScoped
public class ManagedBean {

    Pojo pojo;
    ManagedBean2 mb2;

    public ManagedBean() { pojo = new Pojo(); }

    public void testi() {
        System.out.println("MANAGED BEAN testi() HUUDETTU");
        pojo.testi();
        //mb2.testi();
    }
}

Pojo -luokka

package beans;
import javax.ejb.EJB;

public class Pojo {
    @EJB
    private Ejb ejb;

    public void testi() {
        System.out.println("POJO testi() HUUDETTU");
        ejb.testi();
    }
}

Ejb -luokka

package beans;

import javax.ejb.Stateless;

@Stateless
public class Ejb {

    public void testi() {
        System.out.println("EJB testi() HUUDETTU");
    }
}

Tulosteet ovat tässä:

INFO: MANAGED BEAN testi() HUUDETTU
INFO: POJO testi() HUUDETTU
SEVERE: java.lang.NullPointerException
javax.faces.el.EvaluationException: java.lang.NullPointerException

...
sitten se stacktrace

Stacktrace on tässä:

SEVERE: java.lang.NullPointerException
javax.faces.el.EvaluationException: java.lang.NullPointerException
        at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
        at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
        at javax.faces.component.UICommand.broadcast(UICommand.java:315)
        at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:775)
        at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1267)
        at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
        at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
        at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
        at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
        at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
        at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
        at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
        at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
        at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
        at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
        at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
        at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
        at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
        at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
        at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
        at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
        at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
        at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
        at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
        at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
        at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
        at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.NullPointerException
        at beans.Pojo.testi(Pojo.java:10)
        at beans.ManagedBean.testi(ManagedBean.java:18)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at javax.el.BeanELResolver.invokeMethod(BeanELResolver.java:737)
        at javax.el.BeanELResolver.invoke(BeanELResolver.java:467)
        at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:246)
        at com.sun.el.parser.AstValue.invoke(AstValue.java:228)
        at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:297)
        at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:43)
        at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:72)
        at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:98)
        at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
        ... 32 more

WARNING: #{managedBean.testi()}: java.lang.NullPointerException
javax.faces.FacesException: #{managedBean.testi()}: java.lang.NullPointerException
        at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118)
        at javax.faces.component.UICommand.broadcast(UICommand.java:315)
        at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:775)
        at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1267)
        at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
        at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
        at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
        at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1523)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:279)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:188)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:641)
        at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97)
        at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:85)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:185)
        at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:325)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:226)
        at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:165)
        at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:791)
        at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:693)
        at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:954)
        at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:170)
        at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:135)
        at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:102)
        at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:88)
        at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:76)
        at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:53)
        at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:57)
        at com.sun.grizzly.ContextTask.run(ContextTask.java:69)
        at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:330)
        at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:309)
        at java.lang.Thread.run(Thread.java:619)
Caused by: javax.faces.el.EvaluationException: java.lang.NullPointerException
        at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
        at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
        ... 31 more
Caused by: java.lang.NullPointerException
        at beans.Pojo.testi(Pojo.java:10)
        at beans.ManagedBean.testi(ManagedBean.java:18)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at javax.el.BeanELResolver.invokeMethod(BeanELResolver.java:737)
        at javax.el.BeanELResolver.invoke(BeanELResolver.java:467)
        at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:246)
        at com.sun.el.parser.AstValue.invoke(AstValue.java:228)
        at com.sun.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:297)
        at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:43)
        at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:72)
        at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:98)
        at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
        ... 32 more

Pastean mieluusti lisätietoa kysyttäessä, en vaan oikein tiedä mikä on relevanttia.

Kysymys kuuluukin jotta miksi tuo ei onnistu? Miten tämä kuuluisi toteuttaa oikein?

EDIT: Unohdin mainita, jotta ensin ajattelin ettei pojoon voida annotoida EJB:tä mutta kokeilin saman managed beanin kanssa (jsf->mb->mb->ejb) ja yhtä lailla tulee nullpointerpoikkeus. Huomionarvoista on myöskin se, että EJB:n käyttä suoraan ensimmäisestä managedbeanista toimii vallan hienosti.

Macro [01.04.2011 14:50:09]

#

Ehkä sinun tulisi ensin luoda se EJB-olio? Pojo-luokassa kutsutaan olemattoman olion metodia.

Wizand [01.04.2011 16:23:17]

#

Macro kirjoitti:

Ehkä sinun tulisi ensin luoda se EJB-olio? Pojo-luokassa kutsutaan olemattoman olion metodia.

Ei suinkaan. Enterprise Java Bean tulee poolista jonne on luotu instansseja sovelluksen käynnistys(/deployement) -vaiheessa. Tuo @EJB ohjaa ejb:n paikalle (dependency injection?)

"http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/EJBConcepts9.html"

Wizand [01.04.2011 21:06:47]

#

Tässä viisauksia odotellessa kierrän ongelmaa niin, että injektoin EJB-instanssin suoraan siihen ensimmäiseen managedbeaniin ja lähetän sen metodin parametreissä sinne seuraavaan.

Toimii mutta on rumaa ja tuntuu pahalta, jos äiti näkisi niin ei olisi pojastaan ylpeä. Eli toivottavasti joku täällä osaa ohjata parempaan ratkaisuun.

kayttaja-2499 [01.04.2011 23:15:14]

#

Jos olen ymmärtänyt oikein, ei EJB:itä injektoida automaagisesti joka paikkaan, ei varsinkaan POJO:hin. Eli kysynkin, miksi ihmeessä POJO:sta pitää kutsua EJB:tä?

Wizand [02.04.2011 02:14:40]

#

kayttaja-2499 kirjoitti:

Jos olen ymmärtänyt oikein, ei EJB:itä injektoida automaagisesti joka paikkaan, ei varsinkaan POJO:hin. Eli kysynkin, miksi ihmeessä POJO:sta pitää kutsua EJB:tä?

Tässä EJB toimii lähinnä data access object -mielessä, ja toki nyt pojoillakin saattaa olla tarvetta kammeta tietokannasta tavaraa.

Ojelmarakenne on jotakuinkin niin, että käyttöliittymä- ja toiminnallisen kerroksen välissä on pari mangedbeania ikäänkuin rajapintana, toiminnallinen kerros koostuu näistä pojoista (eli tässä tapauksessa tuo Pojo-luokka) ja sitten tämä EJB huolehtisi tietokantayhteyksistä tämän toiminnallisen ja tietokantakerroksen välissä.

Mutta ohjelman kannalta olennaista ei ole, että toiminnalliset luokat ovat pojoja, kuten jo mainitsin, vaikka vaihtaisin nämä pojot vaikka managedbean tyyppisiksi niin tulee silti tuo poikkeus. All in all, kiinnostaisi lähinnä tietää miksi näin tapahtuu, siis ihan teoriatasolla.

EDIT: Jäsentelyä.

LaNu [11.04.2011 17:16:08]

#

Wizand kirjoitti:

Mutta ohjelman kannalta olennaista ei ole, että toiminnalliset luokat ovat pojoja, kuten jo mainitsin, vaikka vaihtaisin nämä pojot vaikka managedbean tyyppisiksi niin tulee silti tuo poikkeus. All in all, kiinnostaisi lähinnä tietää miksi näin tapahtuu, siis ihan teoriatasolla.

Esimerkissä Pojo luodaan new-operaattorilla. Silloin instanssi ei taida olla "manageroitu". En ole ihan varma, mutta ainakaan ei tule mieleen, milloin new-operaattoria käytettäisiin yhdessä CDI:n kanssa. Jos haluaa "manageroidun" version, jossa CDI toimii, pitänee pojo injektoida ManagedBeaniin. Joka tapauksessa, Pojo tarvitsee jonkin luokkatason markkerin, jolla CDI herätetään henkiin ko. luokassa.

Java EE sisältää näemmä nykyään kaksi eri ManagedBean-annotaatiota:
@javax.annotation.ManagedBean
@javax.faces.bean.ManagedBean

Jos ei Pojosta halua tehdä EJB:tä eikä JSF:n ManagedBeania, tuo toinen vaihtoehto on jonkinlainen "kevyt versio". Toimii ainakin Glassfishin 3 versiolla. Eli Pojoon vain luokkatasolle tuo markkeri. Sen jälkeen Pojosta saa manageroidun version ManagedBean-luokassa ainakin näin: @Resource Pojo pojo;.

Ei tullut null pointeria. vinkki tämän toisen ManagedBean-annotaation käyttöön löytyi tuolta: http://blogs.sun.com/alexismp/entry/javax_annotation_managedbean.

Testaillessa oli jäänyt ManagedBeanin rakentajaan new Pojo(). Päätin sitten vielä testailla sen vaikutusta: tein parametrittoman rakentajan ja parametrillisen sekä lisäsin tulosteeseen tiedon, kumpaa käyttäen objekti luotiin. Kutsuin parametrillista ManagedBeanin konstruktorissa, mutta tulosteen mukaan se objekti ei ollut käytössä vaan CDI oli luonut tilalle oman parametrittoman avulla. Kokeilin vielä tuon @EJB:n toimivuutta laittamalla 1s päästä callbackin tekevän säikeen tuohon parametrilliseen rakentajaan. Kun se säie kutsui testi()-metodia, syntyi sama null pointer error kuin ennenkin. Eli CDI ei näiden testailudien pohjalta koske new-operaattorilla luotuja objekteja.

lainaus:

Ojelmarakenne on jotakuinkin niin, että käyttöliittymä- ja toiminnallisen kerroksen välissä on pari mangedbeania ikäänkuin rajapintana, toiminnallinen kerros koostuu näistä pojoista (eli tässä tapauksessa tuo Pojo-luokka) ja sitten tämä EJB huolehtisi tietokantayhteyksistä tämän toiminnallisen ja tietokantakerroksen välissä.

Eikö olisi loogista tehdä näistä pojoista EJB:tä? EJB3 ei ole enää yhtä paha työtehon tappaja kuin vanhemmat. Nykyään hommat hoituu parilla annotaatiolla - kunhan ne menee oikein. CDI:n kanssa jos jotain on pielessä, niin siinä saa aikaiseksi vaikeasti jäljitettäviä ongelmia. Vielä kun stacktracet/virheilmoitukset on 95% epäolennaista roskaa, kuten Java EE:ssä on tapana... ;-(

Tämä CDI on kokonaisuudessaan melkolailla hämmentävää wanhan koulun koodarille. En minä niin vanha ole, mutta tämä vaatii aikalailla erilaista ajattelua.

Edit: Pastean vielä nuo muokatut luokat kokonaisuudessaan, niin näitä jee5/6 temppuja tuntemattomatkin näkee, miten noita objekteja vaan ilmaantuu "tyhjästä".

@Named(value="managedBean")
@SessionScoped
public class ManagedBean {

    @Resource Pojo pojo;

    public ManagedBean() { }

    public void testi() {
        System.out.println("MANAGED BEAN testi() HUUDETTU");
        pojo.testi();
    }
}
@javax.annotation.ManagedBean
public class Pojo {

    public Pojo() { }

    @EJB
    private EjbBean ejbBean;

    public void testi() {
        System.out.println("POJO testi() HUUDETTU");
        ejbBean.testi();
    }
}

Eli noissa esimerkeissä objektien alustukset tapahtuu EJB- ja Resource -annotaatioiden avulla. Palvelin, tai oikeampi nimitys on säilö, container, estii tai luo niiden perusteella tarvittavat objektit.

Wizand [30.04.2011 13:40:26]

#

Kiitoksia LaNu erinomaisesta vastauksesta.

LaNu kirjoitti:

Esimerkissä Pojo luodaan new-operaattorilla. Silloin instanssi ei taida olla "manageroitu". En ole ihan varma, mutta ainakaan ei tule mieleen, milloin new-operaattoria käytettäisiin yhdessä CDI:n kanssa. Jos haluaa "manageroidun" version, jossa CDI toimii, pitänee pojo injektoida ManagedBeaniin. Joka tapauksessa, Pojo tarvitsee jonkin luokkatason markkerin, jolla CDI herätetään henkiin ko. luokassa.

Java EE sisältää näemmä nykyään kaksi eri ManagedBean-annotaatiota:
@javax.annotation.ManagedBean
@javax.faces.bean.ManagedBean

Kuulostaa ihan järkevältä, nyt kun sinä sen sanoit. Nöyräksi vetää -ilmeisesti täälläpäässä ei tuo JavaEE:n sielunelämä olekaan niin tuttu kuin luulin. :P Jotenkin en osannut yhdistää CDI:n toimintaa managedpapuisuuteen.

LaNu kirjoitti:

Jos ei Pojosta halua tehdä EJB:tä eikä JSF:n ManagedBeania, tuo toinen vaihtoehto on jonkinlainen "kevyt versio". Toimii ainakin Glassfishin 3 versiolla. Eli Pojoon vain luokkatasolle tuo markkeri. Sen jälkeen Pojosta saa manageroidun version ManagedBean-luokassa ainakin näin: @Resource Pojo pojo;.

Ei tullut null pointeria. vinkki tämän toisen ManagedBean-annotaation käyttöön löytyi tuolta: http://blogs.sun.com/alexismp/entry/javax_annotation_managedbean.

Testaillessa oli jäänyt ManagedBeanin rakentajaan new Pojo(). Päätin sitten vielä testailla sen vaikutusta: tein parametrittoman rakentajan ja parametrillisen sekä lisäsin tulosteeseen tiedon, kumpaa käyttäen objekti luotiin. Kutsuin parametrillista ManagedBeanin konstruktorissa, mutta tulosteen mukaan se objekti ei ollut käytössä vaan CDI oli luonut tilalle oman parametrittoman avulla. Kokeilin vielä tuon @EJB:n toimivuutta laittamalla 1s päästä callbackin tekevän säikeen tuohon parametrilliseen rakentajaan. Kun se säie kutsui testi()-metodia, syntyi sama null pointer error kuin ennenkin. Eli CDI ei näiden testailudien pohjalta koske new-operaattorilla luotuja objekteja.

Toistan vielä; kiitoksia tyhjentävästä vastauksesta ;).

LaNa kirjoitti:

Eikö olisi loogista tehdä näistä pojoista EJB:tä? EJB3 ei ole enää yhtä paha työtehon tappaja kuin vanhemmat. Nykyään hommat hoituu parilla annotaatiolla - kunhan ne menee oikein.

Voi olla. Tässä haluttiin lähinnä erottaa tietokantakerros selkeästi toiminnallisesta kerroksesta. Tämä oli tosiaan itselle lähinnä teoreettinen kuriositeetti.

LaNa kirjoitti:

CDI:n kanssa jos jotain on pielessä, niin siinä saa aikaiseksi vaikeasti jäljitettäviä ongelmia. Vielä kun stacktracet/virheilmoitukset on 95% epäolennaista roskaa, kuten Java EE:ssä on tapana... ;-(

Tämä CDI on kokonaisuudessaan melkolailla hämmentävää wanhan koulun koodarille. En minä niin vanha ole, mutta tämä vaatii aikalailla erilaista ajattelua.

Edit: Pastean vielä nuo muokatut luokat kokonaisuudessaan, niin näitä jee5/6 temppuja tuntemattomatkin näkee, miten noita objekteja vaan ilmaantuu "tyhjästä".

Preaching to the choir mate ;)


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta