2

My JSF application is behaving strangely, and I ask colleagues to help me identify a solution.

The application fetches data from the database through Facade+DAO classes, and through debug and println I can state that the object collection is correct (in the example below, the collection contains the 5 objects and their attributes), however, when passing this collection to the Primefaces page, dataTable does not display the attributes, it becomes clear that the the amount of rows is correct but the attributes are not displayed as shown in the figure.

I researched other posts, but the errors described do not resemble mine:

after filtering Empty rows blank rows displayed while paging in the datatable using Primefaces

primefaces datatable is showing blank rows. Showing the same number of rows as the records in backed list

Since the managed bean is reposting the collection correctly, I figured the issue should be on display (ie on the JSF page), and to try to find where the fault could be, I created a page without using Primefaces or Facelets, just pure JSF components, but the failure persisted. The basic code looks like this:

Here are the code snippets:

  • simple page

    <html xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html">
    
    <h:head>
        <link href="scripts/teste.css" rel="stylesheet" type="text/css" media="all" />
    </h:head>
    <h:body>
        <h:form>    
            <h:dataTable value="#{coletaMB.coletas}" var="coleta"
                styleClass="order-table"
                headerClass="order-table-header"
                rowClasses="order-table-odd-row,order-table-even-row">
               <h:column>
                    <f:facet name="header">Nr. Setor</f:facet>
                        <h:outputText value="#{coleta.setor.numero}"/>
                               ---- #{coleta.setor.numero} ----
               </h:column>
           </h:dataTable>       
       </h:form>
    

With this simple code, the page looks like this:

simple JSF page

  • managed bean

    @ManagedBean(name="coletaMB")
    @SessionScoped
    public class ColetaMB{
        @ManagedProperty(name="coleta", value="#{coleta}")
        private Coleta coleta;
        @ManagedProperty(name="coletaFacade", value="#{coletaFacade}")
        private ColetaFacade coletaFacade;
        private List<Coleta> coletas;
    
    
        public List<Coleta> getColetas(){
            if(coletas == null){
                coletas = getListColetas();
            }
            return coletas;
        }
    
        private List<Coleta> getListColetas(){
            coletas = new ArrayList<Coleta>();
            try {
                coletas =  coletaFacade.getColetas();
                return coletas;
            } catch (DAOException e) {
                (...)
            }
        }
        (...)
    }
    
  • Coleta.java

    public class Coleta {
        private int ano;
        private Setor setor;
        private int mes;
        private int semana;
        private int numeroEntrevista;
    
        (*)getters and setter
    }
    
  • Setor.java

    public class Setor {
        private Agencia agencia;
        private String numero;
        private String upa;
    
        (*)getters and setters
    }
    
  • Agencia.java

    public class Agencia {
        private int idAgencia;
        private String nome;
    
        (*)getters and setters
    }
    
  • Facade

    public List<Coleta> getColetas() throws DAOException {
        return dao.getColetas();
    }
    
  • DAO

    @Value("#{queries.sql01}")
    private String sql01;
    
    public List<Coleta> getColetas() throws DAOException {
        try{
            RowMapper<Coleta> mapper = getRowMapper();
            return getJdbcTemplate().query(sql01, mapper);
        } catch (DataAccessException de) {
            de.printStackTrace();
            throw new DAOException(de.getMessage());
        }
    }
    
    private RowMapper<Coleta> getRowMapper() {
        return new RowMapper<Coleta>() {
            public Coleta mapRow(ResultSet rs, int rowNum) throws SQLException {
                Agencia ag = new Agencia();
                ag.setIdAgencia(rs.getInt(1));
                ag.setNome(rs.getString(2));
    
                Setor s = new Setor();
                s.setAgencia(ag);
                s.setUpa(rs.getString(3));
                s.setNumero(rs.getString(4));
    
                Coleta c = new Coleta();
                c.setSetor(s);
                c.setAno(rs.getInt(5));
                c.setMes(rs.getInt(6));
                c.setSemana(rs.getInt(7));
                c.setNumeroEntrevista(rs.getInt(8));
    
                return c;
            }
        };
    }
    

In getListColetas, I inserted a println to verify the collection and it is complete, that is, each object 'coleta' has the object 'setor' and each 'setor' has the object 'agencia'. But, following the suggestion of using 'empty' on the JSF page,

<h:outputText value="#{empty coleta} - #{empty coleta.setor} - #{empty coleta.setor.numero}"/>

the return was false - true - true, and I don't know why.

My complete application is using the following libraries and dependencies (Spring is only used for DI and DAO classes):

build path

Rogério Arantes
  • 712
  • 1
  • 8
  • 29
  • 1
    As the issue persists using plain JSF dataTable it does not seem to be primefaces related. Are you sure for #{coleta.setor} the setor property is initialized and non null? – Selaron Sep 23 '19 at 19:14
  • 1
    When you debug, its the value of the collection not becoming null? maybe your getter needs to check if the collection is null and recalculate its value! also make sure your ManagedBean has the @ViewScoped annotation! checkout https://stackoverflow.com/questions/7031885/how-to-choose-the-right-bean-scope and also check this for getter behaviour https://stackoverflow.com/questions/2090033/why-jsf-calls-getters-multiple-times it happens with datatables also https://stackoverflow.com/questions/22662276/primefaces-datatable-call-method-multiple-times-when-click-commandbutton-why – BugsForBreakfast Sep 23 '19 at 20:07
  • @Selaron, thanks for your return. Honestly, I didn't know about the "empty operator", and your observation helped me understand better. Using your outputText suggestion, the return was "false - true - true". However, making a for in the collections list (before return to page) prints that out: Coleta [setor=520010005000015, ano=2019, mes=8, semana=3, numeroEntrevista=1] >> 5 lines That is, the setor is neither null nor empty, and has a 'numero'. – Rogério Arantes Sep 23 '19 at 20:27
  • BugsForBreakfast, thanks for your comment. The collection value is not null (I made a for and it lists elements) and managed bean has @SessionScoped annotation – Rogério Arantes Sep 23 '19 at 20:34
  • In addition, following the recommendation in post https://stackoverflow.com/questions/2090033/why-jsf-calls-getters-multiple-times, not to do business rule in getter (I had not commented, but for printed the collection more than once), I changed the code to return the collection and call the facade only if it is null. However, datatable still does not print the data. – Rogério Arantes Sep 23 '19 at 20:52
  • Please make a real [mcve] and check the scope... see if you use the **right** session scope... And debug... Set breakpoints etc... And your beans are JSF managed ones (or are you using the spring resolver? How is this spring related? – Kukeltje Sep 23 '19 at 21:29
  • @Kukeltje, as I said in the post above (second paragraph), I used debug and println to check the collection and objects returned by the facade and it is correct and complete (ie, according to BugsForBreakfast's suggestion, the 'coleta' object has the 'setor' and it has a 'numero'). I also followed suggestions and changed the scope to ViewScope, but the problem remains. – Rogério Arantes Sep 24 '19 at 13:31
  • [mcve].... please.... You can remove all PrimeFaces related things from the question. Make it lean but [mcve]... And you cannot use spring for CDI, CDI is a spec to which spring does not adhere, you can use Spring for DI. There is currently too much noise in your question. – Kukeltje Sep 24 '19 at 14:36
  • Thank you for making the big improvement to the question... Now please also read https://stackoverflow.com/tags/jsf/info and improve it even more (the independence of the database) – Kukeltje Sep 24 '19 at 18:32
  • No need for sarcasm. I tried to create minimal code to simulate the problem, but with pure JSF the problem was not repeated. It may be some incompatibility with all libraries of the full application, and so I am not identifying. As I said, the collection that comes from the facade is correct, which maintains database independence. – Rogério Arantes Sep 24 '19 at 18:51
  • @RogerioArantes, Hmm what about the css you are applying to the rows? try removing styleclasses and see if it display the rows with data, when this happened to me the solution was adding logic to the getter when data was null and also using ViewScoped – BugsForBreakfast Sep 24 '19 at 19:37
  • @BugsForBreakfast I deleted CSS but it didn't work (without eliminating CSS, I had already seen from the HTML code that the data wasn't there). I also tried ViewScope unsuccessfully. What is most intriguing to me is the use of empty, at your suggestion. Facade brings the complete object (tested by for before return), but empty prints "false - true - true", and I don't know why – Rogério Arantes Sep 24 '19 at 20:06
  • 1
    @RogerioArantes I see, you know what it could also be, maybe your FetchType of the data is "LAZY", can you check that? Because is thats the case then statements like this will only work with primary or foreign keys, if you want to bring data of an Object that is inside another Object and you are using LAZY instead of EAGER, you gotta use pattern DTO (Data Access Object), in this Object you will have all the attributes of all the Objects which you wanna show on your datatable, please check if you are using LAZY, check it on your model getters – BugsForBreakfast Sep 24 '19 at 20:37
  • @BugsForBreakfast, I'm not using Java Persistence API / Hibernate. My DAO uses JdbcTemplate, from Spring. – Rogério Arantes Sep 24 '19 at 20:48

1 Answers1

0

Resolved: in dataTable tag, I changed the attribute var="coleta" to var="c", like this:

<h:dataTable value="#{coletaMB.coletas}" var="c"
        styleClass="order-table"
        headerClass="order-table-header"
        rowClasses="order-table-odd-row,order-table-even-row">
       <h:column>
            <f:facet name="header">Nr. Setor</f:facet>
                <h:outputText value="#{c.setor.numero}"/>
                       ---- #{c.setor.numero} ----
       </h:column>
</h:dataTable>   

I imagine JSF was conflicting with the @ManagedProperty 'coleta' in ColetaMB, although I understand that the var attribute is specific to varying collection objects delivered to dataTable.

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Rogério Arantes
  • 712
  • 1
  • 8
  • 29