3 Replies Latest reply on Jul 31, 2007 8:12 AM by Yannick Lazzari

    Weird NullPointerException in org.ajax4jsf.org.w3c.tidy.Node

    Yannick Lazzari Newbie

      Hi,

      I have a weird NullPointerException that occurs inside a a4j:repeat. Here's my template snippet:

      <table border="1">
       <thead>
       <tr>
       <th>col1</th>
       </tr>
       </thead>
       <tbody>
       <a4j:repeat value="#{someList}" var="item">
       <h:panelGroup id="theRow">
       <tr>
       <td><h:outputText value="#{item.someValue1}"/></td>
       </tr>
       <tr>
       <td><h:outputText value="#{item.someValue2}"/></td>
       </tr>
       </h:panelGroup>
       </a4j:repeat>
       </tbody>
      </table>
      


      I have a simple a4j:repeat that I use to build an HTML table. I get the following exception when I try to render this template:

      java.lang.NullPointerException
       at org.ajax4jsf.org.w3c.tidy.Node.trimInitialSpace(Node.java:967)
       at org.ajax4jsf.org.w3c.tidy.Node.trimSpaces(Node.java:1033)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseInline.parse(ParserImpl.java:1146)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:224)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseRowGroup.parse(ParserImpl.java:2830)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:224)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseTableTag.parse(ParserImpl.java:2650)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:224)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseBlock.parse(ParserImpl.java:2488)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:224)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseBlock.parse(ParserImpl.java:2488)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:224)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseBody.parse(ParserImpl.java:999)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseTag(ParserImpl.java:224)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl$ParseHTML.parse(ParserImpl.java:507)
       at org.ajax4jsf.org.w3c.tidy.ParserImpl.parseDocument(ParserImpl.java:3430)
       at org.ajax4jsf.org.w3c.tidy.Tidy.parse(Tidy.java:384)
       at org.ajax4jsf.org.w3c.tidy.Tidy.parse(Tidy.java:282)
       at org.ajax4jsf.org.w3c.tidy.Tidy.parseDOM(Tidy.java:625)
       at org.ajax4jsf.framework.ajax.xmlfilter.tidy.TidyParser.parseHtmlByTidy(TidyParser.java:98)
       at org.ajax4jsf.framework.ajax.xmlfilter.tidy.TidyParser.parseHtml(TidyParser.java:203)
       at org.ajax4jsf.framework.ajax.xmlfilter.FilterServletResponseWrapper.parseContent(FilterServletResponseWrapper.java:613)
       at org.ajax4jsf.framework.ajax.xmlfilter.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:284)
       at org.ajax4jsf.framework.ajax.xmlfilter.BaseFilter.doFilter(BaseFilter.java:276)
       at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:40)
       at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
       at org.jboss.seam.debug.hot.HotDeployFilter.doFilter(HotDeployFilter.java:63)
       at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69)
       at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:140)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:217)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:185)
       at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275)
       at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:258)
       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:189)
       at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:611)
       at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:564)
       at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:81)
       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:193)
       at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:611)
       at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:564)
       at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:558)
       at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1067)
       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:137)
       at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:611)
       at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:564)
       at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:558)
       at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1067)
       at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:255)
       at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:618)
       at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:549)
       at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:790)
       at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask(DefaultReadTask.java:326)
       at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:248)
       at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:199)
       at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:252)
       at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:93)
      


      If I simply remove the "id" attribute on the h:panelGroup embedded inside the a4j:repeat, it works. The thing is, I need the "id" attribute because I want to partially re-render certain rows of my table so I will have commands whose "reRender" attribute will be equal to that "id". I'm using the latest snapshot of Ajax4jsf (1.1.12-20070730) but I have the same behaviour with older snapshots as well.

      Thanks for your help.


        • 1. Re: Weird NullPointerException in org.ajax4jsf.org.w3c.tidy.
          Igor Shabalov Apprentice

          NullPointer is bad, however, you cannot put panelGroup between *tbody* and *tr*. And you cannot re-render some subset of the rows. These are limitations of dhtml.
          All you can do is - ether re-render entire table, or re-render content of one or many particular cells. That's all you can do here. No need for panelGroup.

          • 3. Re: Weird NullPointerException in org.ajax4jsf.org.w3c.tidy.
            Yannick Lazzari Newbie

            Thanks for your help. I didn't know about this limitation. But by the way, putting a h:panelGroup between a "tbody" and a "tr" does work so long as you don't specify any attribute (other than "rendered"). It simply doesn't generate any HTML for that tag. That's why I was mislead into thinking that what I wanted to do was actually possible.

            Here's a thought, wouldn't be possible to work around that limitation with some javascript? I'm simply thinking out loud here as I've never really opened the hood of Ajax4jsf to see if it would even be possible. Couldn't we identify all the HTML elements of one "iteration" and use some javascript to recreate those elements from scratch and replace the old elements in the DOM when processing the AJAX response, even managing missing elements in the process as well? For instance, let's assume the following:

            <table>
             <thead>
             <tr>
             <th>Brand</th>
             <th>Model</th>
             <th>Year</th>
             <th>Action</th>
             </tr>
             </thead>
             <tbody>
             <a4j:repeat value="#{listOfCars}" var="car" ajaxKeys="#{ajaxKeys}">
             <h:groupPanel id="row">
             <h:panelGroup rendered="#{not car.editModeFlag}">
             <tr>
             <td>#{car.brand}</td>
             <td>#{car.model}</td>
             <td>#{car.year}</td>
             <td><a4j:commandLink action="#{car.toggleEditMode}" reRender="row"/>
             </tr>
             </h:panelGroup>
             <h:panelGroup rendered="#{car.editModeFlag}">
             <tr>
             <td><h:inputText value="#{car.brand}"/></td>
             <td><h:inputText value="#{car.model}"/></td>
             <td><h:inputText value="#{car.year}"/></td>
             <td rowspan="2"><a4j:commandButton action="#{car.save}" reRender="row"/>
             </tr>
             <tr>
             <td colspan="3"><h:inputText value="#{car.comments}" size="100"/></td>
             </tr>
             </h:panelGroup>
             </h:panelGroup>
             </a4j:repeat>
             </tbody>
            </table>
            


            What I wanted to achieve in this example is some sort of inline editing in a table. We have a list of cars and a link that enables us to edit one car at a time, directly in the table. To make it even more complicated, I've made it so that when in edit mode, a car spans on 2 rows (2 "tr" tags are actually rendered). What I meant earlier is that wouldn't it be possible to prepend the "id" of the h:panelGroup that is an immediate child of the a4j:repeat (the "row" panelGroup) to all it's child elements and use that to identify all the HTML tags that were generated in a given "iteration"? After that, when we are asked to re-render one car "iteration", we re-evaluate the whole "row" panelGroup, identify all the previous elements in the DOM for that same "id", delete them and replace them with the HTML that was generated, also managing the possibility that one "iteration" might have more/less "tr" tags than it did the time before.

            Anyways, like I said, this is just me thinking out loud. Please don't burry me if what I said doesn't make sense at all :)