Skip to content
sheetsmith

@ExcelColumn

Exports a field of a sheet class as a column.

  • Opt-in. Only fields carrying this annotation become columns.
  • Inheritance. Annotated fields of superclasses are columns too.
  • At least one column per sheet class (V-02).
  • Not on static fields (V-05).
  • Records. On a record component, the annotation applies to the component field.
  • Mandatory attributes. header and order have no default, so the compiler rejects a column without them.

Summary of the attributes:

Attribute Type Default
header String none, mandatory
order int none, mandatory
width int ExcelStyle.UNSET
format String ""
converter Class<? extends CellConverter<?>> CellConverter.None.class
headerStyle String ""
styles ColumnStyles @ColumnStyles (no slot set)

The value of a column is read as follows:

  1. Record: through the component accessor (amount()).
  2. Class: through a public, non-static, no-argument getter, declared on the class or inherited, whose return type is assignable to the field type:
    • for boolean and Boolean fields, isX() is tried first, then getX();
    • for fields of any other type, getX(). X is the field name with its first letter in upper case.
  3. Otherwise: directly from the field, even when it is private.

Consequences worth knowing:

  • A getter whose return type does not match is ignored, and the field is read directly. This includes primitive and wrapper mismatches: a Boolean active field with public boolean isActive() is read from the field, because boolean is not assignable to Boolean; the same holds for an int field with an Integer getX() getter. The value written is the same, but any logic inside the getter is bypassed.
  • A getter declared on the sheet class overrides a getter of a superclass, and an instance of a subclass passed as data uses the subclass override (normal virtual dispatch).
  • Getters generated by Lombok (@Getter, @Data, @Value) follow the conventions above and are used.
  • A getter that throws during generation causes a SheetsmithGenerationException naming the sheet, the row and the field, with the original exception as cause.

Modular applications. sheetsmith needs reflective access to the packages that contain the sheet classes. Open them in module-info.java:

  • opens com.example.export; (unqualified) works in every setup;
  • opens com.example.export to cloud.baldilorenzo.sheetsmith; works only when sheetsmith is on the module path, where its module name is cloud.baldilorenzo.sheetsmith. When sheetsmith is on the class path, it belongs to the unnamed module and the qualified directive does not reach it.

A value that cannot be accessed violates V-17, and the message names the package to open.

Type String
Default none: mandatory
Allowed values any non-blank text
Effect Text of the header cell of the column, written as it is (no translation, no trimming).
Validation V-04 when blank (empty or only whitespace).
Type int
Default none: mandatory
Allowed values any int, negative values included; unique within the sheet class, inherited columns included
Effect Columns are placed from left to right in ascending order.
Validation V-03 when two columns share the same value; the error is reported on the second field found and names the first one.
@ExcelColumn(header = "Code", order = 10) String code;
@ExcelColumn(header = "Name", order = 20) String name;
// later, without renumbering:
@ExcelColumn(header = "Category", order = 15) String category;
Type int, characters
Default ExcelStyle.UNSET
Allowed values 1 to 255, or UNSET
Effect Sets the column width in characters (Excel width units of the default font).
Interactions A column with an explicit width keeps it and is excluded from autoSizeColumns. With UNSET, the width comes from automatic sizing or, when that is disabled, from the spreadsheet application.
Validation V-14 outside 1 to 255.
Type String, an Excel format code
Default "", leaving the format to the styles and the application defaults
Allowed values any Excel format code, in the Excel syntax described in section 6.6
Effect Format of the data cells of the column.
Interactions It is the last level of the body cascade: it wins over the dataFormat of every style applied to the cell and over the application default formats. It does not apply to the header cell. The format is written to the file as it is, without validation.
Validation None: an invalid format code is not detected by sheetsmith and may be shown by Excel as a repair message or ignored.
@ExcelColumn(header = "Due date", order = 30, format = "dd/mm/yyyy") LocalDate due;
@ExcelColumn(header = "Amount", order = 40, format = "#,##0.00 \"EUR\"") BigDecimal amount;
@ExcelColumn(header = "Rate", order = 50, format = "0.0%") double rate;
Type Class<? extends CellConverter<?>>
Default CellConverter.None.class, meaning no field converter
Allowed values a converter class handling a type assignable from the field type (primitive types count as their wrappers)
Effect The values of this column are converted with this converter instead of the application or built-in converter for the field type.
Interactions One instance per converter class and per generator, shared by every column that declares it. Without Spring, the class must be public with a public no-argument constructor. With the Spring Boot auto-configuration, the bean of that class is used when exactly one exists, otherwise a new instance is created with dependency injection (see section 9.6).
Validation V-11 when the handled type is incompatible (checked when the handled type can be determined from the generic declaration of the converter class); V-12 when the converter cannot be created.
@ExcelColumn(header = "Id", order = 10, converter = UuidAsText.class) UUID id;
Type String, the name of a named style
Default ""
Effect Applied to the header cell of this column. It is the last level of the header cascade: it wins over the preset, the header slots and the frame.
Validation V-06 when the name does not exist.
@ExcelColumn(header = "Amount", order = 40, headerStyle = "right") BigDecimal amount;
Type ColumnStyles
Default @ColumnStyles, no slot set
Effect The named styles of the data cells of this column: see section 4.8. Column slots are the most specific slots of the body cascade.
@ExcelSheet
@ExcelStyle(name = "money", align = Align.RIGHT)
@ExcelStyle(name = "right", align = Align.RIGHT)
@ExcelStyle(name = "negative-highlight", fontColor = "#C00000")
public class LedgerRow {
@ExcelColumn(header = "Account", order = 10, width = 14)
private String account;
@ExcelColumn(header = "Booked on", order = 20, format = "dd/mm/yyyy")
private LocalDate bookedOn;
@ExcelColumn(header = "Balance", order = 30, format = "#,##0.00;[Red]-#,##0.00",
headerStyle = "right", styles = @ColumnStyles(base = "money"))
private BigDecimal balance;
@ExcelColumn(header = "Currency", order = 40, converter = CurrencyCodeConverter.class)
private Currency currency;
public String getAccount() { return account; }
public LocalDate getBookedOn() { return bookedOn; }
public BigDecimal getBalance() { return balance; }
public Currency getCurrency() { return currency; }
}