webentwicklung-frage-antwort-db.com.de

java.lang.IllegalStateException: CDATA-Tags dürfen nicht verschachtelt sein

Ich habe ein Problem mit einer Ajax-Anforderung in einer JSF-Seite. Wenn ich auf die Schaltfläche klicke, erhalte ich folgende Ausnahme:

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)

Ich denke, es ist ein Problem mit String-Objekten, denn wenn ich die Eigenschaften der JPA-Entität, die auf der Site angezeigt werden, hartcodiert, ist alles in Ordnung. Wenn jedoch die Entität aus der Datenbank abgerufen wird (PostgreSQL), wird die oben erwähnte Ausnahme ausgelöst.

JSF-Code:

<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>
18
alinoe

Beim Rendern der JSF-Antwort, die durch einen Fehler in Ihrem Code verursacht wurde, wird eine Ausnahme ausgelöst. Allerdings hat Mojarra diese Ausnahme mit dem integrierten ajax-Ausnahmehandler nicht richtig verarbeitet, was zu einer anderen Ausnahme führt, die Sie jetzt sehen, und verbirgt alle Details über die ursprüngliche Ausnahme.

Schauen Sie sich die Stapelverfolgung genauer an. Beginnen Sie unten, um den Aufrufstapel zu verfolgen:

at com.Sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.Java:139)

So passierte es während der Renderantwortphase. Okay, schauen Sie sich die nächste Zeile (die darüber) an:

at com.Sun.faces.context.AjaxExceptionHandlerImpl.handle(AjaxExceptionHandlerImpl.Java:123)

Hey, es wurde durch Mojarras eingebauten Ajax-Exception-Handler AjaxExceptionHandlerImpl übergeben! Dies ist only, wenn eine Ausnahme während einer Ajax-Anforderung aufgetreten ist. Okay, lesen Sie die nächsten Zeilen weiter von unten nach oben:

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)

Es wird also versucht, die Fehlerinformationen in die Ajax-Antwort zu schreiben. Diese Informationen müssen in einem CDATA-Block enthalten sein. Das Starten eines CDATA-Blocks ist jedoch folgendermaßen fehlgeschlagen, da offenbar bereits ein CDATA-Block geöffnet ist:

Java.lang.IllegalStateException: CDATA tags may not nest

Dies zeigt wiederum an, dass die Ausnahme beim Schreiben der Ajax-Antwort aufgetreten ist. Dies ist höchstwahrscheinlich darauf zurückzuführen, dass Sie Geschäftslogik in einer Getter-Methode ausführen, die nur beim Generieren der HTML-Ausgabe aufgerufen wird. Der Prozess war also am wahrscheinlichsten wie folgt:

  1. JSF wechselt in die RENDER_RESPONSE-Phase.
  2. JSF muss eine HTML-Ausgabe generieren.
  3. Für jeden <f:ajax render="some"> (oder <p:ajax update="some">) muss ein <update id="some">-XML-Block mit der generierten HTML-Ausgabe in einem CDATA-Block erstellt werden (um die XML-Ausgabe syntaktisch gültig zu halten). Es muss also ein CDATA-Block gestartet werden.
  4. Beim Generieren der HTML-Ausgabe in einen CDATA-Block werden alle EL-Ausdrücke zur Renderzeit ausgewertet, einschließlich des Attributs value aller Komponenten der Benutzeroberfläche.
  5. Irgendwo hat der Getter hinter dem EL-Ausdruck eine Ausnahme ausgelöst, die durch einen Fehler in Ihrem eigenen Code verursacht wurde.
  6. JSF hat die Generierung der HTML-Ausgabe umgehend beendet und den CDATA-Block nicht geschlossen. Die HTTP-Antwort enthält halbgebackene Daten.
  7. AjaxExceptionHandlerImpl wird ausgelöst.
  8. AjaxExceptionHandlerImpl muss die Ausnahme-/Fehlerdetails in die Antwort schreiben. Es wurde jedoch nicht geprüft, ob die Antwort bereits geschrieben wurde. Es versucht blindlings, einen CDATA-Block zu öffnen, der wiederum fehlgeschlagen ist, weil er bereits geöffnet ist. Es warf die Ausnahme, die Sie sehen, und versteckte alle Details über die tatsächliche zugrunde liegende Ausnahme, mit der sie umgehen wollte.

Wie Sie sehen, ist das Problem zweifach:

  1. Der JSF-Renderer sollte die Antwort nicht halb gebacken haben.
  2. Mojarras AjaxExceptionHandlerImpl sollte den Status der Antwort überprüft/überprüft haben.

Wenn Sie Mojarras eingebauten ajax-Ausnahmebehandler durch einen benutzerdefinierten, der sofort die Stapelverfolgung druckt oder durch OmniFaces FullAjaxExceptionHandler, der in der Lage ist, halbgebackene Ajax-Antworten zu erkennen und zu reinigen ersetzt, dann wird dies endgültig geschehen enthüllen und zeigen Sie den tatsächlichen Basiswert, der durch einen Fehler in Ihrem Code verursacht wurde. Wie bereits erwähnt, wird dies höchstwahrscheinlich durch Ausführen von Geschäftslogik in einer Getter-Methode, was eine schlechte Praxis ist verursacht.

46
BalusC

Ich hatte das gleiche Problem wie du. Als ich die Bindung mit der Autocomplete-Komponente aus der Backing Bean verwendet habe, hat es gut funktioniert.

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

und in der Stützbohne

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

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