[UPDATE : Dopo la discussione sul forum Glassfish/ML a http://forums.java.net/jive/thread.jspa?messageID=480532 un bug è stata depositata contro Glassfish https://glassfish.dev.java.net/issues/show_bug.cgi?id=13040 per questo problema.]"Impossibile convertire ejbRef per EJB" sul CDI (Weld) iniezione di @Stateless EJB in @SessionScoped JSF2 fagiolo in Glassfish
Sto provando a iniettare una vista no-interface locale di un bean EStat @ in un bean di supporto JSF2 @Named @ javax.enterprise.context.SessionScoped. L'EJB è uno dei tanti che estendono una classe base generica astratta. L'inserimento di "@Inject TheEJBClass varName" non riesce con "Impossibile convertire ejbRef per ejb TheEJBClass in un oggetto business di tipo classe my.package.name.TheAbstractBase". [modifica: In realtà, l'iniezione ha esito positivo, ma la risoluzione del metodo nel proxy iniettato per i metodi ereditati dalle superclassi fallisce.] Se uso "@EJB TheEJBClass varName", varName rimane nullo, ovvero non viene iniettato nulla.
Dettagli:
Io corro Glassfish 3.0.1 su Linux (Ubuntu 10.04 nel caso in cui è importante) e avendo reali problemi di gestione iniezione dei miei EJB modello dati nella mia sessione JSF2 ambito modelli utilizzando CDI (saldatura) . E sì, prima che tu me lo chieda, ho bean.xml sul posto e CDI si sta attivando per eseguire l'iniezione.
Se inietto con un'annotazione @EJB, ad esempio:
@EJB TheEJBClass memberName;
... il bean non è effettivamente iniettata, lasciando memberName nullo.
Se faccio l'iniezione con un'annotazione CDI @Inject:
@Inject TheEJBClass memberName;
... poi CDI si lamenta quando chiamo un metodo di "memberName" che è implementata in una superclasse di TheEJBClass e non sottoposto a override in TheEJBClass sua auto, riportando:
java.lang.IllegalStateException: Unable to convert ejbRef for ejb TheEJBClass to a business object of type class my.package.name.TheAbstractBase
at
com.sun.ejb.containers.EjbContainerServicesImpl.getBusinessObject(EjbContainerServicesImpl.java:104)
at
org.glassfish.weld.ejb.SessionObjectReferenceImpl.getBusinessObject(SessionObjectReferenceImpl.java:60)
....
ho provato a convertire la base per classe concreta e de-generifying, ma lo stesso problema, quindi non credo che mi colpisce gli insetti di saldatura con basi generiche (https://jira.jboss.org/browse/WELD-305, https://jira.jboss.org/browse/WELD-381, https://jira.jboss.org/browse/WELD-518).
Un profilo del codice, con la qualificazione pacchetto completo sulle annotazioni aggiunte per chiarezza, è:
// JSF2 managed backing bean.
//
// Called via #{someJSF2Model.value} in a JSF2 page
//
@javax.inject.Named
@javax.enterprise.context.SessionScoped
public class SomeJSF2Model implements Serializable {
@javax.inject.Inject TheEJBClass member;
public Integer getValue() {
return member.getValue();
}
// blah blah
}
// One of several EJB classes that extend TheAbstractBase
@javax.ejb.Stateless
public class TheEJBClass extends TheAbstractBase {
// blah blah
// does **NOT** override "getValue()"
}
public abstract class TheAbstractBase {
// blah blah
public Integer getValue() {
return 1;
}
}
Nota che l'iniezione fa lavoro se sovrascrivo TheAbstractBase.getValue() in TheEJBClass, o se io chiamare un metodo definito in TheEJBClass e non una superclasse. Sembra che il problema sia qualcosa a che fare con l'ereditarietà.
Il codice molto simile che utilizzava le funzioni di ciclo di vita e di iniezione incorporate di JSF2 ha funzionato, ma dato che questo è un nuovo progetto e il CDI è dove si stanno dirigendo le cose in futuro, ho pensato che fosse meglio provare per CDI. Ecco quello che ho iniziato con l'utilizzo di iniezione JSF2/EJB, che ha funzionato:
// JSF2 managed backing bean. Using @ManagedBean and JSF2's @SessionScoped
// instead of CDI @Named and CDI @SessionScoped this time.
//
@javax.faces.bean.ManagedBean
@javax.faces.bean.SessionScoped
public class SomeJSF2Model implements Serializable {
@javax.ejb.EJB TheEJBClass member;
public Integer getValue() {
return member.getValue();
}
// blah blah
}
// One of several EJB classes that extend TheAbstractBase
// Unchanged from CDI version
@javax.ejb.Stateless
public class TheEJBClass extends TheAbstractBase {
// blah blah
// does **NOT** override "getValue()"
}
// Unchanged from CDI version
public abstract class TheAbstractBase {
// blah blah
public Integer getValue() {
return 1;
}
}
Attualmente sto lavorando a mettere insieme un caso di test self-contained, ma ho pensato di sparare la questione ora nel caso in cui questo è qualcosa in cui sto solo facendo qualcosa di stupido o c'è una soluzione ben nota che il mio Google-fu non è in grado di trovare. Perché ha funzionato con l'iniezione JSF2/EJB, ma fallisce con l'iniezione CDI?
(Da ri-postato sui forum Glassfish come http://forums.java.net/jive/thread.jspa?threadID=152567)
Ho creato un test case che dimostra questo problema. Sembra dipendere da come il wrapper JavaAssist generato da CDI risolva i riferimenti ai metodi definiti nelle superclassi. Il problema non è in realtà al momento dell'iniezione, ma al momento un metodo ereditato da una superclasse viene chiamato tramite il wrapper iniettato. L'uso della denominazione e dell'ambito JSF2 o CDI non ha nulla a che fare con esso, è solo @EJB vs @Inject Vedere commenti ed esempi in: http://www.postnewspapers.com.au/~craig/public_files_keep/ ErrorDemo.zip (src) e http://www.postnewspapers.com.au/~craig/public_files_keep/ErrorDemo.war (webapp). –
... e per il dolore bonus, il problema è praticamente invertito in JBoss AS 6. L'iniezione CDI funziona bene, ma l'iniezione JSF2 fallisce. –