java.lang.IllegalStateException:CDATA标记可能无法嵌套

时间:2012-08-10 12:41:20

标签: ajax jsf primefaces cdata illegalstateexception

我在JSF页面中遇到了ajax请求的问题。当我点击按钮时,我得到了这个例外:

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实体属性进行硬编码时,一切正常。但是,当从数据库(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>

6 个答案:

答案 0 :(得分:48)

在呈现代码中的错误导致的JSF响应时抛出异常。但是,Mojarra无法使用内置的ajax异常处理程序正确处理此异常,导致您现在看到的另一个异常,隐藏了有关原始异常的所有详细信息。

仔细观察堆栈跟踪。从底部开始跟踪调用堆栈:

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响应期间发生了异常,这很可能是因为您在getter方法中执行业务逻辑,该方法仅在生成HTML输出期间调用。所以这个过程最有可能如下:

  1. JSF进入RENDER_RESPONSE阶段。
  2. JSF需要生成HTML输出。
  3. 对于每个<f:ajax render="some">(或<p:ajax update="some">),它需要在CDATA block内创建一个<update id="some"> XML块并生成HTML输出(以便在语法上保持XML输出)有效)。因此需要启动CDATA块。
  4. 在将CD输出生成CDATA块时,将评估所有渲染时EL表达式,包括所有UI组件的value属性。
  5. 在某处,EL表达式后面的getter引发了一个由你自己的代码中的错误引起的异常。
  6. JSF迅速停止生成HTML输出,但没有关闭CDATA块。 HTTP响应包含半烘焙数据。
  7. AjaxExceptionHandlerImpl已被触发。
  8. AjaxExceptionHandlerImpl需要将异常/错误详细信息写入响应。但是,它没有检查响应是否已经写入。它盲目地试图打开一个CDATA块,因为它已经打开而失败了。它抛出了你所看到的异常,隐藏了它试图处理的真实底层异常的所有细节。
  9. 正如您所看到的,问题是双重的:

    1. JSF渲染器不应该留下半熟的响应。
    2. Mojarra AjaxExceptionHandlerImpl应检查/验证回复状态。
    3. 如果用custom one which immediately prints the stack traceOmniFaces 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引起的。

答案 1 :(得分:0)

我遇到了与你相同的问题,当我使用来自支持bean的自动完成组件绑定时,它运行正常。

<p:autoComplete id="autocomplete" binding="#{searchBean.compui}" title="Find" value="#{searchBean.searchfor}" forceSelection="false" queryDelay="30" dropdown="true" maxResults="20" emptyMessage="None" completeMethod="#{searchBean.complete}" style="width: 90%;"/>
<p:commandButton id="cmdsearch" value="#{msg.search}" action="#{searchBean.search}" update="tblprocresults" icon="ui-icon-zoomin"/>

并在支持bean

private AutoComplete compui;
//compui is initialized when bean is constructed
    public AutoComplete getCompui() {
            return compui;
        }

        public void setCompui(AutoComplete compui) {
            this.compui = compui;
        }

答案 2 :(得分:-2)

CDATA问题不是PrimeFaces问题,而是与负责提供部分输出的JSF实现有关。           替换为它的JSF属性;)

答案 3 :(得分:-2)

如果您还在服务器日志中看到java.lang.ClassCastException: com.sun.faces.facelets.compiler.UIInstructions cannot be cast to org.primefaces.component.tree.UITreeNode,请添加

<context-param>
  <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
  <param-value>true</param-value>
</context-param>

/WEB-INF/web.xml

答案 4 :(得分:-2)

只是要考虑一些事情,有时它可能是一个真正的骨头错误。

例如,如果我忘记在xhtml页面使用的某个bean中初始化一个ArrayList,有时我会得到同样的错误信息:

我会这样做:

List<String> myList;

但忘记这样做:

myList = new ArrayList();

因此,另外要考虑的是,确保您已经处理了所有内务管理(确保变量已初始化/填充等等)

答案 5 :(得分:-4)

我在Tomcat 7中摆脱simliar execption的经验是:如果你在jsf中调用一个方法,你将不得不添加(),即使它没有参数。

此异常但如果您使用的是jetty

则不会出现

编辑:即使这个例外被删除,它还​​有另一个例外:

java.lang.NoSuchMethodError: javax.el.ELResolver.invoke(Ljavax/el/ELContext;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Class;[Ljava/lang/Object;)Ljava/lang/Object;

经过研究我发现Tomcat 7本身带来了EL依赖,因此pom.xml中的任何其他依赖都像

<dependency>
    <groupId>javax.el</groupId>
    <artifactId>el-api</artifactId>
    <version>2.2</version>
    <scope>provided</scope>
</dependency>

应该移除以避免混合。

之后,您必须在Eclipse中以Run as - tomcat7:run启动tomcat7,而不是默认启动tomcat 6的tomcat:run

我的环境:

  • Eclipse Kepler
  • JDK 1.7.0_45
  • Maven 3.1.1