validationjsffaceletsjsf-2.2uiinclude

Handling TagAttributeException and change ui:includeSrc


We have dynamic menu items in a page and the links for include-source .xhtml stored in the DB, in this scenario if source xhtml is wrongly input or failed to find the application context it throws TagAttributeException with Invalid Path message.

After this event, if we make any ajax request it failed, reason is in the restore-view phase tried to restore with invalid xhtml (include src).

Is there any way to handle this exception at the runtime and change the xhtml src to some default xhtml. So that any further AJAX call will work.

XHTML

 <h:form prependId="false">            

          <p:commandButton actionListener="#{exceptionPF.includePage()}"
                 ajax="true"
                 value="Include Wrong Source" />

           <p:commandButton actionListener="#{exceptionPF.includeRightPage()}"
                 ajax="true"
                 value="Include Right Source" />

          <p:panel id="div1" >

              <ui:include src="#{exceptionPF.srcPage}" />

          </p:panel>          


         <p:ajaxExceptionHandler type="javax.faces.view.facelets.TagAttributeException"
                        update="exceptionDialog"
                        onexception="PF('exceptionDialog').show();" />



       <p:dialog id="exceptionDialog" header="Exception '#{pfExceptionHandler.type}' occured!" widgetVar="exceptionDialog"
          height="500px">
    Message: #{pfExceptionHandler.message} <br/>
    Stack-Trace: <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:form>

Bean

@Named
@ViewScoped
public class ExceptionPF implements Serializable {

String srcPage;

public String getSrcPage() {
    return srcPage;
}

public void setSrcPage(String srcPage) {
    this.srcPage = srcPage;
}

public void includePage()
{ 
    setSrcPage("wrong.xhtml");
    RequestContext.getCurrentInstance().update("div1");
}

 public void includeRightPage()
{
    setSrcPage("correct.xhtml");
    RequestContext.getCurrentInstance().update("div1");
}

}

Error

19:38:08,978 INFO  [stdout] (default task-14) *****BEFORE **** RESTORE_VIEW 
   19:38:08,985 INFO  [stdout] (default task-14) *****AFTER **** RESTORE_VIEW
   19:38:08,986 SEVERE [javax.enterprise.resource.webcontainer.jsf.context]     
   (default task-14) javax.faces.view.facelets.TagAttributeException:   
   /index.xhtml @33,62
   <ui:include src="#{exceptionPF.srcPage}"> Invalid path : wrong.xhtml
        at com.sun.faces.facelets.tag.ui.IncludeHandler.apply(IncludeHandler.jav

Solution

  • There's no way of handling an exception from the view side on when it's the view itself who is causing the exception.

    You can use ViewDeclarationLanguage#viewExists() to check if a given view exists. You should do this before setting the srcPage and if necessary get hold of the wrong value in a separate (boolean) variable.

    Here's how you can use it in flavor of an utility method:

    public static boolean viewExists(String viewId) {
        FacesContext context = FacesContext.getCurrentInstance();
        return context.getApplication().getViewHandler()
            .getViewDeclarationLanguage(context, viewId).viewExists(context, viewId);
    }