java.lang.IllegalStateException: CDATA tags may not nest
Asked Answered
G

6

23

I've got a problem with an ajax request in a JSF page. When I click on the button, I get this exception:

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)

I think it's some problem with String objects, because when I hardcode the JPA entity properties which are shown on the site, then everything is OK. However when the entity is retrieved from the database (PostgreSQL), it throws the aforementioned exception.

JSF code:

<p:column>
    <f:facet name="header">
        Action
    </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>
Gros answered 10/8, 2012 at 12:41 Comment(1)
I guess your problem is somewhere else in your JSf code, not in fragment you've posted.Decury
L
51

There's an exception being thrown during rendering the JSF response caused by a bug in your code. However, Mojarra in turn failed to properly handle this exception with the builtin ajax exception handler, causing another exception which you're now seeing, hiding away all detail about the original exception.

Look closer at the stack trace. Start at the bottom to track the call stack:

at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)

Thus, it happened during render response phase. Okay, look at the next line (the one above it):

at com.sun.faces.context.AjaxExceptionHandlerImpl.handle(AjaxExceptionHandlerImpl.java:123)

Hey, it's been passed through Mojarra's builtin ajax exception handler AjaxExceptionHandlerImpl! This is only invoked when an exception has occurred during an ajax request. Okay, read the next lines further from bottom to top:

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)

It's thus attempting to write the error information to the ajax response. This information has to go in a CDATA block. However, starting a CDATA block failed as follows because there's apparently already a CDATA block open:

java.lang.IllegalStateException: CDATA tags may not nest

This in turn indicates that the exception occurred during writing the ajax response, most likely because you're performing business logic in a getter method which is only invoked during generating the HTML output. So the process was most likely as follows:

  1. JSF enters RENDER_RESPONSE phase.
  2. JSF needs to generate HTML output.
  3. For every <f:ajax render="some"> (or <p:ajax update="some">), it needs to create a <update id="some"> XML block with the generated HTML output inside a CDATA block (to keep the XML output syntactically valid). So a CDATA block needs to be started.
  4. While generating the HTML output into a CDATA block, all render-time EL expressions are evaluated, including value attribute of all UI components.
  5. Somewhere, the getter behind the EL expression threw an exception caused by a bug in your own code.
  6. JSF promptly stopped generating HTML output and didn't close the CDATA block. The HTTP response contains halfbaked data.
  7. AjaxExceptionHandlerImpl is triggered.
  8. AjaxExceptionHandlerImpl needs to write the exception/error detail to the response. However, it didn't check if the response is already written. It blindly attempts to open a CDATA block which in turn failed because it's already opened. It threw the exception you're seeing, hiding away all detail about the real underlying exception it tried to handle.

As you can see, the problem is two-fold:

  1. JSF renderer should not have left the response halfbaked.
  2. Mojarra's AjaxExceptionHandlerImpl should have checked/verified the state of the response.

If you replace Mojarra's builtin ajax exception handler by a custom one which immediately prints the stack trace, or by OmniFaces FullAjaxExceptionHandler which is capable of detecting and cleaning halfbaked ajax responses, then it will finally reveal and show the real underlying caused by a bug in your code. As said before, it's most likely caused by performing business logic in a getter method, which is a bad practice.

Lynettelynn answered 30/7, 2013 at 12:1 Comment(3)
-1 So, what is the solution? What should we do to prevent this exception be occured? I got this exception and don't see how your answer might be helpful unless you discrebed JSF internal which are totally unuseful to me and I think to the majority of the developers which are just trying to fix a bug. You were very unclear...Phantom
@St.Antario: I added a tldr to top of answer for the impatient.Lynettelynn
Ok, the issue is that the code worked fine when we were using JSF 1.2. After updating to JSF 2.1 it started throw this exception. Is it striclty JSF 2.x problem?Phantom
R
0

I had the same problem as yours, When I used binding with autocomplete component from the backing bean it worked fine.

<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"/>

and in the backing bean

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

        public void setCompui(AutoComplete compui) {
            this.compui = compui;
        }
Reverso answered 23/8, 2016 at 5:17 Comment(1)
initialization of compui (Autocomplete binding component) is not necessaryReverso
G
-2

CDATA issue is not a PrimeFaces question but related to JSF implementation who is responsible of providing the partial output. replace by it's JSF property ;)

Godthaab answered 25/4, 2014 at 11:2 Comment(0)
C
-2

If you also see java.lang.ClassCastException: com.sun.faces.facelets.compiler.UIInstructions cannot be cast to org.primefaces.component.tree.UITreeNode in the server log, add

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

to /WEB-INF/web.xml

Chenopod answered 1/6, 2014 at 12:5 Comment(0)
E
-2

Just to throw in something to consider as well, sometimes it can be a really bone-headed error.

For example, sometimes I would get this same error message if I forgot to initialize an ArrayList in one of my beans that the xhtml page is using:

I would do this:

List<String> myList;

But forget to do this:

myList = new ArrayList();

So just as another thing to think about, make sure you've taken care of all of your housekeeping (making sure variables are initialized/populated, etc...)

Elaterite answered 2/7, 2014 at 17:24 Comment(0)
K
-4

My experience to get rid of a simliar execption in Tomcat 7 is: if you are calling a method in jsf, you will have to add (), even if it does not have a parameter.

This exception but will not appear, if you are using jetty

EDIT: Even though this exception was eliminated, it gave another exception:

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;

After researching I found the Tomcat 7 brings EL dependency by itself, thus any other dependency in the pom.xml like

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

shoud be removed to avoid the mixing.

After that, you have to start the tomcat7 by Run as - tomcat7:run in Eclipse, instead of tomcat:run which starts by default the tomcat 6.

My enviroment:

  • Eclipse Kepler
  • JDK 1.7.0_45
  • Maven 3.1.1
Kneehigh answered 22/10, 2014 at 13:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.