PrimeFaces Datatable in a nutshell

The dataTable is a key component of JSF architecture. It can display Objects in a Collection or an Array where each Object represents one row in the table and columns match instance variables in the Object. In this tutorial we will show how to use the Primefaces Datatable component in minutes.

If you are new to Primefaces we recommend checking our HelloWorld introduction to it: HelloWorld Primefaces

Setting up the Primefaces Web project

Firstly, create a Web project using Maven with the following dependencies in it:

<dependencies>
    <dependency>
        <groupId>jakarta.platform</groupId>
        <artifactId>jakarta.jakartaee-api</artifactId>
        <version>8.0.0</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.primefaces</groupId>
        <artifactId>primefaces</artifactId>
        <version>${primefaces.version}</version>
    </dependency>
</dependencies>

Then, we will add our first Primefaces datatable:

<p:dataTable var="item" value="#{dtBasicView.items}" size="small" stripedRows="true">
    <p:column headerText="Code">
        <h:outputText value="#{item.id}" />
    </p:column>

    <p:column headerText="Name">
        <h:outputText value="#{item.name}" />
    </p:column>

    <p:column headerText="Category">
        <h:outputText value="#{item.category}" />
    </p:column>

    <p:column headerText="Quantity">
        <h:outputText value="#{item.price}" />
    </p:column>
</p:dataTable>

As you can see, in its most basic configuration, Primefaces datatable is not too different from JSF datatable. We have added a couple of Primefaces custom parameters in it:

  • size: determines the datatable size (small/regular/large)
  • stripedRows: allows to use striped rows when set to “true”

The matching ItemView Bean follows here:

@Named("dtBasicView")
@ViewScoped
public class ItemView implements Serializable {

    private List<Item> items;

    @Inject
    private ItemService service;

    @PostConstruct
    public void init() {
        items = service.getItems();
    }

    public List<Item> getItems() {
        return items;
    }

    public void setService(ItemService service) {
        this.service = service;
    }
    
}

The Bean ItemView is merely used to store a List of Item objects that are referenced in the Datatable.

The ItemService Class is our tiny Persistence Layer which reads the list of Item objects from the DB.

@Stateless
public class ItemService {
    List<Item> items;
    
    @PersistenceContext
    private EntityManager em;

    @PostConstruct
    public void init() {		 
        Query query = em.createQuery("FROM Item");
        items = query.getResultList();
    }

    public List<Item> getItems() {
        return items;
    }

    public void setItems(List<Item> items) {
        this.items = items;
    }

}

Finally, the Entity class which maps the table Item:

@Entity
@Table
public class Item {

    @Id
    @GeneratedValue
    Integer id;
    String name;
    String category;
    double price;

    // Getter/Setters and Constructors omitted for brevity

}

Within the source code for this example, you will find also the persistence.xml file to connect to an existing Datasource (WildFly default Datasource) and an import.sql file to load some data in the DB.

Let’s see our basic Primefaces datatable in action:

Adding data at runtime

Our next task will be to add new Item objects at runtime. To keep it as simple as possible, we will just add a button in the Form which adds a new Item with random data:

 <p:dataTable var="item" value="#{dtBasicView.items}" id="mydata" size="small" stripedRows="true">
    <p:column headerText="Code">
        <h:outputText value="#{item.id}" />
    </p:column>

    <p:column headerText="Name">
        <h:outputText value="#{item.name}" />
    </p:column>

    <p:column headerText="Category">
        <h:outputText value="#{item.category}" />
    </p:column>

    <p:column headerText="Quantity">
        <h:outputText value="#{item.price}" />
    </p:column>
</p:dataTable>

<p:commandButton  action="#{dtBasicView.addRandom}" update="mydata" value="Add Random" icon="ui-icon-check" style="margin:0"/>  	

Within the commandButton, we have set to update the component id “mydata” which is the datatable.

The ItemView method “addRandom” wraps the Session Bean:

public void addRandom() {
        service.addRandomItem();
}

The ItemService inserts an Item with random data on the DB:

public void addRandomItem() {
    Item item = new Item();
    item.setCategory(UUID.randomUUID().toString());
    item.setName(UUID.randomUUID().toString());
    item.setPrice(Math.random() * 1000 + 1);
    items.add(item);
    em.persist(item);

}  

Editing Data

Another key feature of Primefaces datatable is the ability to edit and update the Cells of a Row.

To be able to edit data we need some changes in the dataTable and add a new server method to update the Row. Here is the edit.xhtml page:

<h:form id="form">
    <p:growl id="msgs" showDetail="true"/>
    <div class="card">
        <p:dataTable var="item" value="#{dtBasicView.items}"  editable="true" size="small" stripedRows="true">
            <p:ajax event="rowEdit" listener="#{dtBasicView.onRowEdit}" update=":form:msgs"/>
            <p:ajax event="rowEditCancel" listener="#{dtBasicView.onRowCancel}" update=":form:msgs"/>
            <p:column headerText="Code">
                <h:outputText value="#{item.id}" />
            </p:column>
            <p:column headerText="Name">
                <p:cellEditor>
                    <f:facet name="output">
                        <h:outputText value="#{item.name}"/>
                    </f:facet>
                    <f:facet name="input">
                        <p:inputText label="Name" value="#{item.name}" style="width:100%"/>
                    </f:facet>
                </p:cellEditor>
            </p:column>
            <p:column headerText="Category">
                <p:cellEditor>
                    <f:facet name="output">
                        <h:outputText value="#{item.category}"/>
                    </f:facet>
                    <f:facet name="input">
                        <p:inputText label="Category" value="#{item.category}" style="width:100%"/>
                    </f:facet>
                </p:cellEditor>
            </p:column>
            <p:column headerText="Quantity">
                <p:cellEditor>
                    <f:facet name="output">
                        <h:outputText value="#{item.price}"/>
                    </f:facet>
                    <f:facet name="input">
                        <p:inputText label="Price" value="#{item.price}" style="width:100%"/>
                    </f:facet>
                </p:cellEditor>
            </p:column>
            <p:column style="width:6rem">
                <p:rowEditor editTitle="Edit Row" cancelTitle="Cancel Edit" saveTitle="Save Row"/>
            </p:column>
        </p:dataTable>
    </div>
</h:form>

Don’t be scared if it looks bigger than our first example. As a matter of fact, we had to wrap – for each editable column- a p:cellEditor element. The cellEditor element contains a facet to output the field and a facet for collecting input, when we are editing.

We also added two ajax elements in order to capture events such as start edit and cancel edit.

Here are both methods, contained in the ItemView Bean:

public void onRowEdit(RowEditEvent<Item> event) {
    FacesMessage msg = new FacesMessage("Product Edited", String.valueOf(event.getObject().getName()));
    FacesContext.getCurrentInstance().addMessage(null, msg);
    service.save(event.getObject());
}

public void onRowCancel(RowEditEvent<Item> event) {
    FacesMessage msg = new FacesMessage("Edit Cancelled", String.valueOf(event.getObject().getName()));
    FacesContext.getCurrentInstance().addMessage(null, msg);
}

To update the DB with your change, we also have added a save method in our ItemService class:

public void save(Item item) {
    Integer id = item.getId();
    Item itemdb = em.find(Item.class, id);
    itemdb.setCategory(item.getCategory());
    itemdb.setName(item.getName());
    itemdb.setPrice(item.getPrice());
    em.persist(itemdb);

} 

Let’s test the datatable in edit mode:

As you can see, all fields (except the Code which is a Primary Key in the DB) can be edited.

Using a Datatable with a Paginator

In most cases, you will have a large set of data to display. For this reason, it is advised to use a Paginator which breaks your data in a configurable set of pages. That’s not at all complicated. Let’s see how to do it:

<p:dataTable var="item" value="#{dtBasicView.items}" size="small" stripedRows="true" rows="10" id="mydata"
             paginator="true"
             paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
             currentPageReportTemplate="{startRecord}-{endRecord} of {totalRecords} records"
             rowsPerPageTemplate="5,10,{ShowAll|'All'}">

To activate a Paginator you need to set the attribute “paginator” to “true”. Also, you can provide a Template for it (which maps to the Paginator buttons) and the number of Rows to show, which is controlled by the rowsPerPageTemplate field.

With the above configuration, the view will look like that:

Configuring Datatable expansion

The next example we will include, allows to expand the view showing some extra fields. For example, in the Datatable row you might show only some key fields. By clicking on the single row you can expand it to show some accessory fields. Let’s see how to do it.

<p:dataTable var="item" value="#{dtBasicView.items}" size="small" stripedRows="true">
    <f:facet name="header">
        Expand rows to see detailed information
    </f:facet>
    <p:column style="width:2rem">
        <p:rowToggler/>
    </p:column>
    
    <p:column headerText="Code">
        <h:outputText value="#{item.id}" />
    </p:column>

    <p:column headerText="Name">
        <h:outputText value="#{item.name}" />
    </p:column>

    <p:column headerText="Category">
        <h:outputText value="#{item.category}" />
    </p:column>

    <p:rowExpansion>
        <h:panelGrid id="display" columns="2" cellpadding="4"
            style="width:300px;" styleClass="ui-widget-content"
            columnClasses="label, value">

            <h:outputText value="Item name:" />
            <h:outputText id="extra" value="#{item.name}" />

            <h:outputText value="Price:" />
            <h:outputText id="date" value="#{item.price}" />

        </h:panelGrid>

    </p:rowExpansion>

</p:dataTable>

So, our datatable includes an extra column with a RowToggler, which hides the expanded row. Then, we have added a rowExpansion element which shows a Panel with some extra data. In our case, we will show the Price of the Item.

Here is it in action:

 

Dynamic Primefaces datatable

A common need for many applications is to create tabular data with a dynamic number of columns. Columns can be added programmaticaly, thus you can use the same dataTable for displaying different kind of models.

Creating a dynamic datatable with PrimeFaces is really easy: instead of using the standard <p:column> tag, use the <p:columns> which references the list of columns (via the value attribute) that are mantained in a Collection.

Here is a simple example:

<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.org/ui">

<h:head>

</h:head>

<h:body>
    <h:form id="form" prependId="false">

        <h3>Dynamic Data table example</h3>
        <p:dataTable var="data" value="#{tableBean.people}">
            <p:columns value="#{tableBean.columns}" var="column"
                columnIndexVar="colIndex">
                <f:facet name="header">
                #{column.header}
                </f:facet>

            #{data[column.property]}
            </p:columns>
        </p:dataTable>

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

This is the JSF Managed Bean used:

@ManagedBean
public class TableBean implements Serializable {

    private List<ColumnModel> columns;
    private List<People> people;

    private String columnName;

    public TableBean() {
        createDynamicColumns();
        addPeople();
    }

    private void addPeople() {
        people = new ArrayList<People>();

        People w1 = new People("Homer Simpson","The father",48);
        People w2 = new People("Marge Simpson","The mother",46);
        People w3 = new People("Bart Simpson","Oldest child",11);
        People w4 = new People("Lisa Simpson","Sister of Bart",8);

        people.add(w1);
        people.add(w2);
        people.add(w3);
        people.add(w4);
    }

    private void createDynamicColumns() {

        columns = new ArrayList<ColumnModel>();
        columns.add(new ColumnModel("Name", "name"));
        columns.add(new ColumnModel("Role", "role"));
        columns.add(new ColumnModel("Age", "age"));
    }

    public List<People> getPeople() {
        return people;
    }

    public void setPeople(List<People> people) {
        this.people = people;
    }

    public List<ColumnModel> getColumns() {
        return columns;
    }

    public String getColumnName() {
        return columnName;
    }

    public void setColumnName(String columnName) {
        this.columnName = columnName;
    }

    static public class ColumnModel implements Serializable {

        private String header;
        private String property;

        public ColumnModel(String header, String property) {
            this.header = header;
            this.property = property;
        }

        public String getHeader() {
            return header;
        }

        public String getProperty() {
            return property;
        }
    }
}

And this is the datatable, which has been built dynamically on the server side:

Conclusion

We have covered how to use Primefaces Datatable component starting from the basic component to more advanced use cases.

Download the example from this tutorial.

Export your dataTable to Excel and PDF using Primefaces

Do you need exporting your JSF dataTable to any kind of format such as Excel, PDF, CSV, XML ? We have updated this tutorial to Primefaces 10 to do it in a minute!

In order to export your dataTable, you can use the DataExporter UICommand which is part of the Primefaces suite. Using it is pretty simple. The required libraries to run this example are:

  • Primefaces library
  • Apache POI library (dependency)
  • iText library  (dependency)

The recommended way to configure your project for a Jakarta EE server (such as WildFly) requires the following dependencies in your pom.xml:

<dependencies>
    <dependency>
        <groupId>jakarta.platform</groupId>
        <artifactId>jakarta.jakartaee-api</artifactId>
        <version>8.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.primefaces</groupId>
        <artifactId>primefaces</artifactId>
        <version>${primefaces.version}</version>
    </dependency>

    <dependency>
        <groupId>com.lowagie</groupId>
        <artifactId>itext</artifactId>
        <version>2.1.7</version>
    </dependency>

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>5.0.0</version>
    </dependency>
</dependencies>

The PrimeFaces component required to export your dataTable is called DataExporter and it is nested in a UICommand component such as commandButton or commandLink. See the following example:

<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.org/ui">

<h:head>
</h:head>

<h:body>
    <h:form id="jsfexample">
        <p:panelGrid columns="2">
            <f:facet name="header">  
                Basic PanelGrid  
           </f:facet>
            <h:outputLabel for="key" value="Enter Name" />
            <p:inputText id="key" value="#{manager.name}" />

            <h:outputLabel for="value" value="Enter Surname" />
            <p:inputText id="value" value="#{manager.surname}" />

            <h:outputLabel for="age" value="Enter Age" />
            <p:inputText id="age" value="#{manager.age}" />

            <h:outputLabel for="city" value="Enter City" />
            <p:inputText id="city" value="#{manager.city}" />
            <p:commandButton action="#{manager.save}" update="mydata"
                value="Save" icon="ui-icon-check" style="margin:0" />
            <p:commandButton action="#{manager.clear}" update="mydata"
                value="Delete" icon="ui-icon-cancel" style="margin:0" />

            <h:messages />

        </p:panelGrid>
        <br />
        <p:dataTable value="#{manager.cacheList}" var="item" id="mydata">
            <p:column>
                <f:facet name="header">Name</f:facet>
                <h:outputText value="#{item.name}" />
            </p:column>
            <p:column>
                <f:facet name="header">Surname</f:facet>
                <h:outputText value="#{item.surname}" />
            </p:column>
            <p:column>
                <f:facet name="header">Age</f:facet>
                <h:outputText value="#{item.age}" />
            </p:column>
            <p:column>
                <f:facet name="header">City</f:facet>
                <h:outputText value="#{item.city}" />
            </p:column>
        </p:dataTable>
        <p:panel header="Export All Data">
            <h:commandLink>
                <p:graphicImage value="/icons/excel.jpg" />
                <p:dataExporter type="xls" postProcessor="#{manager.postProcessXLS}"
                    target="mydata" fileName="myexcel" />
            </h:commandLink>
            <h:commandLink>
                <p:graphicImage value="/icons/pdf.png" />
                <p:dataExporter type="pdf" target="mydata" fileName="mypdf" />
            </h:commandLink>
        </p:panel>

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

As you can see this page contains:

  • a form for instering data
  • a datatable with id=”mydata”
  • a panel used to export data in Excel or PDF

The <p:dataExporter> specifies the type of export with the “type” attribute. You can opt between “xls“,”pdf,”csv” and “xml“. Next, you need to select the dataTable with the “target” attribute and the resulting filename with the “fileName” attribute. (In this tutorial we will show just Excel and PDF export, however using csv and xml is trivial, just add the required type attribute to the dataExporter)

Additionally an Excel, PDF dataExporter can use the preProcessor or postProcessor to add some pre-processing or post-processing functionalities to your document. This can be used to add custom styles to your document or also to modify the content as well. For example here is the JSF bean which contains the Excel postProcessor method postProcessXLS which does some uppercase and styling to your excel:

package com.mastertheboss.controller;

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

import javax.faces.view.ViewScoped;
import javax.inject.Named;

import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;

import com.mastertheboss.model.Person;

@Named(value = "manager")
@ViewScoped
public class PropertyManager implements Serializable {

    private String name;
    private String surname;
    private int age;
    private String city;

    ArrayList<Person> cacheList = new ArrayList();

    public void save() {
        Person p = new Person(name, surname, age, city);
        cacheList.add(p);
    }

    public void clear() {
        cacheList.clear();
    }

    public void postProcessXLS(Object document) {

        HSSFWorkbook wb = (HSSFWorkbook) document;
        HSSFSheet sheet = wb.getSheetAt(0);
        CellStyle style = wb.createCellStyle();
        style.setFillBackgroundColor(IndexedColors.AQUA.getIndex());

        for (Row row : sheet) {
            for (Cell cell : row) {

                switch (cell.getCellType()) {

                case STRING:
                    cell.setCellValue(cell.getStringCellValue().toUpperCase());
                    cell.setCellStyle(style);
                    break;

                }

            }
        }
    }

    // Getters/Setters omitted for brevity
}

Within the postProcessXLS we are iterating over the list of Rows and Cells of the Spreadsheet. then, we are checking the Cell type to apply an Uppercase if the Cell contains a String

Here’s the application in action:

Exporting the dataTable in CSV or XML

It is also possible to export your dataTable in other standard formats such as CSV or XML. It is only matter of changing the type attribute. For example, in CSV format:

<h:commandLink>
	<p:commandButton value="Export as CSV" ajax="false" >
	<p:dataExporter type="csv" target="mydata" fileName="mycsv.csv" pageOnly="true" />
</h:commandLink>

This is how to export the dataTable in XML format:

<h:commandLink>
	<p:commandButton value="Export as XML" ajax="false" >
	<p:dataExporter type="xml" target="mydata" fileName="mydata.xml" pageOnly="true" />
</h:commandLink>

Exporting only the current page

By default dataExporter works on whole dataset, if you’d like export only the data displayed on current page (as we did in our example), set the pageOnly attribute to true.

<p:dataExporter type="xml" target="mydata" fileName="mydata.xml" pageOnly="true" />

Installing POI and iText as modules on WildFly

If you plan to use POI and iText across several applications of yours, then why not installing them as a module with WildFly ? First download the JAR files for both libraries.

Then, you can install them on WildFly as a module by running the following CLI command:

[standalone@localhost:9990 /] module add --name=org.apache.poi --dependencies=javax.api,org.apache.commons.logging --resources=poi-5.0.0.jar
[standalone@localhost:9990 /] module add --name=com.lowagie.itext --resources=itext-2.1.7.jar

This is the module structure for Apache POI:

+---org
     +---apache
         +-----poi
              +-----main
                    module.xml
                    poi-3.17.jar

Within it, there’s the following module.xml:

<module xmlns="urn:jboss:module:1.1" name="org.apache.poi">
    <properties>
        <property name="jboss.api" value="private"/>
    </properties>
    <resources>
        <resource-root path="poi-3.17.jar"/>
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="org.apache.commons.logging"/>
    </dependencies>
</module>

On the other hand, this is the module path for iText:

+---com
      +----lowagie
           +----itext
                +-----main
                      module.xml
                      itext-2.1.7.jar

And the corresponding module.xml

<module xmlns="urn:jboss:module:1.1" name="com.lowagie.itext">

    <properties>
        <property name="jboss.api" value="private"/>
    </properties>

     <resources>
        <resource-root path="itext-2.1.7.jar"/>
    </resources>
    <dependencies>
    </dependencies>

</module>

Fine, now the last thing to do is setting the application dependencies into the META-INF/MANIFEST.MF file:

Manifest-Version: 1.0
Dependencies: org.apache.poi com.lowagie.itext export

Great. Now your WildFly is able to use iText and POI libraries as a module.

 Last thing to note: the current release of Primefaces libraries refers to an older release of iText. If you try to install the latest iText distribution you will end up to the following error: java.lang.NoClassDefFoundError: com/lowagie/text/
This is due to the fact that in the recent iText release the package com/lowagie/text has been renamed as com/itextpdf/text. So until this is fixed use the suggested iText release (2.1.7) or at least verify the package structure.

You can find the code from this PrimeFaces Exporter Demo here. Enjoy it !

How to populate a dataTable from a JSON file

How to use natively JSON data into a JSF dataTable ? When using Primefaces you have more than one option to do it!

The JSF dataTable tag is used to display data on JSF view pages. The data bound table components are responsible for displaying the relational data in a tabular format. typically a dataTable is backed by a List of java Objects which are filled from a source. As you can imagine, by parsing an external resource of file you can display anything you like in your dataTable.

Primefaces, however, ships with two built-in solutions which are perfectly fit for displaying data in JSON format.

Use JSONArray and JSONObject

The first solution we will discuss is a pure Java solution which uses some classes in the package org.primefaces.json that can be added directly into the dataTable’s list. Let’s see an example:

package com.mastertheboss;

import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;

import org.primefaces.json.JSONArray;
import org.primefaces.json.JSONObject;

@ManagedBean(name = "jsonService")
@ApplicationScoped
public class MyJsonService {

    public List getData() throws Exception {
        String data = "  [{\n" + 
                "    \"nm\": \"Harold II\",\n" + 
                "    \"cty\": \"United Kingdom\",\n" + 
                "    \"hse\": \"House of Wessex\",\n" + 
                "    \"yrs\": \"1066\"\n" + 
                "  },\n" + 
                "  {\n" + 
                "    \"nm\": \"William I\",\n" + 
                "    \"cty\": \"United Kingdom\",\n" + 
                "    \"hse\": \"House of Normandy\",\n" + 
                "    \"yrs\": \"1066-1087\"\n" + 
                "  },\n" + 
                "  {\n" + 
                "    \"nm\": \"William II\",\n" + 
                "    \"cty\": \"United Kingdom\",\n" + 
                "    \"hse\": \"House of Normandy\",\n" + 
                "    \"yrs\": \"1087-1100\"\n" + 
                "  },\n" + 
                "  {\n" + 
                "    \"nm\": \"Henry I\",\n" + 
                "    \"cty\": \"United Kingdom\",\n" + 
                "    \"hse\": \"House of Normandy\",\n" + 
                "    \"yrs\": \"1100-1135\"\n" + 
                "  },\n" + 
                "  {\n" + 
                "    \"nm\": \"Stephen\",\n" + 
                "    \"cty\": \"United Kingdom\",\n" + 
                "    \"hse\": \"House of Blois\",\n" + 
                "    \"yrs\": \"1135-1154\"\n" + 
                "  }]";

        List monarchList = new ArrayList<>();
        JSONArray jsonArray = new JSONArray(data);
        for (int i = 0; i < jsonArray.length(); i++) {
            JSONObject json = jsonArray.getJSONObject(i);  
            monarchList.add(new Monarch(json.getString("nm"), json.getString("cty"), json.getString("hse"), json.getString("yrs")));
        }

        return monarchList;
    }

}

So in this bean we have statically created a JSON String which is an array of items. We have therefore created a JSONArray from that String and extracted the JSONObject creating a Java Bean for each entry. The Java Bean class (Monarch) is added into the List.

This simple Bean class is exposed as a JSF ManagedProperty to your View:

package com.mastertheboss;

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

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;

@ManagedBean(name = "jsonView")
@ViewScoped

public class MyJsonView implements Serializable {

    private List monarchList = new ArrayList<>();

    @ManagedProperty("#{jsonService}")
    private MyJsonService service;

    @PostConstruct
    public void init() {
        try {
            monarchList = service.getData();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public List getMonarchList() {
        return monarchList;
    }

    public void setMonarchList(ArrayList list) {
        this.monarchList = list;
    }

    public void setService(MyJsonService service) {
        this.service = service;
    }
}

That’s all. For the sake of completeness, we will include also the Java Bean class:

package com.mastertheboss;

public class Monarch {
    String name;
    String city;
    String house;
    String years;

    public String getName() {
        return name;
    }

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

    public Monarch(String name, String city, String house, String years) {
        super();
        this.name = name;
        this.city = city;
        this.house = house;
        this.years = years;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getHouse() {
        return house;
    }

    public void setHouse(String house) {
        this.house = house;
    }

    public String getYears() {
        return years;
    }

    public void setYears(String years) {
        this.years = years;
    }
}

The index.xhtml page, will display your dataTable’s List of Monarch objects:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
          xmlns:h="http://xmlns.jcp.org/jsf/html"
          xmlns:p="http://primefaces.org/ui">
        <h:head>
            <title>JSON Datatable</title>
        </h:head>
        <h:body>
            <h:form>
                <p:dataTable var="data" value="#{jsonView.monarchList}">
                    <p:column headerText="Name" sortBy="#{data.name}">
                        <h:outputText value="#{data.name}" />
                    </p:column>
                    <p:column headerText="House" sortBy="#{data.house}">
                        <h:outputText value="#{data.house}" />
                    </p:column>
                    <p:column headerText="City" sortBy="#{data.city}">
                        <h:outputText value="#{data.city}" />
                    </p:column>
                    <p:column headerText="Years" sortBy="#{data.years}">
                        <h:outputText value="#{data.years}" />
                    </p:column>                                        
                </p:dataTable>
            </h:form>
        </h:body>
    </html>

Here is your application once deployed on WildFly:

You can find the full project here: https://github.com/fmarchioni/mastertheboss/tree/master/web/primefaces/json-datatable

Use Prime UI

Another option is using PrimeUI. PrimeUI is a JavaScript library that spins off from PrimeFaces and consists of a set of javascript widgets to create rich UIs easily. So basically it’s a decoupling from the standard widgets based on (PrimeFaces + JSF) and creating a pure javascript library to make Primefaces widgets available to any framework. These widgets are implemented with plain jQuery, designed to work with JSON for data progressing and use client side progressive enhancement to render UIs.

PrimeUI is available for download at: https://github.com/primefaces/primeui/releases . A sample of a dataTable which uses JSON natively is available in the PrimeUI showcase. We will add a simplified example of it here:

<html ng-app>
  <head>
    <link href="development/prime-ui-0.9.5.css" rel="stylesheet">
    <link href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" rel="stylesheet">
    <link href="http://www.primefaces.org/prime-ui/demo/css/aristo/theme.css" rel="stylesheet">
    <link href="http://www.primefaces.org/prime-ui/demo/css/sh.css" rel="stylesheet">
    <link href="http://www.primefaces.org/css/all.css" rel="stylesheet">
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
    <script type="text/javascript" src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
    <script type="text/javascript" src="development/prime-ui-1.0.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
    <script type="text/javascript">
    $(function() {
        var localData = [
            {'brand': 'Volkswagen', 'year': 2012, 'color': 'White', 'vin': 'dsad231ff'},
            {'brand': 'Audi', 'year': 2011, 'color': 'Black', 'vin': 'gwregre345'},
            {'brand': 'Renault', 'year': 2005, 'color': 'Gray', 'vin': 'h354htr'},
            {'brand': 'BMW', 'year': 2003, 'color': 'Blue', 'vin': 'j6w54qgh'},
            {'brand': 'Mercedes', 'year': 1995, 'color': 'White', 'vin': 'hrtwy34'},
            {'brand': 'Volvo', 'year': 2005, 'color': 'Black', 'vin': 'jejtyj'},
            {'brand': 'Honda', 'year': 2012, 'color': 'Yellow', 'vin': 'g43gr'},
            {'brand': 'Jaguar', 'year': 2013, 'color': 'White', 'vin': 'greg34'},
            {'brand': 'Ford', 'year': 2000, 'color': 'Black', 'vin': 'h54hw5'},
            {'brand': 'Fiat', 'year': 2013, 'color': 'Red', 'vin': '245t2s'}
        ];
 
        $('#tbllocal').puidatatable({
            caption: 'Local Datasource',
            columns: [
                {field: 'vin', headerText: 'Vin'},
                {field: 'brand', headerText: 'Brand'},
                {field: 'year', headerText: 'Year'},
                {field: 'color', headerText: 'Color'}
            ],
            datasource: localData
        });
 
         
    });
</script>
  </head>
<body>
  <div id="tbllocal"></div>
 
 
</body>
</html>

As you can see, at the top of our HTML page, we are loading the required jquery, angular and primeui javascript and css. In order to display the datatable into the div named “tbllocal” we have to link the datasource object with a static/remote list of items. In this example, the JSON-like structure has been defined into the variable localData.

JSF Drag and Drop with Primefaces

 In this tutorial we will learn how to perform Drag & Drop in your JSF applications using PrimeFaces library.

Drag & Drop with PrimeFaces

Drag-and-drop is an action, meaning grabbing an object and dragging it to a different location. Components capable of being dragged and dropped enrich the Web and make a solid base for modern UI patterns. The drag-and-drop utilities in PrimeFaces allow us to create draggable and droppable user interfaces efficiently. They make it abstract for developers to deal with the implementation details on a browser level.
In this tutorial, we will learn about PrimeFaces’ drag-and-drop utilities: Draggable and Droppable. AJAX-enhanced drag-and-drop and a special integration with data iteration components will be explained as well.

A component can be made draggable by using p:draggable. The component ID must match the for attribute of the p:draggable component. If the for attribute is omitted, the parent component will be selected as a draggable target. Let’s make some panel components draggable and apply some basic features:

    <p:panel id="pnl" header="Draggable panel with default settings">
            <h:outputText value="Drag me around" />
        </p:panel>
        <p:draggable for="pnl" />
        <p:panel id="hpnl" header="Draggable panel by handle">
            <h:outputText value="I can be only dragged by my header" />
        </p:panel>
        <p:draggable for="hpnl" handle=".ui-panel-titlebar" />
        <p:panel id="cpnl" header="Draggable panel with clone">
            <h:outputText
                value="I display a clone as helper while being dragged" />
        </p:panel>
        <p:draggable for="cpnl" helper="clone" />
        <p:panel id="rpnl" header="Draggable panel with revert">
            <h:outputText
                value="I will be returned to my start position when dragging stops" />
        </p:panel>
        <p:draggable for="rpnl" revert="true" />
        <p:panel id="opnl" header="Draggable panel with opacity">
            <h:outputText value="I use opacity for helper while being dragged" />
        </p:panel>
        <p:draggable for="opnl" opacity="0.5" />

        
The following screenshot shows the five panels. The last panel is being dragged. Its opacity has been changed to 0.5 after dragging starts.

How it works

By default, any point in a dragged component can be used as a handle. To restrict the drag-start click to a specified element(s), we can use the handle option, which is a jQuery selector. The second panel is dragged by using its header only.
By default, the actual component is used as a drag indicator. The helper option allows keeping the component at its original location during dragging. This can be achieved with helper set to clone as for the third panel.
If the revert option is set to true, the component will return to its starting position when dragging stops and the draggable component is not dropped onto a matching droppable component. The fourth panel features this behavior.
Opacity for helper while it is being dragged is another useful option to give the user a visual feedback. The opacity of the fifth panel is reduced when dragging.

Defining droppable targets

Any component can be enhanced with a droppable behaviour. Droppable components are targets for draggable ones. To enable droppable functionality on any PrimeFaces component, we always need a component called Droppable. In this recipe, we will see how to defi ne droppable targets and learn a client-side callback onDrop.

How to do it

A component can be made droppable by using p:droppable. The component ID must match the for attribute of p:droppable. If the for attribute is omitted, the parent component will be selected as a droppable target. We will take two h:panelGroup components and make them droppable and draggable respectively. In addition, we will define a client-side callback that gets invoked when a draggable component is dropped. This can be accomplished by the onDrop attribute, which points to a JavaScript function.

    <h:panelGroup id="drop" layout="block" styleClass="ui-widget-content"
        style="height:150px;width:300px;">
        <p class="ui-widget-header" style="margin: 0; padding: 5px;">Drop
            here</p>
        <p:droppable onDrop="handleDrop" />
    </h:panelGroup>
    <br />
    <h:panelGroup id="drag" layout="block"
        style="height:150px;width:300px;">
        <p>Drag me to my target</p>
    </h:panelGroup>
    <p:draggable for="drag" />

    
The client-side callback highlights the droppable h:panelGroup component and adds the text Dropped! to the paragraph tag p when invoked.

<script>
function handleDrop(event, ui) {
$(event.target).addClass("ui-state-highlight").find("p").html("Dropped!");
}
</script>

Before……

……After

How it works

The onDrop callback gets two parameters: event and ui, which are objects holding information about the drag-and-drop event. The droppable target is accessible by event.We use this fact to add the style class ui-state-highlight to the target. This class is defined by jQuery ThemeRoller. The event parameter is the original browser event, and ui is a prepared object with the following properties:

  • ui.draggable: This is the current draggable element,an jQuery object
  • ui.helper: This is the current draggable helper,an jQuery object
  • ui.position: This is the current position of the draggable helper { top: , left: }
  • ui.offset: This is the current absolute position of the draggable helper { top: , left: }

Using Drag and Drop with PrimeFaces File Upload

Some components like the <p:fileUpload /> are natively able to perform Drag and Drop. For example, in order to allow Drag and Drop in your Forms, simply set the dragDropSupport attribute to “true” as in the following example:

<h:form>
    <p:fileUpload fileUploadListener="#{fileUploadView.handleFileUpload}" mode="advanced" dragDropSupport="true"
                          update="messages" sizeLimit="100000" allowTypes="/(\.|\/)(gif|jpe?g|png)$/" />
 
    <p:growl id="messages" showDetail="true" />
</h:form>

 The Backing Bean FileUploadView is needed to provide messages notification to the FacesContext:

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.context.FacesContext;
 
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.UploadedFile;
 
@ManagedBean
public class FileUploadView {
 
    public void handleFileUpload(FileUploadEvent event) {
        FacesMessage message = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
        FacesContext.getCurrentInstance().addMessage(null, message);
    }
}

Using Drag and Drop with PrimeFaces Datatable

As you can see from Primefaces showcase, using Drag & Drop with PrimeFaces datatable is quite straightforward. The javascript callback function handleDrop will provide the animation effect to be applied when the component is dropped. Also, one of the columns (the one containing the dragIcon) has the <p:draggable> element which means you can drag it. Where can it be dropped ? In a corresponding <p:droppable />

<script type="text/javascript">
    function handleDrop(event, ui) {
        var droppedCar = ui.draggable; 
        droppedCar.fadeOut('fast');
    }
</script>
 
<h:form id="carForm">
    <p:fieldset id="availableCarsField" legend="Available Cars">
        <p:dataTable id="availableCars" var="car" value="#{dndCarsView.cars}">
            <p:column style="width:20px">
                <h:outputText id="dragIcon" styleClass="ui-icon ui-icon-arrow-4" />
                <p:draggable for="dragIcon" revert="true" helper="clone"/>
            </p:column>
 
            <p:column headerText="Id">
                <h:outputText value="#{car.id}" />
            </p:column>
 
            <p:column headerText="Year">
                <h:outputText value="#{car.year}" />
            </p:column>
 
            <p:column headerText="Brand">
                <h:outputText value="#{car.brand}" />
            </p:column>
 
            <p:column headerText="Color">
                <h:outputText value="#{car.color}" />
            </p:column>
        </p:dataTable>
    </p:fieldset>
 
    <p:fieldset id="selectedCars" legend="Selected Cars" style="margin-top:20px">
        <p:outputPanel id="dropArea">
            <h:outputText value="!!!Drop here!!!" rendered="#{empty dndCarsView.droppedCars}" style="font-size:24px;" />
            <p:dataTable id="selectedCarsTable" var="car" value="#{dndCarsView.droppedCars}" rendered="#{not empty dndCarsView.droppedCars}">
                <p:column headerText="Id">
                    <h:outputText value="#{car.id}" />
                </p:column>
 
                <p:column headerText="Year">
                    <h:outputText value="#{car.year}" />
                </p:column>
 
                <p:column headerText="Brand">
                    <h:outputText value="#{car.brand}" />
                </p:column>
 
                <p:column headerText="Color">
                    <h:outputText value="#{car.color}" />
                </p:column>
 
            </p:dataTable>
        </p:outputPanel>
    </p:fieldset>
 
    <p:droppable for="selectedCars" tolerance="touch" activeStyleClass="ui-state-highlight" datasource="availableCars" onDrop="handleDrop">
        <p:ajax listener="#{dndCarsView.onCarDrop}" update="dropArea availableCars" />
    </p:droppable>
 
</h:form>

As you can see, in order to handle the clone of the dndCarsView List, another List has been added to the dndCarsView called droppedCars. Each time a Drop Event occurs, the onCarDrop method receives a callback where the Car object is added into the  List<Car> droppedCars:

public class DNDCarsView implements Serializable {
  
    @ManagedProperty("#{carService}")
    private CarService service;
 
    private List<Car> cars;
     
    private List<Car> droppedCars;
     
    private Car selectedCar;
     
    @PostConstruct
    public void init() {
        cars = service.createCars(9);
        droppedCars = new ArrayList<Car>();
    }
     
    public void onCarDrop(DragDropEvent ddEvent) {
        Car car = ((Car) ddEvent.getData());
  
        droppedCars.add(car);
        cars.remove(car);
    }
     
    public void setService(CarService service) {
        this.service = service;
    }
 
    public List<Car> getCars() {
        return cars;
    }
 
    public List<Car> getDroppedCars() {
        return droppedCars;
    }    
 
    public Car getSelectedCar() {
        return selectedCar;
    }
 
    public void setSelectedCar(Car selectedCar) {
        this.selectedCar = selectedCar;
    }
}

Creating a DataScroller with Primefaces

In this tutorial you will learn how to use a Primefaces DataScroller to let your application load additional set of Data as you scroll down the Web page (on Demand scrolling). This component is available since Primefaces 5.

The structure of the component dataScroller is quite similar to a dataTable. The key attribute of it is the chunkSize by which you can control the amount of items that will be loaded and displayed at once. Here follows an example which displays the World’s country list in chunks:

<!DOCTYPE html>
<html xmlns="http://www.w3c.org/1999/xhtml"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui">
<h:head></h:head>
<h:body>
 
    
<h:form> 
    <p:dataScroller value="#{dataScrollerView.countries}" var="c" chunkSize="10">
        <f:facet name="header">
            Data Scroller Demo
        </f:facet>
 
        <h:panelGrid columns="2" style="width:100%" columnClasses="logo,detail">
             
            <p:outputPanel>
                <h:panelGrid columns="2" cellpadding="5">
                    <h:outputText value="Country code:" />
                    <h:outputText value="#{c.code}" style="font-weight: bold"/>
 
                    <h:outputText value="Name:" />
                    <h:outputText value="#{c.name}" style="font-weight: bold"/>
                </h:panelGrid>
            </p:outputPanel>
        </h:panelGrid>
    </p:dataScroller>
</h:form>
</h:body>
</html>

In order to work you will need a DataScrollerView to hold the list of Country objects:

package com.mastertheboss.bean;
 
import java.io.Serializable;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;

import com.mastertheboss.model.Country;
import com.mastertheboss.service.CountryService;
 
 
@ManagedBean
@ViewScoped
public class DataScrollerView implements Serializable {
     
    private List<Country> countries;
         
    @ManagedProperty("#{countryService}")
    private CountryService service;
     
    @PostConstruct
    public void init() {
    	countries = service.createCountries();
    }
 
    public List<Country> getCountries() {
        return countries;
    }
 
    public void setService(CountryService service) {
        this.service = service;
    }
}

The Country class is a simple Java Bean with some properties in it:

package com.mastertheboss.model;

import java.io.Serializable;

public class Country implements Serializable {
	private String code;
	private String name;

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public String getName() {
		return name;
	}

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

	public Country() {
	}

}

Finally, the CountryService populates the List of Country using as source the JDK’s Locale getISOCountries:

package com.mastertheboss.service;
 
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.ManagedBean;

import com.mastertheboss.model.Country;
 
 
@ManagedBean(name = "countryService")
@ApplicationScoped
public class CountryService {

     
    public List<Country> createCountries() {
    	
    	String[] locales = Locale.getISOCountries();
    	List<Country> list = new ArrayList<Country>();
    	
    	for (String countryCode : locales) {

    		Locale obj = new Locale("", countryCode);
    		Country c = new Country();
    		c.setCode( obj.getCountry());
    		c.setName(obj.getDisplayCountry());
    		 
    		list.add(c);

    	}
    	        
        return list;
    }
       
}

Here is your DataScroller view in action:

Looking for other ways to display your large set of data ? Then check this article where we show how to enable live scrolling on a dataTable in order to lazy load its content

Dynamic PrimeFaces detail forms

In my last post – Dynamic PrimeFaces Datatables –     I have explained how to use Java Reflection to dynamically generate PrimeFaces DataTables. In this article we are going to use the same technique to create dynamic detail forms.

In our following examples we will use the DynaForm component of the PrimeFacex Extensions project. As you can see from the showcase example, this component it€s useful when we have a dynamically described form.

We€re are going to create detail forms for the following POJO classes:

public class User implements Serializable{

	private static final long serialVersionUID = 1L;
	private static List<User> users = new ArrayList<User>();

	private Integer id;

	private String lastName;
	private String firstName;

	static{

		users.add(new User(0, "Solid","Snake"));
		users.add(new User(1, "Vulcan","Raven"));
		users.add(new User(2, "Meryl","Silverburgh"));
		users.add(new User(3, "Hal","Emmerich"));
		users.add(new User(4, "Frank","Jaeger"));
	}

	public User(Integer id, String firstName, String lastName) {

		super();
		this.id = id;
		this.lastName = lastName;
		this.firstName = firstName;

	}

	public User() {}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

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

	public String getLastName() {
		return lastName;
	}

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

	public static List<User> getAll(){
		return users;
	}

	public static User get(final Integer id){

		return (User) CollectionUtils.find(users, new Predicate() {

			public boolean evaluate(Object object) {

				return ((User) object).getId().equals(id);

			}

		});

	}

	public static User store(User p){

		if(p.getId() == null){

			User maxUserId = Collections.max(users, new Comparator<User>() {

				public int compare(User o1, User o2) {
					return o1.getId().compareTo(o2.getId());
				}

			});

			p.setId(maxUserId.getId()+1);
			users.add(p);

		}else{
			users.set(p.getId(), p);
		}
		return p;
	}

	public static void delete(User p){
		users.remove(p);
	}

}

And here is the Car POJO Class:

public class Car implements Serializable{

	private static final long serialVersionUID = 1L;

	private static List<Car> cars = new ArrayList<Car>();

	private Integer id;
	private String brand;
	private String color;
	private Integer year;
	private String notes;
	private boolean used;
	
	static{
		cars.add(new Car(0, "Honda","Yellow",1995,false,"Broken Brakes"));
		cars.add(new Car(1, "Volvo","Black",1973,true));
		cars.add(new Car(1, "Audi","Silver",1987,false));
		cars.add(new Car(1, "Renault","White",1963,true));
		cars.add(new Car(1, "Volkswagen","Black",1985,true));
	}	

	public Car(Integer id, String brand, String color, Integer year, boolean used,String notes) {
		super();
		this.id = id;
		this.brand = brand;
		this.color = color;
		this.year = year;
		this.used = used;
		this.notes = notes;
	}
	
	public Car(Integer id, String brand, String color, Integer year, boolean used) {
		this(id,brand,color,year,used,"");
	}
	
	public Car() {}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public Integer getYear() {
		return year;
	}

	public void setYear(Integer year) {
		this.year = year;
	}

	public boolean isUsed() {
		return used;
	}

	public void setUsed(boolean used) {
		this.used = used;
	}

	public String getNotes() {
		return notes;
	}

	public void setNotes(String notes) {
		this.notes = notes;
	}

	public static List<Car> getAll(){
		return cars;

	}

	public static Car get(final Integer id){
		return (Car) CollectionUtils.find(cars, new Predicate() {
			public boolean evaluate(Object object) {
				return ((Car) object).getId().equals(id);
			}
		});
	}

	public static Car store(Car p){
		if(p.getId() == null){
			Car maxUserId = Collections.max(cars, new Comparator<Car>() {
				public int compare(Car o1, Car o2) {
					return o1.getId().compareTo(o2.getId());
				}
			});
			
			p.setId(maxUserId.getId()+1);
			
			cars.add(p);
		}else{
			cars.set(p.getId(), p);
		}

		return p;
	}

	public static void delete(Car p){
		cars.remove(p);
	}
}

To use a DynaForm we need to create a DynaFormModel. This object will contain an instance of DynaFormRow for every accessible property of our POJO. We will automatically generate the rows using the property descriptors of the class, just like in the last post. In order to achieve this goal we will use this builder:

public class ReflectionDynaFormModelBuilder {
	
	private Class modelClass;
	private Comparator<PropertyDescriptor> propertySortComparator;
	private Predicate propertyFilterPredicate;
	private Set<String> excludedProperties;
	private static Set<String> defaultExcludedProperties = new HashSet<String>(0);
	private Map<String,FormControlBuilder> customBuilders = new HashMap<String, FormControlBuilder>();
	public static Comparator<PropertyDescriptor> DEFAULT_PROPERTY_COMPARATOR = new Comparator<PropertyDescriptor>() {
		public int compare(PropertyDescriptor o1, PropertyDescriptor o2) {
			return o1.getName().compareTo(o2.getName());
		}
	};
	
	static{
		defaultExcludedProperties.add("class");
	}
	
	public ReflectionDynaFormModelBuilder(Class modelClass) {
		this.modelClass = modelClass;
		this.propertyFilterPredicate = PredicateUtils.truePredicate();
		this.propertySortComparator = DEFAULT_PROPERTY_COMPARATOR;
		this.excludedProperties = new HashSet<String>(0);
	}
	
	public ReflectionDynaFormModelBuilder setPropertyFilterPredicate(Predicate p){
		this.propertyFilterPredicate = p;
		return this;
	}
	
	public ReflectionDynaFormModelBuilder setPropertySortComparator(Comparator<PropertyDescriptor> c){
		this.propertySortComparator = c;
		return this;
	}
	
	public ReflectionDynaFormModelBuilder setExcludedProperties(Set<String> p){
		this.excludedProperties = p;
		return this;
	}
	
	public ReflectionDynaFormModelBuilder putCustomBuilder(String name,FormControlBuilder builder){
		this.customBuilders.put(name, builder);
		return this;
	}
	
	public ReflectionDynaFormModelBuilder putCustomBuilders(Map<String,FormControlBuilder> builders){
		this.customBuilders.putAll(builders);
		return this;
	}
	
	public ReflectionDynaFormModelBuilder setExcludedProperties(String...p){
		this.excludedProperties = new HashSet<String>(0);
		for (String excludedProperty : p) {
			this.excludedProperties.add(excludedProperty);
		}
		return this;
	}
	
	public DynaFormModel build(){
		DynaFormModel formModel = new DynaFormModel();
		
		List<PropertyDescriptor> propertyDescriptors = new ArrayList<PropertyDescriptor>(Arrays.asList(PropertyUtils.getPropertyDescriptors(modelClass)));
		
		CollectionUtils.filter(propertyDescriptors, PredicateUtils.andPredicate(propertyFilterPredicate, new Predicate() {
			public boolean evaluate(Object object) {
				PropertyDescriptor propertyDescriptor = (PropertyDescriptor) object;
				return 
						propertyDescriptor.getReadMethod() != null && 
						propertyDescriptor.getWriteMethod() != null &&
						!defaultExcludedProperties.contains(propertyDescriptor.getName()) &&
						!excludedProperties.contains(propertyDescriptor.getName());
			}
		}));
		
		Collections.sort(propertyDescriptors, propertySortComparator);
		
		for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
			DynaFormRow row = formModel.createRegularRow();  
			if(customBuilders.containsKey(propertyDescriptor.getName())){
				customBuilders.get(propertyDescriptor.getName()).populateRow(row);
			}else{
				//Default Row
				DynaFormLabel label = row.addLabel(propertyDescriptor.getName());
		        DynaFormControl input = row.addControl(new DynaPropertyModel(propertyDescriptor.getName()), propertyDescriptor.getPropertyType().getSimpleName().toLowerCase());  
		        label.setForControl(input);
			} 
		}
		
		return formModel;
	}
}

As you can see, for every readable property we generate a DynaFormRow, a DynaFormLabel and, most importantly, a DynaFormControl. We also generate a DynaPropertyModel, this object will contain all the metadata of the property, for now it will simply contains the name of the property itself.

public class DynaPropertyModel implements Serializable{
    
	private static final long serialVersionUID = 1L;
	
	private String name;
    
    public DynaPropertyModel() {}
    
    public DynaPropertyModel(String name) {
		super();
		this.name = name;
	}
    
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

Basic Example

Using this builder is quite simple, as we can see in the next example:

Managed Bean

@ManagedBean
@ViewScoped
public class BasicDetailExampleBean implements Serializable{
	
	private static final long serialVersionUID = 1L;
	
	private Object model;
	private Class currentClass;
	private String currentClassName;
	private Integer id;
	private Boolean disabled = false;
	private DynaFormModel formModel;
	
	public final void onPreRender(){
		try {
			currentClass = Class.forName(currentClassName);
			this.formModel = new ReflectionDynaFormModelBuilder(currentClass)
				.setExcludedProperties("id")
				.setPropertySortComparator(getPropertyComparator())
				.putCustomBuilders(getCustomBuilders())
				.build();
			if(id != null){
				this.model = MethodUtils.invokeExactStaticMethod(currentClass, "get", new Object[]{id});
			}else{
				this.model = currentClass.newInstance();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	protected Comparator<PropertyDescriptor> getPropertyComparator() {
		return ReflectionDynaFormModelBuilder.DEFAULT_PROPERTY_COMPARATOR;
	}

	protected Map<String, FormControlBuilder> getCustomBuilders() {
		//No Custom
		return new HashMap<String, FormControlBuilder>(0);
	}

	public final String save(){
		try {
			MethodUtils.invokeExactStaticMethod(currentClass, "store", new Object[]{this.model});
			return "param.xhtml?class=" + currentClassName + "&faces-redirect=true";
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public String getCurrentClassName() {
		return currentClassName;
	}

	public void setCurrentClassName(String currentClass) {
		this.currentClassName = currentClass;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public Boolean getDisabled() {
		return disabled;
	}

	public void setDisabled(Boolean disabled) {
		this.disabled = disabled;
	}

	public Object getModel() {
		return model;
	}

	public DynaFormModel getFormModel() {
		return formModel;
	}
}

And the XHTML Page

<f:metadata>
	<f:viewParam name="class" value="#{basicDetailExampleBean.currentClassName}"></f:viewParam>
	<f:viewParam name="id" value="#{basicDetailExampleBean.id}" converter="javax.faces.Integer"></f:viewParam>
	<f:viewParam name="disabled" value="#{basicDetailExampleBean.disabled}" converter="javax.faces.Boolean"></f:viewParam>
	<f:event listener="#{basicDetailExampleBean.onPreRender}" type="preRenderView"></f:event>
</f:metadata>
<h:body>
	<h:form>
		<p:messages id="messages" showSummary="true"/>
		
	    <pe:dynaForm id="dynaForm" value="#{basicDetailExampleBean.formModel}" var="data">
	        <pe:dynaFormControl type="string" for="txt">
	        	<p:inputText 
	        		id="txt" 
	        		value="#{basicDetailExampleBean.model[data.name]}"
	        		disabled="#{basicDetailExampleBean.disabled}"/>
	        </pe:dynaFormControl>
	        <pe:dynaFormControl type="boolean" for="boolean">
	           	<p:selectBooleanCheckbox 
	           		id="boolean" 
	           		value="#{basicDetailExampleBean.model[data.name]}"
	           		disabled="#{basicDetailExampleBean.disabled}"/>
	        </pe:dynaFormControl>
	        <pe:dynaFormControl type="integer" for="integer">
	           	<p:inputText 
	           		id="integer" 
	           		value="#{basicDetailExampleBean.model[data.name]}" 
	           		converter="javax.faces.Integer"
	           		disabled="#{basicDetailExampleBean.disabled}"/>
	        </pe:dynaFormControl>
	    </pe:dynaForm>
	    
	    <p:commandButton
	    	process="@form"
	    	value="Save" 
	    	disabled="#{basicDetailExampleBean.disabled}"
	    	action="#{basicDetailExampleBean.save}"/>
    </h:form>
</h:body>
</html>

What we just obtained it€s a dynamic form, we just need to change the €˜class€ and €˜id€ view param to change class and model to edit/view.

Datatable Integration

All the parameters in the detail form are passed via view paramters. So it€s extremely simple to integrate our new detail form with the dynamic datatable from previous post.

<f:metadata>
	<f:viewParam name="class" value="#{viewParamExampleBean.currentClass}"></f:viewParam>
	<f:event listener="#{viewParamExampleBean.onPreRender}" type="preRenderView"></f:event>
</f:metadata>
<h:body>
	<h:outputLink 
		value="basicDetail.xhtml?faces-redirect=true">
			Create
			<f:param name="class" value="#{viewParamExampleBean.currentClass}"/>
	</h:outputLink>
	<p:dataTable var="obj" value="#{viewParamExampleBean.data}">
		<p:column>
			<h:outputLink 
				value="basicDetail.xhtml?faces-redirect=true">
					Edit
					<f:param name="id" value="#{obj.id}"/>
					<f:param name="class" value="#{viewParamExampleBean.currentClass}"/>
			</h:outputLink>
		</p:column>
		<p:column>
			<h:outputLink 
				value="basicDetail.xhtml?faces-redirect=true">
					View
					<f:param name="id" value="#{obj.id}"/>
					<f:param name="disabled" value="true"/>
					<f:param name="class" value="#{viewParamExampleBean.currentClass}"/>
			</h:outputLink>
		</p:column>
		<p:columns 
			value="#{viewParamExampleBean.columns}" 
			var="column"
			headerText="#{column.header}">
			<p:selectBooleanCheckbox 
				value="#{obj[column.property]}" 
				disabled="true"
				rendered="#{column.type.toString() == 'boolean'}"/>
			<h:outputText value="#{obj[column.property]}" rendered="#{column.type.toString() != 'boolean'}" />
		</p:columns>
	</p:dataTable>
</h:body>
</html>

As you can see with just two managed beans we can manage every POJO class of a simple project.

Advanced Usage

In the Car class, we have a €˜notes€ field. If we want a better user experience we need to use a p:inputTextArea in place of the standard p:inputText. And propably the €˜notes€ field should be the last input in the form. We can force the behaviour of our ReflectionDynaFormModelBuilder, changing the DynaFormRow for a specific field or changing the order or the fields.

@ManagedBean
@ViewScoped
public class AdvancedDetailExampleBean extends BasicDetailExampleBean{
	
	private static final String NOTES_FIELD = "notes";
	private static final long serialVersionUID = 1L;
	
	@Override
	protected Comparator<PropertyDescriptor> getPropertyComparator() {
		return new Comparator<PropertyDescriptor>() {
			public int compare(PropertyDescriptor first, PropertyDescriptor second) {
				if(NOTES_FIELD.equals(first.getName())){
					return 1;
				}else if(NOTES_FIELD.equals(second.getName())){
					return -1;
				}else{
					return ReflectionDynaFormModelBuilder.DEFAULT_PROPERTY_COMPARATOR.compare(first, second);
				}
			}
		};
	}
	
	@Override
	protected Map<String, FormControlBuilder> getCustomBuilders() {
		Map<String, FormControlBuilder> toReturn = new HashMap<String, FormControlBuilder>(0);
		toReturn.put(NOTES_FIELD, new FormControlBuilder() {
			public void populateRow(DynaFormRow row) {
				//We will show notes in a textArea
				DynaFormLabel label = row.addLabel(NOTES_FIELD);
		        DynaFormControl input = row.addControl(new DynaPropertyModel(NOTES_FIELD), "text");  
		        label.setForControl(input);
			}
		});
		return toReturn;
	}
}

In this new managed bean we changed the type of the notes filed from €˜string€ to €˜text€ (to show a textArea). The default behaviour is to use the simple name of the class of the property for choosing the input component. We can also add a Dependency Injection framework like Spring or Google Guice in our application, to avoid the creation of the second bean.

Conclusions

Thanks to the reflection, with just a bunch of classes we can manage a full CRUD application. Obviously the code that you just analyzed it’s not ready for production. In the next releases of this small  Prototyping Framework I will try to obtain the field attributes (like required,size,maxlength) from the javax.validation annotations. Another possible feature could be some kind of COC implementation: for example every €˜notes€ field should be the last field with a textArea component.

If you want to contribute just fork the repository of the project! Enjoy!

Dynamic PrimeFaces Datatables

In this post I will explain how to use Java Reflection to extract PrimeFaces models from POJO classes. Specifically we will create a dynamic DataTable using the p:columns component. 

Setup

Using reflection could be quite tediuos, luckily for us theres the Apache Commons BeanUtils API. This library helps us to dynamically read the properties of our POJOs. To use this API we just need to add the dependency to our pom.xml in this way.

<dependency>
	<groupId>commons-beanutils</groupId>
        <artifactId>commons-beanutils</artifactId>
	<version>1.9.2</version>
</dependency>

The ColumnModel Class

We are going to use this POJO class for the first example. As you will notice the class its a quite simple (and useless) implementation of the Active Record pattern.

public class User implements Serializable{

	private static final long serialVersionUID = 1L;

	private static List<User> users = new ArrayList<User>();

	private Integer id;
	private String lastName;
	private String firstName;
	
	static{
		users.add(new User(0, "Solid","Snake"));
		users.add(new User(1, "Vulcan","Raven"));
		users.add(new User(2, "Meryl","Silverburgh"));
		users.add(new User(3, "Hal","Emmerich"));
		users.add(new User(4, "Frank","Jaeger"));
	}

	public User(Integer id, String firstName, String lastName) {
		super();
		this.id = id;
		this.lastName = lastName;
		this.firstName = firstName;
	}

	public User() {}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

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

	public String getLastName() {
		return lastName;
	}

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

	public static List<User> getAll(){
		return users;

	}

	public static User get(final Integer id){
		return (User) CollectionUtils.find(users, new Predicate() {
			public boolean evaluate(Object object) {
				return ((User) object).getId().equals(id);
			}
		});
	}

	public static User store(User p){
		if(p.getId() == null){
			User maxUserId = Collections.max(users, new Comparator<User>() {
				public int compare(User o1, User o2) {
					return o1.getId().compareTo(o2.getId());
				}
			});
			
			p.setId(maxUserId.getId()+1);
			
			users.add(p);
		}else{
			users.set(p.getId(), p);
		}

		return p;
	}

	public static void delete(User p){
		users.remove(p);
	}
}

What we have to do now is to dynamically create the columns ˜idfirstName and ˜lastName, in order to do that we will use this class: the ColumnModel.

public class ColumnModel implements Serializable {

	private static final long serialVersionUID = 1L;

	private String property;
	private String header;
	private Class<?> type;
	public ColumnModel() {}

	public String getProperty() {
		return property;
	}

	public void setProperty(String property) {
		this.property = property;
	}
	public String getHeader() {
		return header;
	}
	public void setHeader(String header) {
		this.header = header;
	}
	public Class<?> getType() {
		return type;
	}

	public void setType(Class<?> type) {
		this.type = type;
	}

}

This class is just a POJO itself, that holds the data about the tille, header and type of a PrimeFaces column. We need to create a ColumnModel instance for every property of the User class. To achieve this goal I implemented this ReflectionColumnModelBuilder object.

public class ReflectionColumnModelBuilder {
	
	private Class modelClass;

	private Comparator<PropertyDescriptor> propertySortComparator;
	private Predicate propertyFilterPredicate;
	private Set<String> excludedProperties;

	private static Set<String> defaultExcludedProperties = new HashSet<String>(0);
	
	static{
		defaultExcludedProperties.add("class");
	}
	
	public ReflectionColumnModelBuilder(Class modelClass) {

		this.modelClass = modelClass;
		this.propertyFilterPredicate = PredicateUtils.truePredicate();
		this.propertySortComparator = new Comparator<PropertyDescriptor>() {

			public int compare(PropertyDescriptor o1, PropertyDescriptor o2) {

				return o1.getName().compareTo(o2.getName());

			}

		};

		this.excludedProperties = new HashSet<String>(0);

	}

	public ReflectionColumnModelBuilder setPropertyFilterPredicate(Predicate p){

		this.propertyFilterPredicate = p;
		return this;

	}

	public ReflectionColumnModelBuilder setPropertySortComparator(Comparator<PropertyDescriptor> c){

		this.propertySortComparator = c;
		return this;

	}

	public ReflectionColumnModelBuilder setExcludedProperties(Set<String> p){

		this.excludedProperties = p;
		return this;

	}
	public ReflectionColumnModelBuilder setExcludedProperties(String...p){

		this.excludedProperties = new HashSet<String>(0);

		for (String excludedProperty : p) {
			this.excludedProperties.add(excludedProperty);
		}

		return this;
	}

	public List<ColumnModel> build(){

		List<ColumnModel> columns = new ArrayList<ColumnModel>(0);

		List<PropertyDescriptor> propertyDescriptors = new ArrayList<PropertyDescriptor>(Arrays.asList(PropertyUtils.getPropertyDescriptors(modelClass)));

		CollectionUtils.filter(propertyDescriptors, PredicateUtils.andPredicate(propertyFilterPredicate, new Predicate() {

			public boolean evaluate(Object object) {

				PropertyDescriptor propertyDescriptor = (PropertyDescriptor) object;

				return 

						propertyDescriptor.getReadMethod() != null && 

						!defaultExcludedProperties.contains(propertyDescriptor.getName()) &&

						!excludedProperties.contains(propertyDescriptor.getName());

			}

		}));
	

		Collections.sort(propertyDescriptors, propertySortComparator);

		for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {

			ColumnModel columnDescriptor = new ColumnModel();

			columnDescriptor.setProperty(propertyDescriptor.getName());

			columnDescriptor.setHeader(StringUtils.capitalize(StringUtils.join(StringUtils.splitByCharacterTypeCamelCase(propertyDescriptor.getName())," ")));

			columnDescriptor.setType(propertyDescriptor.getPropertyType());

			columns.add(columnDescriptor);

		}

		return columns;

	}

}

Lets focus on the build method. We use the instruction PropertyUtils.getPropertyDescriptors(modelClass) to get all the PropertyDescriptor of the POJO class. 

The Javadoc of the PropertyDescriptor class states that this object describes one property that a Java Bean exports via a pair of accessor methods. We sort and filter our descriptors and then we wrap everything in a collection of ColumnModel objects.

A First Example

The Page 

<p:dataTable var="user" value="#{basicExampleBean.users}">

   <p:columns value="#{basicExampleBean.columns}" 
                      var="column" headerText="#{column.header}">

      <h:outputText value="#{user[column.property]}" />

   </p:columns>

</p:dataTable>

The Bean

@ManagedBean
@ViewScoped

public class BasicExampleBean implements Serializable{

private List<ColumnModel> columns = new ArrayList<ColumnModel>(0);

   @PostConstruct
   public void init() {

      columns = new ReflectionColumnModelBuilder(User.class).
                          setExcludedProperties("id").build();

   }

   public List<User> getUsers(){

      return User.getAll();

   }

   public List<ColumnModel> getColumns() {

      return columns;

   }

}

As we can see in the example, to create the columns that only thing that is required is to pass the User class to the builder. Note that we also excluded the id column. The result of the example is this:

 

Ajax

We can also change class with an Ajax event, lets create a second POJO: a Car model.

public class Car implements Serializable{

	private static final long serialVersionUID = 1L;

	private static List<Car> cars = new ArrayList<Car>();

	private Integer id;
	private String brand;
	private String color;
	private Integer year;
	private boolean used;
	
	static{
		cars.add(new Car(0, "Honda","Yellow",1995,false));
		cars.add(new Car(1, "Volvo","Black",1973,true));
		cars.add(new Car(1, "Audi","Silver",1987,false));
		cars.add(new Car(1, "Renault","White",1963,true));
		cars.add(new Car(1, "Volkswagen","Black",1985,true));
	}	

	public Car(Integer id, String brand, String color, Integer year, boolean used) {
		super();
		this.id = id;
		this.brand = brand;
		this.color = color;
		this.year = year;
		this.used = used;
	}

	public Car() {}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getColor() {
		return color;
	}

	public void setColor(String color) {
		this.color = color;
	}

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public Integer getYear() {
		return year;
	}

	public void setYear(Integer year) {
		this.year = year;
	}

	public boolean isUsed() {
		return used;
	}

	public void setUsed(boolean used) {
		this.used = used;
	}

	public static List<Car> getAll(){
		return cars;

	}

	public static Car get(final Integer id){
		return (Car) CollectionUtils.find(cars, new Predicate() {
			public boolean evaluate(Object object) {
				return ((Car) object).getId().equals(id);
			}
		});
	}

	public static Car store(Car p){
		if(p.getId() == null){
			Car maxUserId = Collections.max(cars, new Comparator<Car>() {
				public int compare(Car o1, Car o2) {
					return o1.getId().compareTo(o2.getId());
				}
			});
			
			p.setId(maxUserId.getId()+1);
			
			cars.add(p);
		}else{
			cars.set(p.getId(), p);
		}

		return p;
	}

	public static void delete(Car p){
		cars.remove(p);
	}
}

Note that this class has a boolean value: we are going to use the type property of the ColumnModel object to display a p:selectBooleanCheckbox instead of the classic h:outputText. We use a p:selectOneRadio to switch between the two classes.

The Page

<h:form>

<h:panelGrid columns="2" style="margin-bottom:10px" cellpadding="5">

       <p:outputLabel for="currentClass" value="Class:" />

       <p:selectOneRadio id="currentClass" value="#{dynamicExampleBean.currentClass}">

           <f:selectItem itemLabel="User" itemValue="it.strazz.primefaces.model.User" />

           <f:selectItem itemLabel="Car" itemValue="it.strazz.primefaces.model.Car" />

           <p:ajax listener="#{dynamicExampleBean.onChangeClass}" update="@form"/>

       </p:selectOneRadio>

   </h:panelGrid>

<p:dataTable var="obj" value="#{dynamicExampleBean.data}">

   <p:columns value="#{dynamicExampleBean.columns}" 
   var="column" headerText="#{column.header}">

      <p:selectBooleanCheckbox value="#{obj[column.property]}" 
    disabled="true" rendered="#{column.type.toString() == 'boolean'}"/>

      <h:outputText value="#{obj[column.property]}" rendered="#{column.type.toString() != 'boolean'}" />

   </p:columns>

</p:dataTable>

</h:form>

The Bean

@ManagedBean
@ViewScoped
public class DynamicExampleBean implements Serializable{
	
	private List<ColumnModel> columns = new ArrayList<ColumnModel>(0);
	private String currentClass = User.class.getName();
	
	@PostConstruct
	public void init() {
		onChangeClass();
	}
	
	public void onChangeClass(){
		try {
			columns = new ReflectionColumnModelBuilder(Class.forName(currentClass)).
					setExcludedProperties("id").
					build();
		} catch (ClassNotFoundException e) {
			//Will not happen
			columns = null;
		}
	}
	
	public List<Object> getData(){
		try {
			return (List<Object>) MethodUtils.invokeExactStaticMethod(Class.forName(currentClass), "getAll", null);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public List<ColumnModel> getColumns() {
		return columns;
	}
	public String getCurrentClass() {
		return currentClass;
	}

	public void setCurrentClass(String currentClass) {
		this.currentClass = currentClass;
	}
}

The only thing that may need some explanation is the getData method: we use the MethodUtils class to dynamically invoke the getAll static method of one of the two classes. The result of this example is this:

Using ViewParam

For our last example we are going to use a f:viewParam to choose the data to display. This example its similar to the previous one but the ColumnModels are generated during the preRender event.

The Page

<f:metadata>
	<f:viewParam name="class" value="#{viewParamExampleBean.currentClass}"></f:viewParam>
	<f:event listener="#{viewParamExampleBean.onPreRender}" type="preRenderView"></f:event>
</f:metadata>
<h:body>
	<p:dataTable var="obj" value="#{viewParamExampleBean.data}">
		<p:columns 
			value="#{viewParamExampleBean.columns}" 
			var="column"
			headerText="#{column.header}">
			<p:selectBooleanCheckbox 
				value="#{obj[column.property]}" 
				disabled="true"
				rendered="#{column.type.toString() == 'boolean'}"/>
			<h:outputText value="#{obj[column.property]}" rendered="#{column.type.toString() != 'boolean'}" />
		</p:columns>
	</p:dataTable>
</h:body>

The Bean

@ManagedBean
@ViewScoped
public class ViewParamExampleBean implements Serializable{
	
	private List<ColumnModel> columns = new ArrayList<ColumnModel>(0);
	private String currentClass = User.class.getName();
	
	public void onPreRender() {
		try {
			columns = new ReflectionColumnModelBuilder(Class.forName(currentClass)).
					setExcludedProperties("id").
					build();
		} catch (ClassNotFoundException e) {
			//Will not happen
			columns = null;
		}
	}
	
	public List<Object> getData(){
		try {
			return (List<Object>) MethodUtils.invokeExactStaticMethod(Class.forName(currentClass), "getAll", null);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public List<ColumnModel> getColumns() {
		return columns;
	}
	
	public String getCurrentClass() {
		return currentClass;
	}

	public void setCurrentClass(String currentClass) {
		this.currentClass = currentClass;
	}
}

We can now use a single page for every model in our application, and we can change the data displayed with a simple menu like this:

<h:form>

   <p:menubar>

       <p:menuitem value="View Param (User)" action="param?faces-redirect=true&amp;class=it.strazz.primefaces.model.User"/>

       <p:menuitem value="View Param (Car)" action="param?faces-redirect=true&amp;class=it.strazz.primefaces.model.Car"/>

   </p:menubar>

</h:form>

To create new pages the only thing that we need to implement its the new POJO class. Obviously in a real life application you will need a better persistence layer (JPA, Hibernate) than our ˜dummy active record.

Conclusions

During one of my first Java lessons at the university, my teacher said Reflection is Devil!or something like that. It’s true, but it could be a useful hack sometimes. The code of this article would be the base of a quick prototyping framework for PrimeFaces: it will not be a scaffolder like the CRUD generator bundled with NetBeans, but almost everything will be built at runtime just like this example. If you want to contribute just send me an email or create a pull request at the GitHub project repository. 

In the next post I will use the same reflection technique to create a detail page for our POJOs.

Forked source code for WildFly: https://github.com/fmarchioni/primefaces-reflection-crud