Codion uses a plugin oriented approach to report viewing and provides an implementation for JasperReports.

With the Codion JasperReports plugin you can either design your report based on an SQL query in which case you use the JRReport class, which facilitates the report being filled using the active database connection, or you can design your report around the JRDataSource implementation provided by the JasperReportsDataSource class, which is constructed around an iterator.

1. JDBC Reports

Using a report based on an SQL query is the simplest way of viewing a report using Codion, just add a method similar to the one below to a EntityTablePanel subclass. You can then create an action calling that method and put it in for example the table popup menu as described in the adding a print action section.

public class CustomerTablePanel extends EntityTablePanel {

  public CustomerTablePanel(SwingEntityTableModel tableModel) {
    super(tableModel);
    // associate a custom Control with the PRINT control key,
    // which calls the viewCustomerReport method in this class,
    // enabled only when the selection is not empty
    control(PRINT).set(Control.builder()
            .command(this::viewCustomerReport)
            .caption("Customer report")
            .smallIcon(FrameworkIcons.instance().print())
            .enabled(tableModel().selection().empty().not())
            .build());
  }

  private void viewCustomerReport() {
    List<Entity> selectedCustomers = tableModel().selection().items().get();
    if (selectedCustomers.isEmpty()) {
      return;
    }

    Collection<String> customerIds = Entity.values(Customer.ID, selectedCustomers);
    Map<String, Object> reportParameters = new HashMap<>();
    reportParameters.put("CUSTOMER_IDS", customerIds);

    JasperPrint customerReport = tableModel().connection()
            .report(Customer.REPORT, reportParameters);

    Dialogs.builder()
            .component(new JRViewer(customerReport))
            .owner(this)
            .modal(false)
            .title("Customer Report")
            .size(new Dimension(800, 600))
            .show();
  }
}

2. JRDataSource Reports

The JRDataSource implementation provided by the JasperReportsDataSource simply iterates through the iterator received via the constructor and retrieves the field values from the underlying entities. The easiest way to make this work is to design the report using field names that correspond to the attribute names, so using the Store domain example from above the fields in a report showing the available items would have to be named 'name', 'active', 'category_code' etc.

EntityConnection connection = connectionProvider.connection();

EntityDefinition customerDefinition =
        connection.entities().definition(Customer.TYPE);

Iterator<Entity> customerIterator =
        connection.select(all(Customer.TYPE)).iterator();

JasperReportsDataSource<Entity> dataSource =
        new JasperReportsDataSource<>(customerIterator,
                (entity, reportField) ->
                        entity.get(customerDefinition.attributes().getOrThrow(reportField.getName())));

JRReport customerReport = fileReport("reports/customer.jasper");

JasperPrint jasperPrint = JasperReports.fillReport(customerReport, dataSource);

3. Examples