Basics
Complete, self-contained use cases. Package declarations and imports are omitted where obvious. All names and data are fictional.
Minimal export
Section titled “Minimal export”@ExcelSheetpublic record ProductRow( @ExcelColumn(header = "SKU", order = 10) String sku, @ExcelColumn(header = "Name", order = 20) String name, @ExcelColumn(header = "Price", order = 30) BigDecimal price) {}
byte[] file = Sheetsmith.builder().build() .generate(List.of(SheetData.of("Products", ProductRow.class, products)));Result: header in row 1, frozen; one row per product; columns sized to content; no styles (Excel defaults); prices in the General format, unless a default number format is configured.
Several sheets with different classes
Section titled “Several sheets with different classes”List<SheetData<?>> sheets = List.of( SheetData.of("Summary", SummaryRow.class, List.of(summary)), SheetData.of("Customers", CustomerRow.class, customers), SheetData.of("Orders", OrderRow.class, orders));
byte[] file = sheetsmith.generate(sheets);Sheets appear in list order. All three classes are validated before anything is written, and their errors, if any, are reported together.
One class, several sheets
Section titled “One class, several sheets”Map<YearMonth, List<OrderRow>> byMonth = orders.stream() .collect(Collectors.groupingBy(order -> YearMonth.from(order.date()), TreeMap::new, Collectors.toList()));
List<SheetData<?>> sheets = byMonth.entrySet().stream() .<SheetData<?>>map(e -> SheetData.of(e.getKey().toString(), OrderRow.class, e.getValue())) .toList();
byte[] file = sheetsmith.generate(sheets);YearMonth.toString() gives names such as 2026-09, which are valid sheet names. The metadata of OrderRow is computed once.
Columns inherited from a base class
Section titled “Columns inherited from a base class”public abstract class AuditedRow { @ExcelColumn(header = "Created by", order = 900) protected String createdBy; @ExcelColumn(header = "Created on", order = 910, format = "dd/mm/yyyy") protected LocalDate createdOn; public String getCreatedBy() { return createdBy; } public LocalDate getCreatedOn() { return createdOn; }}
@ExcelSheetpublic class ContractRow extends AuditedRow { @ExcelColumn(header = "Contract", order = 10) private String number; @ExcelColumn(header = "Party", order = 20) private String party; public String getNumber() { return number; } public String getParty() { return party; }}The audit columns (orders 900 and 910) follow the contract columns in every subclass. Orders must be unique across the whole hierarchy. Named styles must be declared on ContractRow (or a style sheet), not on AuditedRow.