[I've CC'd Sivakumar because of the similarity between this and the
earlier issue I reported, as both involve inconsistencies between Weld
and JSF2 injection in Glassfish. Hope you don't mind.]
Hi
I'm using the Mojarra JSF2 RI embedded in Glassfish 3.0.1 with CDI(weld)
in a new project, and I seem to have hit another odd inconsistency
between CDI and JSF2 injection. The previous one was a glassfish bug,
but I'm not sure if this one is a bug or me doing something silly.
I need to access a DAO facade (a @Stateless EJB) from a JSF2
@FacesConverter. As apparently JSF2 doesn't support DI in converters
(sigh) I have to look the EJB up via JNDI or obtain it indirectly via an
EL lookup on an object that contains a reference to it.
If I do an EL lookup via FacesContext in the converter, I can obtain the
@SessionScoped model bean that has the @Stateless DAO EJB injected into
it. This works fine whether using JSF2 or CDI.
If the model bean is managed using CDI (ie @Named
@javax.enterprise.context.SessionScoped and inject with @Inject), the
field into which the DAO EJB is injected is null when the model bean is
looked up via EL from the FacesConverter, even though it was non-null at
@PostConstruct time in the same object.
If I use JSF2 (ie use @ManagedBean @javax.faces.bean.SessionScoped and
inject with @EJB), the injected dao ejb field is always non-null and can
be accessed and used as expected.
I've produced a self-contained test case in source-code and deployable
war form to demonstrate this inconsistency. It can be found here:
http://www.postnewspapers.com.au/~craig/public_files_keep/ErrorDemo2.war
http://www.postnewspapers.com.au/~craig/public_files_keep/ErrorDemo2.zip
Is this another CDI integration bug? Or is this not meant to work?
A boiled-down outline of the code is that this works:
@ManagedBean
@javax.faces.bean.SessionScoped
public class ModelBean implements Serializable {
private static final long serialVersionUID = 99L;
@EJB DemoEJB demoEJB;
@PostConstruct
protected void postConstruct() {
if (demoEJB == null) throw new IllegalStateException("NoEJB");
}
// blah blah
@FacesConverter(forClass=EntityObject.class)
public static class EntityObjectConverter implements Converter {
@Override
public Object getAsObject(FacesContext context, UIComponent
component, String value) {
ModelBean modelBean =
(ModelBean)context.getApplication()
.getELResolver().getValue(
context.getELContext(), null, "modelBean"
);
System.err.println("(EL) modelBean is " + modelBean +
", modelBean.demoEJB is " + modelBean.demoEJB);
return modelBean.demoEJB.getEntityForKey(value);
}
}
}
but this throws a NullPointerException when accessing members of
ModelBean.demoEJB:
@Named
@javax.enterprise.context.SessionScoped
public class ModelBean implements Serializable {
private static final long serialVersionUID = 98L;
@Inject DemoEJB demoEJB;
@PostConstruct
protected void postConstruct() {
if (demoEJB == null) throw new IllegalStateException("NoEJB");
}
// blah blah
@FacesConverter(forClass=EntityObject.class)
public static class EntityObjectConverter implements Converter {
@Override
public Object getAsObject(FacesContext context, UIComponent
component, String value) {
ModelBean modelBean =
(ModelBean)context.getApplication().getELResolver()
.getValue(
context.getELContext(), null, "modelBean"
);
// Note that "modelBean.demoEJB" is null here. WTF?
// It was a suitable EJB proxy object in @PostConstruct...
System.err.println("(EL) ModelBean is " + modelBean + ",
modelBean.demoEJB is " + modelBean.demoEJB);
return modelBean.demoEJB.getEntityForKey(value);
}
}
}
--
Craig Ringer
Tech-related writing: http://soapyfrogs.blogspot.com/