Close

Java Swing - JTable Lazy Pagination with JPA

[Updated: Jul 4, 2018, Created: Feb 2, 2018]

This example shows how to do lazy pagination with JTable. The data will be retrieved from JPA backend on demand. We will use Hibernate as JPA provider and H2 in-memory database. The JTable will also have sorting functionality like the last example.

Main class

public class PaginationExampleMain {
  public static void main(String[] args) {
      JFrame frame = createFrame();
      ObjectTableModel<Employee> objectDataModel = createObjectDataModel();
      JTable table = new JTable(objectDataModel);
      table.setAutoCreateRowSorter(true);
      PaginationDataProvider<Employee> dataProvider = createDataProvider(objectDataModel);
      PaginatedTableDecorator<Employee> paginatedDecorator = PaginatedTableDecorator.decorate(table,
              dataProvider, new int[]{5, 10, 20, 50, 75, 100}, 10);
      frame.add(paginatedDecorator.getContentPanel());
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
  }

  private static ObjectTableModel<Employee> createObjectDataModel() {
      return new ObjectTableModel<Employee>() {
          @Override
          public Object getValueAt(Employee employee, int columnIndex) {
              switch (columnIndex) {
                  case 0:
                      return employee.getId();
                  case 1:
                      return employee.getName();
                  case 2:
                      return employee.getPhoneNumber();
                  case 3:
                      return employee.getAddress();
              }
              return null;
          }

          @Override
          public int getColumnCount() {
              return 4;
          }

          @Override
          public String getColumnName(int column) {
              switch (column) {
                  case 0:
                      return "Id";
                  case 1:
                      return "Name";
                  case 2:
                      return "Phone Number";
                  case 3:
                      return "Address";
              }
              return null;
          }

          @Override
          public String getFieldName(int column) {
              switch (column) {
                  case 0:
                      return "id";
                  case 1:
                      return "name";
                  case 2:
                      return "phoneNumber";
                  case 3:
                      return "address";
              }
              return null;
          }
      };
  }

  private static PaginationDataProvider<Employee> createDataProvider(
          ObjectTableModel<Employee> objectDataModel) {

      return new EmployeeLazyDataProvider(objectDataModel);
  }

  private static JFrame createFrame() {
      JFrame frame = new JFrame("JTable Pagination example");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.setSize(new Dimension(600, 300));
      return frame;
  }
}

PaginationDataProvider implementation

public class EmployeeLazyDataProvider implements PaginationDataProvider<Employee> {
    private final int totalEmployeeCount;
    private final ObjectTableModel<Employee> objectTableModel;

    public EmployeeLazyDataProvider(ObjectTableModel<Employee> objectTableModel) {
        this.objectTableModel = objectTableModel;
        this.totalEmployeeCount = DataService.INSTANCE.getEmployeeTotalCount();
    }

    @Override
    public int getTotalRowCount() {
        return totalEmployeeCount;
    }

    @Override
    public List<Employee> getRows(int startIndex, int endIndex, int sortColumnIndex, boolean sortDescending) {
        String fieldName = sortColumnIndex != -1 ?
                objectTableModel.getFieldName(sortColumnIndex) : null;
        return DataService.INSTANCE.getEmployeeList(
                startIndex,  endIndex - startIndex , fieldName, sortDescending);
    }
}

Employee class with JPA annotations

@Entity
public class Employee {
    @Id
    @SequenceGenerator(name = "eSGen", sequenceName = "employeeSeq",
            initialValue = 50)
    @GeneratedValue(generator = "eSGen")
    private long id;
    private String name;
    private String phoneNumber;
    private String address;

    public long getId () {
        return id;
    }

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

    public String getName () {
        return name;
    }

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

    public String getPhoneNumber () {
        return phoneNumber;
    }

    public void setPhoneNumber (String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getAddress () {
        return address;
    }

    public void setAddress (String address) {
        this.address = address;
    }
}

The pagination decorator

There's no change with the decorator from the last example.

JPA data service

public enum DataService {
  INSTANCE;
  private final EntityManagerFactory emf =
          Persistence.createEntityManagerFactory("employee-unit");

  DataService() {
      //persisting some test data in database
      EntityManager em = emf.createEntityManager();
      em.getTransaction().begin();
      DataFactory dataFactory = new DataFactory();
      for (int i = 1; i < 100; i++) {
          Employee employee = new Employee();
          employee.setName(dataFactory.getName());
          employee.setPhoneNumber(String.format("%s-%s-%s", dataFactory.getNumberText(3),
                  dataFactory.getNumberText(3),
                  dataFactory.getNumberText(4)));
          employee.setAddress(dataFactory.getAddress() + "," + dataFactory.getCity());
          em.persist(employee);
      }

      em.getTransaction().commit();
      em.close();
  }

  public List<Employee> getEmployeeList(int start, int size,
                                        String sortField, boolean sortDescending) {
      EntityManager em = emf.createEntityManager();
      CriteriaBuilder cb = em.getCriteriaBuilder();
      CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
      Root<Employee> r = q.from(Employee.class);
      CriteriaQuery<Employee> select = q.select(r);
      if (sortField != null) {
          q.orderBy(sortDescending ?
                  cb.desc(r.get(sortField)) : cb.asc(r.get(sortField)));
      }

      TypedQuery<Employee> query = em.createQuery(select);
      query.setFirstResult(start);
      query.setMaxResults(size);
      List<Employee> list = query.getResultList();
      return list;
  }

  public int getEmployeeTotalCount() {
      EntityManager em = emf.createEntityManager();
      Query query = em.createQuery("Select count(e.id) From Employee e");
      return ((Long) query.getSingleResult()).intValue();
  }
}

Output

Example Project

Dependencies and Technologies Used:

  • h2 1.4.196: H2 Database Engine.
  • hibernate-core 5.2.12.Final: The core O/RM functionality as provided by Hibernate.
    Implements javax.persistence:javax.persistence-api version 2.1
  • datafactory 0.8: Library to generate data for testing.
  • JDK 1.8
  • Maven 3.3.9

JTable lazy Pagination with Sorting Example Select All Download
  • table-lazy-pagination-with-jpa
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • EmployeeLazyDataProvider.java
          • resources
            • META-INF

    See Also