Skip to content

tentackle-fx-rdc-poi — Spreadsheet (XLS) Export for RDC Tables

Overview and Motivation

Every rich desktop client table and tree-table already offers a context-menu action to export its rows to a spreadsheet file. Out of the box that action lives in TableUtilities and writes CSV (RFC 4180) — a format every spreadsheet application can open, with no extra dependencies.

tentackle-fx-rdc-poi upgrades that same action to write a real Excel .xls workbook using Apache POI. It does so without any change to application code: the module contributes a single service that replaces the default TableUtilities. Drop the module on the path and the table popup's Export to spreadsheet command produces a styled .xls file instead of CSV.

How it plugs in

The module ships one public type, PoiTableUtilities, which extends TableUtilities and is registered through the service API:

@Service(TableUtilities.class)
@ClasspathFirst(TableUtilities.class)   // POI isn't modularized yet, but fx-rdc is
public class PoiTableUtilities extends TableUtilities {
  ...
}
  • @Service(TableUtilities.class) makes ServiceFinder return PoiTableUtilities wherever the RDC asks for the singleton TableUtilities.getInstance() — including the Export / Export selected rows items wired up in TablePopup.
  • @ClasspathFirst(TableUtilities.class) is required because Apache POI is not yet a proper JPMS module (see the caveat below).

Only two methods are overridden:

  • selectSpreadsheetFile(...) — opens the file dialog with the .xls extension and remembers the last directory per table, using persisted preferences (key prefix lastXlsNames/).
  • toSpreadsheet(columnConfigurations, file, items) — builds the workbook from the table's visible TableColumnConfigurations.

What the export produces

The exporter walks each visible column's binding and maps the model value to a typed cell:

Model value Cell rendering
Boolean boolean cell
BMoney numeric cell with a #,##0[.0…] format matching the money scale
any other Number numeric cell
Date / Calendar date cell with the built-in m/d/yy format
anything else (!= null) rich-text string from toString()

Column headers are written as a bold, italic, centered first row. Number formats are cached and reused per scale, so a large export does not create one cell style per row.

JPMS / POI caveat

Apache POI 5.x still depends on filename-based automatic modules (e.g. commons-math3), so this module deliberately has no module-info.java and relies on @ClasspathFirst.

If you build a distribution image with the jlink/jpackage plugin, keep the POI artifact on the classpath — moving it to the module path (even via modulePathOnly) fails, because an automatic module referencing it uses the wrong class loader and throws ClassNotFoundException:

<plugin>
  <groupId>org.tentackle</groupId>
  <artifactId>tentackle-jlink-maven-plugin</artifactId>
  <configuration>
    <classpathDependencies>
      <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
      </dependency>
    </classpathDependencies>
  </configuration>
</plugin>

Once POI and all its transitive dependencies are fully modularized, the module can declare a normal module-info.java and this special handling can be dropped.

See also