Method invocation from JSF-Page failure in PrimeFaces dataTable - WeldClientProxy does not have the property
komat Mar 2, 2012 7:45 AMHello all,
well, I have a problem that's driving me rather insane for quite some time now. Basically I try to invoke a method rather than querying a property of an EJB Bean from a JSF page. And that fails because the CDI Proxy created by Weld doesn't provide that (existing) method. I'm very new to all this web-development / javaee stuff, so any comments would be of great value to me. Actually I now believe the problem lies somewhere else ... so let's get into the details.
Environment: I'm developing a web application based on Seam 3.1.0, JBoss AS 7.1 Final, PrimeFaces 3.1.1 (and probably some other technologies, I didn't start this project). The project is strongly based on the booking example from Seam3 - unfortunately I don't know which version exactly but it certainly predated JBoss AS 7.1 Final (probably sometime in late 2011). The example is available from the Seam 3 release files ( http://seamframework.org/Seam3/Downloads ) or github ( https://github.com/seam/examples/tree/master/booking ). I also use the EntityHome mechanism by Bernard Labno available from https://issues.jboss.org/browse/SEAMPERSIST-59 .
So, basically, I have an Entity Bean (Blah), I have a EJB Bean to access the Entity Bean that is extending EntityHome (BlahHome) and I want to display all Blah's from the database in a table. The relevant JSF part is:
<prime:dataTable var="blah" value="#{blahHome.blubbBlubbMethod('bleh')}"> <prime:column> <f:facet name="header"> <h:outputText value="ID"/> </f:facet> <h:outputText value="#{blah.getId}"/> </prime:column> <prime:column> <f:facet name="header"> <h:outputText value="Name"/> </f:facet> <h:outputText value="#{blah.getName}"/> </prime:column> <prime:column> <f:facet name="header"> <h:outputText value="Description"/> </f:facet> <h:outputText id="desc" value="#{blah.getShortenedDescription}"/> <prime:tooltip for="desc"> <h:outputText value="#{blah.description}" escape="false" class="multilineTooltip"/> </prime:tooltip> </prime:column> <prime:column> <f:facet name="header"> <h:outputText value="End"/> </f:facet> <h:outputText value="#{blah.getEnd}"/> </prime:column> </prime:dataTable>
The vital part is
<prime:dataTable var="blah" value="#{blahHome.blubbBlubbMethod('bleh')}">
where blubbBlubbMethod returns a List of Blah objects and binds the variable called blah to it, which is used to iterate through the list and fills the table (as far as I understand).
The blubbBlubbMethod from the BlahHome class is quite simple and has the following code:
public List<Blah> getBlahblah() { log.info("GETBLAHBLAH CALLED"); List<Blah> blahblah = queries.getBlahs(); return blahblah; } public List<Blah> blubbBlubbMethod(String x) { try { log.info("BLUBBBLUBBMETHOD CALLED with " + x); return getBlahblah(); } catch (Exception e) { log.warn("BLUBBBLUBB: Catched Exception: " + e.getClass().getName() + " - " + e.getMessage()); throw e; } }
Now, there is no javadoc for PrimeFaces, but as far as I understand, it's primarily extending JSF constructs. The specification of dataTable for JSF ( http://javaserverfaces.java.net/nonav/docs/2.0/pdldocs/facelets/h/dataTable.html ) mentions that the "value" attribute of a dataTable must be a ValueExpression that returns an Object. Which, according to the Java EE 6 tutorial ( http://docs.oracle.com/javaee/6/tutorial/doc/bnahu.html#bnahz ) can be a method expression.
But what actually happens is this:
10:14:40,620 SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (http--127.0.0.1-8080-1) Error Rendering View[/blahsMainPage.xhtml]: javax.el.PropertyNotFoundException: /blahsMainPage.xhtml @28,87 value="#{blahHome.blubbBlubbMethod('bleh')}": The class 'ts.test.entity.bean.BlahHome$Proxy$_$$_WeldClientProxy' does not have the property 'blubbBlubbMethod'.
So apparently the proxy class created by Weld for CDI (Dependency Injection) misses the blubbBlubbMethod. And this is the point where I am lost, because I cannot see a reason why a CDI proxy class should miss a standard method (but as I mentioned, I don't really understand these technologies on thoroughly).
But there is more to it. In general, method expressions seem to work. For example, I use
<h:outputText id="desc" value="#{blah.getShortenedDescription}"/>
and that works perfectly well.
The funny thing is, that when I make blubbBlubbMethod a property, by creating a method called getBlubbBlubbMethod(String x), it works. So apparently some part of my stack requires that the expression in the value attribute of the dataTable is a property and method expressions are not supported there. If anyone could point me to a location where this is documented or verify that this is a bug (in which part ?), I'd be immensely grateful.
But the best thing is: what I just posted happens when my BlahHome bean is @ConversationScoped. With @RequestScoped I get the same exception. But I also get more. Look at the following shortened stacktrace:
10:14:40,620 SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (http--127.0.0.1-8080-1) Error Rendering View[/blahsMainPage.xhtml]: javax.el.PropertyNotFoundException: /blahsMainPage.xhtml @28,87 value="#{blahHome.blubbBlubbMethod('bleh')}": The class 'ts.test.entity.bean.BlahHome$Proxy$_$$_WeldClientProxy' does not have the property 'blubbBlubbMethod'. at com.sun.faces.facelets.el.TagValueExpression.getType(TagValueExpression.java:100) [javax.faces-2.1.7.jar:2.1.6-SNAPSHOT] at org.primefaces.component.datatable.DataTable.isLazy(DataTable.java:922) [primefaces-3.1.1.jar:] at org.primefaces.component.datatable.DataTableRenderer.encodeMarkup(DataTableRenderer.java:177) [primefaces-3.1.1.jar:] at org.primefaces.component.datatable.DataTableRenderer.encodeEnd(DataTableRenderer.java:103) [primefaces-3.1.1.jar:] at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:875) [jboss-jsf-api_2.1_spec-2.0.0.Final.jar:2.0.0.Final] at com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:312) [javax.faces-2.1.7.jar:2.1.6-SNAPSHOT] [.....] 10:14:40,649 INFO [ts.test.xxx.exceptioncontrol.GeneralExceptionHandler] (http--127.0.0.1-8080-1) Exception logged by seam-catch catcher: /blahsMainPage.xhtml @28,87 value="#{blahHome.blubbBlubbMethod('bleh')}": The class 'ts.test.entity.bean.BlahHome$Proxy$_$$_WeldClientProxy' does not have the property 'blubbBlubbMethod'. 10:14:41,020 INFO [ts.test.entity.bean.BlahHome] (http--127.0.0.1-8080-1) BLAHHOME POSTCONSTRUCT 10:14:41,022 INFO [ts.test.entity.bean.BlahHome] (http--127.0.0.1-8080-1) BLUBBBLUBBMETHOD CALLED with bleh 10:14:41,023 INFO [ts.test.entity.bean.BlahHome] (http--127.0.0.1-8080-1) GETBLAHBLAH CALLED 10:14:41,024 WARN [ts.test.inventory.BlahQueries] (http--127.0.0.1-8080-1) Exception during DB Query: : org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type javax.enterprise.context.ConversationScoped at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:598) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31] at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:71) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31] at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:104) [weld-core-1.1.5.AS71.Final.jar:2012-02-10 15:31] at org.jboss.weld.proxies.EntityManager$ManagedPersistenceContext$1667316843$Proxy$_$$_WeldClientProxy.createNamedQuery(EntityManager$ManagedPersistenceContext$1667316843$Proxy$_$$_WeldClientProxy.java) [weld-core-1.1.5.AS71.Final.jar:] at ts.test.inventory.BlahQueries.getBlahs(BlahQueries.java:31) [classes:] at ts.test.inventory.BlahQueries$Proxy$_$$_WeldClientProxy.getBlahs(BlahQueries$Proxy$_$$_WeldClientProxy.java) [classes:] at ts.test.entity.bean.BlahHome.getBlahblah(BlahHome.java:91) [classes:] at ts.test.entity.bean.BlahHome.blubbBlubbMethod(BlahHome.java:98) [classes:] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.7.0_147-icedtea] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) [rt.jar:1.7.0_147-icedtea] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.7.0_147-icedtea] at java.lang.reflect.Method.invoke(Method.java:601) [rt.jar:1.7.0_147-icedtea] [.....] 10:14:41,124 INFO [ts.test.entity.bean.BlahHome] (http--127.0.0.1-8080-1) BLAHHOME PREDESTROY
There it is. blubbBlubbMethod is called actually.
Note that the POSTCONSTRUCT log text (from the method annotated with @PostConstruct) only appears after the PropertyNotFoundException arrives.
Now ... what to make of it ? Are there multiple passes when rendereing jsf views ? Is this a PrimeFaces fault ? Why the heck are there differences between @RequestScoped and @ConversationScoped ? How is Weld and CDI related to all of this ? Really, any hints are appreciated tremendously as I'm chewing on this problem for days now.
For further examination I attached all relevant classes, pages, and a more verbose stacktrace to this post - if anything more is needed, I'd be happy to supply it.
Thanks !
Konstantin
Some more references (it was very difficult for me to find info about the PropertyNotFoundException on the web for me):
- The most fitting stuff I found was a forum post where they say method expressions worked with AS 5 but do not with AS 7: https://community.jboss.org/thread/173375
- I tried to update Mojarra (don't remember why exactly), but it didn't change anything: https://community.jboss.org/message/720446?tstart=0
-
blah-StackTrace.txt.zip 3.1 KB
-
blahsMainPage.xhtml.zip 959 bytes
-
BlahQueries.java.zip 586 bytes
-
BlahHome.java.zip 1.1 KB
-
Blah.java.zip 1.1 KB