Reputation: 73
Primefaces 6.1 ajaxExceptionHandler is not working as expected in liferay 7 portlet. Based on the Primefaces user guide, I tried to implement simple exception handling. When the commandButton is pressed, the backing bean throws a NullPointerException, which should be displayed in a dialog window. The problem is, when the dialog pops up, the exception information is not shown. It seems that the returned ajax response itself contains the exception info (as shown below), but the dialog component is not updated accordingly.
test.xhtml (snippet)
<h:body>
<h:form>
<h3 style="margin-top:0">AJAX 1410</h3>
<p:commandButton actionListener="#{policyAdminBean.throwNpe}"
ajax="true"
value="Throw NullPointerException!" />
<p:ajaxExceptionHandler type="javax.faces.application.ViewExpiredException"
update=":exceptionDialog"
onexception="PF('exceptionDialogVar').show();" />
<p:ajaxExceptionHandler type="java.lang.NullPointerException"
update=":exceptionDialog"
onexception="PF('exceptionDialogVar').show();" />
</h:form>
<p:dialog id="exceptionDialog" header="Exception '#{pfExceptionHandler.type}' occured!" widgetVar="exceptionDialogVar"
height="500px">
Message: #{pfExceptionHandler.message} <br/>
StackTrace: <h:outputText value="#{pfExceptionHandler.formattedStackTrace}" escape="false" /> <br />
<p:button onclick="document.location.href = document.location.href;"
value="Reload!"
rendered="#{pfExceptionHandler.type == 'javax.faces.application.ViewExpiredException'}" />
</p:dialog>
</h:body>
TestBean.java
@Named
@ViewScoped
public class TestBean implements Serializable {
private static final long serialVersionUID = -4856350663999482370L;
public void throwNpe(){
throw new NullPointerException("test exception");
}
}
faces-config.xml (snippet)
<application>
<message-bundle>Language</message-bundle>
<locale-config>
<default-locale>hu</default-locale>
</locale-config>
<el-resolver>
org.primefaces.application.exceptionhandler.PrimeExceptionHandlerELResolver
</el-resolver>
</application>
<lifecycle>
<phase-listener>com.liferay.faces.util.lifecycle.DebugPhaseListener</phase-listener>
</lifecycle>
<factory>
<exception-handler-factory>
org.primefaces.application.exceptionhandler.PrimeExceptionHandlerFactory
</exception-handler-factory>
</factory>
ajax response (snippet)
<partial-response id="_policyadmin_WAR_wfsadminportlets_">
<update id="_policyadmin_WAR_wfsadminportlets_:exceptionDialog"><![CDATA[
<div id="_policyadmin_WAR_wfsadminportlets_:exceptionDialog"
class="ui-dialog ui-widget ui-widget-content ui-corner-all ui-shadow ui-hidden-container">
<div class="ui-dialog-titlebar ui-widget-header ui-helper-clearfix ui-corner-top"><span
id="_policyadmin_WAR_wfsadminportlets_:exceptionDialog_title" class="ui-dialog-title">Exception 'java.lang.NullPointerException' occured!</span><a
href="#" class="ui-dialog-titlebar-icon ui-dialog-titlebar-close ui-corner-all"
aria-label="Close"><span class="ui-icon ui-icon-closethick"></span></a></div>
<div class="ui-dialog-content ui-widget-content">
Message: test exception <br/>
StackTrace: java.lang.NullPointerException: test exception<br/> at
[removed for brevity...]
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)<br/> at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)<br/> at
java.lang.Thread.run(Thread.java:745)<br/> <br/></div>
</div>
<script id="_policyadmin_WAR_wfsadminportlets_:exceptionDialog_s" type="text/javascript">$(function () {
PrimeFaces.cw("Dialog", "exceptionDialogVar", {
id: "_policyadmin_WAR_wfsadminportlets_:exceptionDialog",
height: "500px"
});
});</script>
]]>
</update>
<eval><![CDATA[var
hf=function(type,message,timestampp){PF('exceptionDialogVar').show();};hf.call(this,"java.lang.NullPointerException","test
exception","2017-04-25 14:54:55");]]>
</eval>
</partial-response>
Upvotes: 2
Views: 786
Reputation: 421
Good question!
This pattern of use for the PrimeFaces AJAX exception handler was working in PrimeFaces before version 6.0. So if you revert to say, PrimeFaces 5.3, you will see it working on Liferay 7. The commit that broke PrimeFaces was e22e40a, which was a complex commit, unknowingly affecting portlets by changing the way the PrimeFaces partial responses are constructed.
A pull request has been sent to the PrimeFaces integrators to fix this. https://github.com/primefaces/primefaces/pull/2333
Once this pull request is merged, you can build PrimeFaces from the latest source, and you will see that this is fixed.
DETAILS: Specifically, commit e22e40a changed the PrimePartialResponseWriter.startDocument() method, eliminating its call to encodeCallbackParams() which, in turn, was calling the startChangesIfNecessary() method in mojarra. Since these calls were eliminated, no "changes" element was introduced into the partial response. With no changes, no update occurs in the dialog's DOM. Here is a working stack showing the calls down into startChangesIfNecessary before the e22e40a commit.
Upvotes: 1