web-dev-qa-db-fra.com

java.lang.IllegalStateException: les balises CDATA ne peuvent pas imbriquer

J'ai un problème avec une demande ajax dans une page JSF. Lorsque je clique sur le bouton, j'obtiens cette 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)

Je pense que c'est un problème avec les objets String, car quand je code les propriétés d'entité JPA qui sont affichées sur le site, tout est OK. Cependant, lorsque l'entité est extraite de la base de données (PostgreSQL), elle lève l'exception susmentionnée.

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

Une exception est générée lors du rendu de la réponse JSF provoquée par un bogue dans votre code. Cependant, Mojarra à son tour n'a pas réussi à gérer cette exception avec le gestionnaire d'exceptions ajax intégré, provoquant une autre exception que vous voyez maintenant, masquant tous les détails de l'exception d'origine.

Regardez de plus près la trace de la pile. Commencez par le bas pour suivre la pile d'appels:

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

Ainsi, cela s’est passé pendant la phase de réponse au rendu. Ok, regardez la ligne suivante (celle au-dessus):

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

Salut, il a été passé par le gestionnaire d'exceptions ajax intégré à Mojarra AjaxExceptionHandlerImpl! Only est invoqué lorsqu'une exception s'est produite lors d'une demande ajax. D'accord, lisez les lignes suivantes plus en avant de bas en haut:

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)

Il tente donc d'écrire les informations d'erreur dans la réponse ajax. Cette information doit aller dans un bloc CDATA. Cependant, le démarrage d'un bloc CDATA a échoué comme suit, car il semble qu'un bloc CDATA soit déjà ouvert:

Java.lang.IllegalStateException: CDATA tags may not nest

Cela indique à son tour que l'exception s'est produite lors de l'écriture de la réponse ajax, probablement parce que vous exécutez une logique métier dans une méthode de lecture qui n'est appelée que lors de la génération de la sortie HTML. Le processus était donc probablement le suivant:

  1. JSF entre dans la phase RENDER_RESPONSE.
  2. JSF doit générer une sortie HTML.
  3. Pour chaque <f:ajax render="some"> (ou <p:ajax update="some">), il doit créer un bloc XML <update id="some"> avec la sortie HTML générée dans un bloc CDATA (pour que la sortie XML soit syntaxiquement valide). Donc, un bloc CDATA doit être démarré.
  4. Lors de la génération de la sortie HTML dans un bloc CDATA, toutes les expressions EL au moment du rendu sont évaluées, y compris l'attribut value de tous les composants de l'interface utilisateur.
  5. Quelque part, le getter derrière l'expression EL a émis une exception provoquée par un bogue dans votre propre code.
  6. JSF a rapidement arrêté de générer une sortie HTML et n'a pas fermé le bloc CDATA. La réponse HTTP contient des données à moitié cuites.
  7. AjaxExceptionHandlerImpl est déclenché.
  8. AjaxExceptionHandlerImpl doit écrire le détail de l'exception/de l'erreur dans la réponse. Cependant, il n'a pas vérifié si la réponse est déjà écrite. Il tente aveuglément d'ouvrir un bloc CDATA qui a échoué car il est déjà ouvert. Il a jeté l'exception que vous voyez en cachant tous les détails de la véritable exception sous-jacente qu'il a essayé de gérer.

Comme vous pouvez le constater, le problème est double:

  1. Le rendu JSF ne devrait pas avoir laissé la réponse à moitié cuite.
  2. La variable AjaxExceptionHandlerImpl de Mojarra aurait dû vérifier/vérifier l'état de la réponse.

Si vous remplacez le gestionnaire d'exceptions ajax intégré de Mojarra par un custom qui imprime immédiatement la trace de pile , ou par OmniFaces FullAjaxExceptionHandler qui est capable de détecter et de nettoyer les réponses ajax saccadées , il sera finalement révélé et affiché réel sous-jacent causé par un bug dans votre code. Comme indiqué précédemment, il est fort probable que exécute une logique métier dans une méthode getter, ce qui est une mauvaise pratique .

46
BalusC

J'ai eu le même problème que le vôtre. Lorsque j'ai utilisé la liaison avec le composant autocomplete du bean de support, cela a bien fonctionné.

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

et dans le haricot

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