20

我在 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>
4

6 回答 6

50

在呈现由代码中的错误引起的 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 块<update id="some">内创建一个带有生成的 HTML 输出的 XML 块(以保持 XML 输出在语法上有效)。所以需要启动一个 CDATA 块。
  4. 在将 HTML 输出生成到 CDATA 块中时,会评估所有呈现时 EL 表达式,包括value所有 UI 组件的属性。
  5. 在某个地方,EL 表达式背后的 getter 引发了由您自己的代码中的错误引起的异常。
  6. JSF 立即停止生成 HTML 输出并且没有关闭 CDATA 块。HTTP 响应包含半生不熟的数据。
  7. AjaxExceptionHandlerImpl被触发。
  8. AjaxExceptionHandlerImpl需要将异常/错误详细信息写入响应。但是,它没有检查响应是否已经写入。它盲目地尝试打开一个 CDATA 块,该块又失败了,因为它已经打开了。它抛出了你看到的异常,隐藏了它试图处理的真正底层异常的所有细节。

如您所见,问题有两个方面:

  1. JSF 渲染器不应该让响应半途而废。
  2. MojarraAjaxExceptionHandlerImpl应该已经检查/验证了响应的状态。

如果您将 Mojarra 的内置 ajax 异常处理程序替换为立即打印堆栈跟踪的自定义处理程序,或者由能够检测和清理半生不熟的 ajax 响应的 OmniFaces 替换FullAjaxExceptionHandler那么它将最终揭示并显示由代码中的错误引起的真正底层. 如前所述,这很可能是由于在 getter 方法中执行业务逻辑造成的,这是一种不好的做法

于 2013-07-30T12:01:32.103 回答
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"/>

并在后备豆中

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

        public void setCompui(AutoComplete compui) {
            this.compui = compui;
        }
于 2016-08-23T05:17:01.187 回答
-2

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

于 2014-04-25T11:02:32.313 回答
-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

于 2014-06-01T12:05:02.880 回答
-2

只是为了考虑一些事情,有时它可能是一个非常愚蠢的错误。

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

我会这样做:

List<String> myList;

但是忘记这样做:

myList = new ArrayList();

所以就像另一件要考虑的事情一样,确保你已经处理好所有的家务(确保变量被初始化/填充,等等......)

于 2014-07-02T17:24:04.167 回答
-4

我在 Tomcat 7 中摆脱类似 execption 的经验是:如果您在 jsf 中调用方法,则必须添加 (),即使它没有参数。

此异常但不会出现,如果您使用的是码头

编辑:即使消除了这个异常,它也给出了另一个异常:

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>

应移除以避免混合。

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

我的环境:

  • 日食开普勒
  • JDK 1.7.0_45
  • Maven 3.1.1
于 2014-10-22T13:35:47.220 回答