SEVERE: Servlet.service() for servlet Faces Servlet threw exception java.lang.IllegalStateException: CDATA tags may not nest at com.sun.faces.renderkit.html_basic.HtmlResponseWriter.startCDATA(HtmlResponseWriter.java:630) at javax.faces.context.ResponseWriterWrapper.startCDATA(ResponseWriterWrapper.java:172) at javax.faces.context.PartialResponseWriter.startError(PartialResponseWriter.java:342) at org.primefaces.context.PrimePartialResponseWriter.startError(PrimePartialResponseWriter.java:210) at com.sun.faces.context.AjaxExceptionHandlerImpl.handlePartialResponseError(AjaxExceptionHandlerImpl.java:200) at com.sun.faces.context.AjaxExceptionHandlerImpl.handle(AjaxExceptionHandlerImpl.java:123) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:119) at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
我认为这是String对象的一些问题,因为当我硬编码站点上显示的JPA实体属性时,一切都OK。然而,当从数据库(Postgresql)中检索实体时,它会引发上述异常。
JSF代码:
<p:column> <f:facet name="header"> Akcja </f:facet> <h:commandButton actionListener="#{mBDocumentMigration.actionEdit(object)}" value="Edytuj" rendered="#{mBDocumentMigration.editingObject == null}" > <f:ajax render="@form" execute="@form" /> </h:commandButton> <h:commandButton action="#{mBDocumentMigration.actionZapisz}" value="Zapisz" rendered="#{mBDocumentMigration.editingObject != null}" > <f:ajax render="@form" execute="@this" /> </h:commandButton> </p:column>
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
因此,它在渲染响应阶段发生。好的,看下一行(上面一行):
at com.sun.faces.context.AjaxExceptionHandlerImpl.handle(AjaxExceptionHandlerImpl.java:123)
嘿,它已经通过Mojarra的内置的ajax异常处理程序AjaxExceptionHandlerImpl!仅在ajax请求期间发生异常时才调用此方法。好的,从下到上阅读下一行:
at com.sun.faces.renderkit.html_basic.HtmlResponseWriter.startCDATA(HtmlResponseWriter.java:630) at javax.faces.context.ResponseWriterWrapper.startCDATA(ResponseWriterWrapper.java:172) at javax.faces.context.PartialResponseWriter.startError(PartialResponseWriter.java:342) at org.primefaces.context.PrimePartialResponseWriter.startError(PrimePartialResponseWriter.java:210) at com.sun.faces.context.AjaxExceptionHandlerImpl.handlePartialResponseError(AjaxExceptionHandlerImpl.java:200)
因此,尝试将错误信息写入ajax响应。此信息必须在CDATA块中。然而,启动CDATA块失败如下,因为显然已经有一个CDATA块打开了:
java.lang.IllegalStateException: CDATA tags may not nest
这又表示在编写ajax响应时发生异常,很可能是因为您在生成HTML输出时仅调用getter方法执行业务逻辑。所以这个过程最有可能如下:
> JSF进入RENDER_RESPONSE阶段。
> JSF需要生成HTML输出。
>对于每个< f:ajax render =“some”> (或< p:ajax update =“some”>)),则需要创建< update id =“some”>在CDATA block之间生成的HTML输出的XML块(以保持XML输出在语法上有效)。所以需要启动一个CDATA块。
>将HTML输出生成到CDATA块中时,会对所有渲染时EL表达式进行求值,包括所有UI组件的value属性。
>在某个地方,EL表达式后面的getter会抛出一个由你自己的代码中的错误引起的异常。
> JSF会立即停止生成HTML输出,并没有关闭CDATA块。 HTTP响应包含半记录数据。
> AjaxExceptionHandlerImpl被触发。
> AjaxExceptionHandlerImpl需要将异常/错误详细信息写入响应。但是,它没有检查响应是否已经被写入。它盲目地尝试打开一个CDATA块,由此它已经被打开了。它抛出了你看到的异常,隐藏了所有关于它试图处理的真正的底层异常的细节。
你可以看到,问题是双重的:
> JSF渲染器不应该让响应halfbaked。
> Mojarra的AjaxExceptionHandlerImpl应该已经检查/验证了响应的状态。
如果您用custom one which immediately prints the stack trace或OmniFaces FullAjaxExceptionHandler
which is capable of detecting and cleaning halfbaked ajax responses替换Mojarra的内置ajax异常处理程序,那么最终会显示和显示代码中的错误引起的真正原因。如前所述,这很可能是performing business logic in a getter method,which is a bad practice造成的。