Yesterday I got hit by a very frustrating problem in developing a Java EE 6 web application under Oracle GlassFish 3.1 Application Server, using EJB 3.1, CDI, and JSF 2.0 EL expression.
The error message:
SEVERE: Error Rendering View[/pages/refills.xhtml]
javax.el.ELException: /pages/refills.xhtml: The class 'com.abispulsa.bisnis.service.org$jboss$weld$bean-com$abispulsa$bisnis$jsf-SessionBean-RefillManager_$$_WeldProxy' does not have the property 'summary'.
at com.sun.faces.facelets.compiler.TextInstruction.write(TextInstruction.java:88)
It happens with this very simple JSF 2.0 Facelets tag:
<p>Records: #{refillManager.summary}</p>
Where refillManager is a EJB 3.1 bean:
import javax.ejb.Stateless;
import javax.inject.Named;
import com.abispulsa.refill.PendingHandler;
@Named("refillManager")
@Stateless
public class RefillManager implements PendingHandler {
Google Searches exposed many different issues, but nothing useful for my problem.
What I know is that it's caused by @Stateless, when I remove it and simply use CDI with @ApplicationScoped, it works perfectly. Of course at that point I lose declarative JPA transactions.
(note: You can use declarative transactions without EJB using Seam Persistence CDI extensions).
To add to the frustration, I can't seem to reproduce the problem with another EJB + CDI bean. The others work fine!
I found the solution while reading the excellent Java EE 6 Book Enterprise JavaBeans 3.1 from O'Reilly. It is @javax.ejb.LocalBean !
Cause of the problem is @Stateless/@Stateful session bean that implements an interface, but not marked it as @javax.ejb.LocalBean.@LocalBeans designates that a session bean exposes a no-interface view. If a bean implements interface(s), it seems EJB only exposes those interfaces, meaning JSF 2.0 EL will not be able to access getter/setters that are not part of the declared interfaces (although they're accessible using the concrete class). This may also happen to objects from "rich" languages like Groovy or Scala.Solution:Annotate the class with @javax.ejb.LocalBean.
Alternatives:
Example:
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.inject.Named;
import com.abispulsa.refill.PendingHandler;
@Named("refillManager")
@Stateless
@LocalBean
public class RefillManager implements PendingHandler {
Alternatives:
- Use EJB + JSF ManagedBean in XML, not CDI.
- Use CDI + Seam Persistence / Solder, not EJB. (I guess prefer this one)
If you want to develop enterprise web applications using the latest Java EE 6 and EJB 3.1 technology be sure to get Enterprise JavaBeans 3.1 book from O'Reilly.
No comments:
Post a Comment