Skip to content


Folders and files

Last commit message
Last commit date

Latest commit


Repository files navigation

ExcelUtil from Apache POI

Maven Central

ExcelUtil is a Java wrapper using Apache POI to read and write Excel file in declarative fashion.

This library is also introduced as "Related Project" on Apache POI's official website.


ExcelUtil is using Apache POI version 5.2.2


Usage Guides

For full detail guides & example, see the Wiki page.

Quick Guides

Write Excel

Here we have a simple class Book:

class Book {
    private String isbn;
    private String title;
    private double rating;
    private String author;
    private String subCategory;
    private Category category;
    static class Category {
        private long id;
        private String name;

A very simple usage

The core building block to write data is DataTemplate<T>. It holds mapping rules of the DTO class you need to export Excel.

public class Main {

    static final DataTemplate<Book> BOOK_TEMPLATE = DataTemplate

    public static void main(String[] args) {
        InputStream stream = BOOK_TEMPLATE.writeData(books);

        FileUtil.writeToDisk(".../books.xlsx", stream, true);

Your DTO class should follow camelCase convention, so that the generated titles would be correct.

Customize Styles

The next building block is Style, which is pretty much the same as what you can configure with normal Excel.

static final Style BASED_STYLE = Style
        .fontSize((short) 12)

static final Style HEADER_STYLE = Style
        .builder(BASED_STYLE)     // it is able to accumulate previous style

Since Apache POI has some limitations regarding to stylings, it is recommended to pre-define your styles as static constant for optimization and further reuse.

Below is an example to apply styles conditionally.

public class Main {
    static final Style DATA_STYLE = ...
    static final Style HIGH_RATE = ...
    static final Style FAVORITE_ONE = ...

    static final DataTemplate<Book> BOOK_TEMPLATE = DataTemplate
            .column(c -> c.field("isbn").title("ISBN"))  // customize column title
            .includeFields("title", "author")
            .column(c -> c.title("Category")
                          .transform(book -> book.getCategory().getName()))  // derive new column
            .column(c -> c.field("rating")
                          .conditionalStyle(book -> book.getRating() > 4 ?  // styles with conditions
                                                    HIGH_RATE : null))
            .config(cf -> cf.startAtCell("A2")
                            .conditionalRowStyle(book -> book.getTitle() // selective styling
                                            .contains("Harry Potter") ? FAVORITE_ONE : null));

    public static void main(String[] args) {
        InputStream stream = BOOK_TEMPLATE.writeData(books);

        FileUtil.writeToDisk(".../books.xlsx", stream, true);



Merge rows

You can merge your data rows, either based on same cell values or a particular value that you specify.

Before doing so, you might want to sort your data so that the merging process can perform correctly.

     .comparing((Book book) -> book.getCategory().getId())

Here is example of how to configure merge rows.

static final Style VCENTER = Style.builder().verticalAlignment(VerticalAlignment.CENTER).build();

static final DataTemplate<Book> BOOK_TEMPLATE = DataTemplate
        .column(c -> c.field("subCategory")
                      .mergeOnValue(true))  // merge cells with the same value consecutively
        .column(c -> c.title("Category")
                      .transform(book -> book.getCategory().getName())
                      .mergeOnId(book -> book.getCategory().getId()))  // merge on derived value
        .config(cf -> cf.startAtCell("A2")



Read Excel

The building block to read data is ReaderConfig<T>.

ReaderConfig<Book> BOOK_READER = ReaderConfig
        .column(0, "ibsn")
        .column(1, "title")
        .column(2, "author")
        .column(3, "category");

You can directly retrieve the config from your already defined DataTemplate<T>.

ReaderConfig<Book> BOOK_READER = BOOK_TEMPLATE.getReaderConfig();

InputStream stream = FileUtil.readFromDisk(".../book.xlsx");
List<Book> books = BOOK_READER.readSheet(stream);

For more flexible process while reading data, use built-in callback handler as below.

ReaderConfig<Book> READER_CONFIG = ReaderConfig
    .column(0, "ibsn")
    .column(1, "title")
    .handler(set -> set.atColumn(2)
                       .handle((book, cell) -> {
                           String value = cell.readString();
    .handler(set -> set.fromColumn(3)
                       .handle((book, cell) -> {
                           String title = cell.getColumnTitle();
                           if (title.contains("Rating in")) {
                               String year = title.substring(10);
                               Double rating = cell.readDouble();
                               book.getRatingMap().put(year, rating);


Documentation can be found here.


  • Minimum JDK version: 1.8
  • Support Excel version:
    • 97-2003 (.xls)
    • 2007+ (.xlsx)


Released under Apache-2.0 License.