[RESOLVIDO] Problema com Primefaces - DataTable não persiste dado no p:commandLink

É o seguinte pessoal.
Estou desenvolvendo uma aplicação utilizando JSF 2.0 com Primefaces.
Em uma das minhas telas, eu preciso apresentar várias informações aninhadas e para isso estou utilizando o componente DataTable do Primefaces junto do RowToggler, que permite que eu expanda as linhas de minha tabela para apresentar mais informações.

O caso é: Tenho um Bean Pai que possui uma lista de Beans Filhos. Esse Bean Filho por sua vez, possui uma lista de Beans Netos.
Minha tela, apresenta os dados do PAI e crio uma tabela onde serão apresentandos os dados do Filho.
Em cada Filho (linha dessa tabela), eu tenho meu RowToggler que expande a tabela, exibindo uma outra tabela contendo os Netos. (tabela dentro de tabela). Nessa tabela dos Netos, no rodapé dela eu tenho um botão (p:commandLink) para adicionar um novo neto.

A questão, é que pra eu adicionar um novo Neto eu preciso saber a referência dele na tabela filho, seria algo como, eu preciso saber filho de quem ele é pra poder adicioná-lo.
Está tudo funcionando perfeitamente, porém, quando vou adicionar o Neto, meu BackingBean dá nullPointerException pois não sabe quem é o FILHO, mesmo eu tentando fazer binding dele no meu XHTML.

Bom, fica confuso de se explicar, mais abaixo vou deixar um código perfeitamente funcional para quem quiser ver o problema e quem sabe, achar a solução.
Creio que as únicas alterações necessárias serão em algum import ou no SKin do Primefaces.

Abaixo, os 3 Beans:

[code]import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class FatherBean implements Serializable {

private String name;
private String lastName;
private List<SonBean> sonsBean;

public FatherBean(String name, String lastName) {
    this.name = name;
    this.lastName = lastName;

    sonsBean = new ArrayList<SonBean>();
}

public FatherBean() {
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public List<SonBean> getSonsBean() {
    return sonsBean;
}

public void setSonsBean(List<SonBean> sonsBean) {
    this.sonsBean = sonsBean;
}

}[/code]

[code]import java.io.Serializable;

public class GrandsonBean implements Serializable {

private String name;
private String lastName;

public GrandsonBean(String name, String lastName) {
    this.name = name;
    this.lastName = lastName;
}

public GrandsonBean() {
}

public String getLastName() {
    return lastName;
}

public void setLastName(String lastName) {
    this.lastName = lastName;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

}
[/code]

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class SonBean implements Serializable {

    private String name;
    private String lastName;
    private List<GrandsonBean> grandsonsBean;

    public SonBean(String name, String lastName) {
        this.name = name;
        this.lastName = lastName;

        grandsonsBean = new ArrayList<GrandsonBean>();
    }

    public SonBean() {
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<GrandsonBean> getGrandsonsBean() {
        return grandsonsBean;
    }

    public void setGrandsonsBean(List<GrandsonBean> grandsonsBean) {
        this.grandsonsBean = grandsonsBean;
    }
}

Meu Managed Bean:


import java.io.Serializable;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean(name = "testMB")
@ViewScoped
public class commanLinkTestMB implements Serializable {

    private FatherBean father;
    private SonBean son = new SonBean();
    private GrandsonBean grandson = new GrandsonBean();

    public commanLinkTestMB() {
        this.father = new FatherBean("John", "Doe");

        GrandsonBean grandson1 = new GrandsonBean("aaa", "aaaa");
        GrandsonBean grandson2 = new GrandsonBean("abb", "abbb");
        GrandsonBean grandson3 = new GrandsonBean("acc", "accc");
        GrandsonBean grandson4 = new GrandsonBean("bbb", "bbbb");
        GrandsonBean grandson5 = new GrandsonBean("bcc", "bccc");
        GrandsonBean grandson6 = new GrandsonBean("bdd", "bddd");

        SonBean son1 = new SonBean("Son-1", "111");
        SonBean son2 = new SonBean("Son-2", "222");

        son1.getGrandsonsBean().add(grandson1);
        son1.getGrandsonsBean().add(grandson2);
        son1.getGrandsonsBean().add(grandson3);

        son2.getGrandsonsBean().add(grandson4);
        son2.getGrandsonsBean().add(grandson5);
        son2.getGrandsonsBean().add(grandson6);

        this.father.getSonsBean().add(son1);
        this.father.getSonsBean().add(son2);

    }

    public FatherBean getFather() {
        return father;
    }

    public void setFather(FatherBean father) {
        this.father = father;
    }

    public SonBean getSon() {
        return son;
    }

    public void setSon(SonBean son) {
        this.son = son;
    }

    public GrandsonBean getGrandson() {
        return grandson;
    }

    public void setGrandson(GrandsonBean grandson) {
        this.grandson = grandson;
    }

    public void addGrandson() {
        System.out.println("Log -----name - " + son.getName());
        System.out.println("Log -----lastName - " + son.getName());
        this.son.getGrandsonsBean().add(grandson);
    }
}

Meu XHTML:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:p="http://primefaces.prime.com.tr/ui">
    <link type="text/css" rel="stylesheet" href="./CSS/Rich/skin.css"/>
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>

        <h:form id="form1">
            <p:panel header="Father">

                <!-- Panel 1 ###################################-->
                <p:panel header="Fathers Info" toggleable="true">
                    <h:panelGrid columns="1">
                        <h:panelGrid columns="5">

                            <h:outputText value="Name:" />
                            <h:outputText value="#{testMB.father.name}"/>
                            <p:divider/>
                            <h:outputText value="LastName:" />
                            <h:outputText value="#{testMB.father.lastName}"/>
                        </h:panelGrid>
                    </h:panelGrid>
                </p:panel>

                <p:panel header="Sons" toggleable="true">

                    <p:dataTable id="table" value="#{testMB.father.sonsBean}" var="sons" rows="10" paginatorPosition="bottom" rendered="true">

                        <p:column  style="width:20px">
                            <p:rowToggler/>
                        </p:column>

                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Name" />
                            </f:facet>
                            <h:outputText value="#{sons.name}"/>
                        </p:column>

                        <p:column>
                            <f:facet name="header">
                                <h:outputText value="Last Name" />
                            </f:facet>
                            <h:outputText value="#{sons.lastName}"/>
                        </p:column>

                        <!--*************************************-->
                        <!--Init Expansion-->
                        <!--*************************************-->

                        <f:facet name="expansion">

                            <p:panel header="Grandsons" toggleable="true">
                                <p:dataTable id="subTable" value="#{sons.grandsonsBean}"  var="grand" >
                                    <p:column>
                                        <f:facet name="header">
                                            <h:outputText value="Grandson Name" />
                                        </f:facet>
                                        <h:outputText value="#{grand.name}"/>
                                    </p:column>

                                    <p:column>
                                        <f:facet name="header">
                                            <h:outputText value="Grandson Last Name" />
                                        </f:facet>
                                        <h:outputText value="#{grand.lastName}"/>
                                    </p:column>

                                    <f:facet name="footer">
                                        <p:column>
                                            <p:commandLink id="addlink" oncomplete="addGrandSon.show()" immediate="true">
                                                <h:graphicImage value="/images/icons/add1.png" style="border:0"/>
                                                <f:setPropertyActionListener value="#{sons}" target="#{testMB.son}"/>
                                            </p:commandLink>
                                        </p:column>
                                    </f:facet>
                                </p:dataTable>
                            </p:panel>

                        </f:facet>
                        <!--*************************************-->
                        <!--End Expansion-->
                        <!--*************************************-->
                    </p:dataTable>
                </p:panel>
            </p:panel>


            <!-- ################################### -->
            <!-- Edition block -->
            <p:dialog widgetVar="addGrandSon" width="450" modal="true" header="Editar Registro" resizable="false">

                <h:panelGrid columns="2">

                    <h:outputText value="Name" />
                    <h:inputText value="#{testMB.grandson.name}"/>
                    <h:outputText value="Last Name"/>
                    <h:inputText value="#{testMB.grandson.lastName}"/>

                    <p:commandButton value="Add"
                                     action="#{testMB.addGrandson}"
                                     update="form1:Grandsons"
                                     oncomplete="addGrandSon.hide();"/>
                    <p:commandButton value="Cancel"
                                     onclick="addGrandSon.hide();return false;" />
                </h:panelGrid>

            </p:dialog>
        </h:form>
    </h:body>
</html>

Já tentei várias coisas, tentei passar o atributo no “action” do commandLink e nada.Ainda não consegui resolver…
Fico no aguardo de qualquer solução.

Edit: Quando eu clico em adicionar o NETO, meu ManagedBean é chamado e o atributo NETO está com o Binding feito corretamente, porém, o FILHO está null, ou seja, a seguinte linha:

 <f:setPropertyActionListener value="#{sons}" target="#{testMB.son}"/>

Parece não ser executada como deveria.

Tenho o mesmo problema.
Parece que o problema está relacionado a tabelas aninhadas + passagem de parâmetros para o BackingBean.

Alguém tem alguma sugestão sobre como contornar o problema?

Obrigado,

Na atual versão do Primefaces 2.2 RC2 o problema realmente ocorre.
A versão que será lançada na próxima semana do Primefaces, parece corrigir o problema.

O RowToggler para expandir as linhas de uma tabela, passará a utilizar o componente <p:rowExpansion> e não mais o <f:facet expansion>.
Dessa forma, será possível passar corretamente o valor dos atributos de tabelas aninhadas para o BackingBean.

A solução foi confirmada quando baixei a última versão (Build Noturno) do Primefaces e testei nessa mesma aplicação de exemplo do erro que postei.
:wink: