{"id":16215065,"url":"https://github.com/firegloves/mempoi","last_synced_at":"2026-02-27T09:14:36.753Z","repository":{"id":44561615,"uuid":"183628179","full_name":"firegloves/MemPOI","owner":"firegloves","description":"A library to simplify export from database to Excel files using Apache POI :japanese_goblin:","archived":false,"fork":false,"pushed_at":"2025-01-23T05:30:23.000Z","size":11924,"stargazers_count":60,"open_issues_count":3,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-09T20:08:30.783Z","etag":null,"topics":["apache-poi","database","excel","excelgenerator","excelwriter","hacktoberfest","java","poi","sheet","xlsx"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/firegloves.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"docs/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-04-26T12:53:08.000Z","updated_at":"2024-11-06T08:46:46.000Z","dependencies_parsed_at":"2024-07-18T11:46:21.272Z","dependency_job_id":"bf3194b8-f434-478f-8976-363ba9b3eafd","html_url":"https://github.com/firegloves/MemPOI","commit_stats":{"total_commits":287,"total_committers":8,"mean_commits":35.875,"dds":0.5435540069686411,"last_synced_commit":"fc2be6acd60f369a6074884d1bc72bc00a5e557a"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firegloves%2FMemPOI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firegloves%2FMemPOI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firegloves%2FMemPOI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/firegloves%2FMemPOI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/firegloves","download_url":"https://codeload.github.com/firegloves/MemPOI/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248103873,"owners_count":21048245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apache-poi","database","excel","excelgenerator","excelwriter","hacktoberfest","java","poi","sheet","xlsx"],"created_at":"2024-10-10T11:13:47.248Z","updated_at":"2026-02-27T09:14:36.694Z","avatar_url":"https://github.com/firegloves.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Codacy Badge](https://app.codacy.com/project/badge/Coverage/cc1f609aa1284ce0b15d7deb6e451737)](https://www.codacy.com/gh/firegloves/MemPOI/dashboard?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=firegloves/MemPOI\u0026amp;utm_campaign=Badge_Coverage)\n[![Codacy Badge](https://app.codacy.com/project/badge/Grade/cc1f609aa1284ce0b15d7deb6e451737)](https://www.codacy.com/gh/firegloves/MemPOI/dashboard?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=firegloves/MemPOI\u0026amp;utm_campaign=Badge_Grade)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n![Maven Central](https://img.shields.io/maven-central/v/it.firegloves/mempoi)\n![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/firegloves/MemPOI)\n[![Build and Test](https://github.com/firegloves/MemPOI/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/firegloves/MemPOI/actions/workflows/build-and-test.yml)\n[![Code coverage](https://github.com/firegloves/MemPOI/actions/workflows/code-coverage.yml/badge.svg)](https://github.com/firegloves/MemPOI/actions/workflows/code-coverage.yml)\n[![Staging repo Maven Central](https://github.com/firegloves/MemPOI/actions/workflows/publish-to-staging-repo-maven-central.yml/badge.svg)](https://github.com/firegloves/MemPOI/actions/workflows/publish-to-staging-repo-maven-central.yml)\n![Java 8](https://img.shields.io/badge/Java%208-Tested-blueviolet)\n![Java 11](https://img.shields.io/badge/Java%2011-Tested-blueviolet)\n![Java 17](https://img.shields.io/badge/Java%2017-Tested-blueviolet)\n![Java 21](https://img.shields.io/badge/Java%2021-Tested-blueviolet)\n[![Known Vulnerabilities](https://snyk.io/test/github/firegloves/mempoi/badge.svg)](https://snyk.io/test/github/firegloves/mempoi)\n![No ORM - Super Fast](https://img.shields.io/badge/No%20ORM-SuperFast-orange)\n\n# MemPOI :green_book: \u0026nbsp; :arrow_right: \u0026nbsp; :japanese_goblin: \u0026nbsp; :arrow_right: \u0026nbsp; :tropical_drink:\nA library to simplify export from database to Excel files using Apache POI\n\n---\n\n## \u003cp align=center\u003eWithout MemPOI\u003c/p\u003e\n\n![](img/with-and-without-mempoi/without-mempoi.jpg)\n\n## \u003cp align=center\u003eWith MemPOI\u003c/p\u003e\n\n![](img/with-and-without-mempoi/with-mempoi.jpg)\n\n---\n\n### No ORM = Super Fast\n\nMemPOI is not designed to be used with an ORM due to performance needs on massive exports.\nBy directly leveraging JDBC classes to access DB data, MemPOI ensures super-fast execution on hundreds of thousands of records.\n\nA short \u003ca href=\"https://medium.com/@lucorset/mempoi-a-mempo-mask-for-apache-poi-to-let-you-conquer-freedom-and-sip-a-good-mojito-on-the-930e1ca337d8\"\u003estory about Mempoi's birth\u003c/a\u003e\n\n---\n\n### Support\n\n- Apache POI 4.0.0+\n- Java 8+\n\n---\n\n### Import\n\n#### With Gradle\n\n```Groovy\nimplementation group: 'it.firegloves', name: 'mempoi', version: '1.10.1'\n```\n\n#### With Maven\n\n```XML\n\u003cdependency\u003e\n    \u003cgroupId\u003eit.firegloves\u003c/groupId\u003e\n    \u003cartifactId\u003emempoi\u003c/artifactId\u003e\n    \u003cversion\u003e1.10.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n--\n\n### What's new in 1.10.1\n- Vulnerable dependencies fix\n\n### What's new in 1.10.0\n- NEW FUNCTIONALITY - [Ignore columns](#ignore-columns)\n- NEW FUNCTIONALITY - [Rearrange columns](#rearrange-columns)\n- Spring Framework example - [Spring Framework example](#spring-framework-example)\n\n---\n\nHere you can find documentation organized on a single page, if you prefer a more structured version please consult the [wiki](https://github.com/firegloves/MemPOI/wiki)\n\nMain features index:\n\n- [Basic usage](#basic-usage)\n- [File VS byte array](#file-vs-byte-array)\n- [Supported SQL data types](#supported-sql-data-types)\n- [Column headers](#column-headers)\n- [Multiple sheets](#multiple-sheets)\n- [Adjust columns width](#adjust-columns-width)\n- [Styles](#styles)\n- [Simple text header](#simple-text-header)\n- [Simple text footer](#simple-text-footer)\n- [Footers and subfooters](#footers-and-subfooters)\n- [Cell formulas](#cell-formulas)\n- [Excel Table](#excel-table)\n- [Excel Pivot Table](#excel-pivot-table)\n- [Metadata](#metadata)\n- [Column Configuration](#column-configuration)\n- [Column cell style](#column-cell-style)\n- [Data transformation functions](#data-transformation-functions)\n- [Column header customization](#column-header-customization)\n- [Ignore Columns](#ignore-columns)\n- [Rearrange Columns](#rearrange-columns)\n- [Encryption](#encryption)\n- [Null values over primitives default ones](#null-values-over-primitives-default-ones)\n- [Data post elaboration pipeline](#data-post-elaboration-pipeline)\n- [Merged Regions](#merged-regions)\n- [Column and Row offsets](#column-and-row-offsets)\n- [Spring Framework example](#spring-framework-example)\n- [Force Generation](#force-generation)\n- [Logging](#logging)\n- [Vulnerable dependency management](#vulnerable-dependency-management)\n- [Donate crypto](#donate-crypto)\n\n---\n\n### MemPOI survey\n\nIn order to better trace MemPOI usages and decide the next features, I created a [survey](https://lucorset.typeform.com/to/bDIRbY). No subscription is required.\n\n---\n\n### Basic usage\n\nAll you need is to instantiate a MemPOI passing it the List of your exporting queries. MemPOI will do all the stuff for you generating a .xlsx file containing resulting data.\nYou need to pass your export queries as a List of `MempoiSheet` (`PreparedStatement` + sheet name).\nYou can use `MempoiBuilder` to correctly populate your MemPOI instance, like follows:\n\n```Java\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                    .addMempoiSheet(new MempoiSheet(prepStmt))\n                    .build();\n\nCompletableFuture\u003cMempoiReport\u003e future = memPOI.prepareMempoiReport();\n```\n\nYou can find more examples in the functional tests package.\n\nBy default `SXSSFWorkbook` is used, but these are the supported `Workbook`'s descendants:\n- `SXSSFWorkbook`\n- `XSSFWorkbook`\n- `HSSFWorkbook`\n\n**Multiple sheets supported** - Each `MempoiSheet` will add a sheet to the generated report\n\n---\n\n### File VS byte array\n\nYou can choose to write directly to a file or to obtain the byte array of the generated report (for example to pass it back to a waiting client)\n\n#### File\n\nSimply pass a file to the `MempoiBuilder` and the report will be written on file.\nTo get the absolute file path where the report has been saved you can access `MempoiReport`'s `file` property.\n\n```Java\nFile fileDest = new File(\"test_with_file.xlsx\");\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                    .withFile(fileDest)\n                    .addMempoiSheet(new MempoiSheet(prepStmt))\n                    .build();\n\nCompletableFuture\u003cMempoiReport\u003e fut = memPOI.prepareMempoiReport();\nMempoiReport mempoiReport = fut.get();\nmempoiReport.getFile(); // will return the string absolute path of the generated report file\n```\n\n#### Byte array\n\nIf you omit to specify a file in the `MempoiBuilder`, MemPOI will write the report on a byte array.\nThen you can read the byte array by accessing the `MempoiReport`'s `bytes` property.\n\n```Java\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                    .addMempoiSheet (new MempoiSheet(prepStmt))\n                    .build();\n\nCompletableFuture\u003cMempoiReport\u003e fut = memPOI.prepareMempoiReport();\nMempoiReport mempoiReport = fut.get();\nmempoiReport.getBytes(); // will return the byte[] containing the generated report\n```\n\n### Supported SQL data types\n\n- BIGINT\n- DOUBLE\n- DECIMAL\n- FLOAT\n- NUMERIC\n- REAL\n- INTEGER\n- SMALLINT\n- TINYINT\n- CHAR\n- NCHAR\n- VARCHAR\n- NVARCHAR\n- LONGVARCHAR\n- TIMESTAMP\n- DATE\n- TIME\n- BIT\n- BOOLEAN\n- UUID (Postgres) (thanks to [nanshakov](https://github.com/nanshakov))\n\n---            \n\n**You have to take care to manage your database connection, meanwhile `PreparedStatement` and `ResultSet` are managed and closed internally by MemPOI**\n\n---\n\n### Column headers\n\nColumn headers are generated taking export query column names. If you want to choose column headers you can specify them with `AS` clause. For example:\n\n```SQL\nSELECT id, name AS first_name FROM Foo\n```\n\nwill result in a sheet with 2 columns: id and first_name (containing db's name column data)\n\nStarting by version 1.6.0 it is possible to programmatically manage column headings through a specific [Column header customization](#column-header-customization)\n\n---\n\n### Multiple sheets\n\nMultiple sheets in the same document are supported: `MempoiBuilder` accepts a list of `MempoiSheet`.\nLook at this example and at the result above:\n\n```Java\nMempoiSheet dogsSheet = MempoiSheetBuilder.aMempoiSheet()\n                            .withSheetName(\"Dogs sheet\")\n                            .withPrepStmt(conn.prepareStatement(\"SELECT pet_name AS DOG_NAME, pet_race AS DOG_RACE FROM pets WHERE pet_type = 'dog'\"))\n                            .build();\n\nMempoiSheet catsSheet = MempoiSheetBuilder.aMempoiSheet()\n                            .withSheetName(\"Cats sheet\")\n                            .withPrepStmt(conn.prepareStatement(\"SELECT pet_name AS CAT_NAME, pet_race AS CAT_RACE FROM pets WHERE pet_type = 'cat'\"))\n                            .build();\n\nMempoiSheet birdsSheet = MempoiSheetBuilder.aMempoiSheet()\n                            .withSheetName(\"Birds sheet\")\n                            .withPrepStmt(conn.prepareStatement(\"SELECT pet_name AS BIRD_NAME, pet_race AS BIRD_RACE FROM pets WHERE pet_type = 'bird'\"))\n                            .build();\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                            .withFile(fileDest)\n                            .withAdjustColumnWidth(true)\n                            .addMempoiSheet(dogsSheet)\n                            .addMempoiSheet(catsSheet)\n                            .addMempoiSheet(birdsSheet)\n                            .build();\n\nCompletableFuture\u003cMempoiReport\u003e fut = memPOI.prepareMempoiReport();\nString absoluteFileName = fut.get().getFile();\n\n```\n\n![](img/multiple_sheets.gif)\n\n---\n\n### Adjust columns width\n\nMemPOI can adjust columns width to fit the longest content by setting to `true` the property `MempoiBuilder.adjustColumnWidth` as follows:\n\n```Java\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                    .withAdjustColumnWidth(true)\n                    .addMempoiSheet(new MempoiSheet(prepStmt))\n                    .build();\n```\n\n**Adjusting columns width for huge datasets could dramatically slow down the generation process**\n\n---\n\n### Styles\n\nMemPOI comes with a preset of default data formatting styles for\n\n- header cells\n- integer data types cells\n- floating-point data types cells\n- date data types cells\n- datetime data types cells\n\nThe default styles are automatically applied. You can inspect them looking at the end of `MempoiReportStyler` class\nIf you want to reset the default styles you need to use an empty `CellStyle` when you use `MempoiBuilder`, for example:\n\n```Java\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                    .withWorkbook(workbook)\n                    .addMempoiSheet(new MempoiSheet(prepStmt))\n                    .withIntegerCellStyle(workbook.createCellStyle())     // no default style for integer fields\n                    .build();\n```\n\nThis is an example setting a custom CellStyle for header's cells:\n\n```Java\nCellStyle headerCellStyle = workbook.createCellStyle();\nheaderCellStyle.setFillForegroundColor(IndexedColors.DARK_RED.getIndex());\nheaderCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                    .withFile(fileDest)\n                    .addMempoiSheet(new MempoiSheet(prepStmt))\n                    .withHeaderCellStyle(headerCellStyle)\n                    .build();\n```                    \n\nMemPOI comes with a set of templates ready to use. You can use them as follows:\n\n```Java\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                    .withWorkbook(workbook)\n                    .addMempoiSheet(new MempoiSheet(prepStmt))\n                    .withStyleTemplate(new ForestStyleTemplate())\n                    .build();\n```\n\nActually you can:\n- provide different styles for different sheets\n- granularly override bundled styles' cell styles\n\n```Java\n// SummerStyleTemplate for dogsSheet\nMempoiSheet dogsSheet = new MempoiSheet(conn.prepareStatement(\"SELECT id, creation_date, dateTime, timeStamp AS STAMPONE, name, valid, usefulChar, decimalOne, bitTwo, doublone, floattone, interao, mediano, attempato, interuccio FROM \" + TestConstants.TABLE_EXPORT_TEST), \"Dogs\");\ndogsSheet.setStyleTemplate(new SummerStyleTemplate());\n\n// Customized ForestStyleTemplate for catsSheet\nCellStyle floatingPointCellStyle = workbook.createCellStyle();\nfloatingPointCellStyle.setFillForegroundColor(IndexedColors.AQUA.getIndex());\nfloatingPointCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);\n\nMempoiSheet catsheet = MempoiSheetBuilder.aMempoiSheet()\n                                            .withSheetName(\"Cats\")\n                                            .withPrepStmt(prepStmt)\n                                            .withStyleTemplate(new ForestStyleTemplate())\n                                            .withFloatingPointCellStyle(floatingPointCellStyle)           // overrides ForestStyleTemplate's floating-point cell style\n                                            .build();\n                                            \nList\u003cMempoiSheet\u003e sheetList = Arrays.asList(dogsSheet, catsheet);\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                    .withWorkbook(workbook)\n                    .withFile(fileDest)\n                    .withAdjustColumnWidth(true)\n                    .withMempoiSheetList(sheetList)\n                    //    .setStyleTemplate(new PanegiriconStyleTemplate())     \u003c----- it has no effects because for each sheet a template is specified\n                    .withMempoiSubFooter(new NumberSumSubFooter())\n                    .withEvaluateCellFormulas(true)\n                    .build();\n``` \n\nList of available templates:\n\n| Name                      |      Image            |\n|---------------------------|-----------------------|\n| AquaStyleTemplate         |![](img/template/aqua.png)\n| ForestStyleTemplate       |![](img/template/forest.png)\n| PanegiriconStyleTemplate  |![](img/template/panegiricon.png)\n| PurpleStyleTemplate       |![](img/template/purple.png)\n| RoseStyleTemplate         |![](img/template/rose.png)\n| StandardStyleTemplate     |![](img/template/standard.png)\n| StoneStyleTemplate        |![](img/template/stone.png)\n| SummerStyleTemplate       |![](img/template/summer.png)\n\n#### Numeric cell styles\n\nNumeric data types (and the corresponding cell styles) are now split between integer and floating-point data types. This means that from version 1.3.0 database integer data types will be exported without numbers after comma. You can still specify a custom cell style or explicitly use one of the available ones.\nFor example in order use pre v1.3.0 integer cell style you can do something like this:\n\n```Java\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                    .withWorkbook(workbook)\n                    .addMempoiSheet(new MempoiSheet(prepStmt))\n                    .withIntegerCellStyle(new StandardStyleTemplate().getFloatingPointCellStyle())     // no default style for integer fields\n                    .build();\n```\n\n---\n\n### Simple text header\n\nStarting by v1.9 MemPOI supports the addition of a textual header before the exported data.\nTo add the text header you can simply add a line in the desired `MempoiSheetBuilder` as follows:\n\n```Java\nMempoiSheetBuilder.aMempoiSheet()\n        .withSheetName(catsSheetName)\n        .withSimpleHeaderText(\"My simple header\")\n        .withPrepStmt(conn.prepareStatement(catsQuery))\n        .build();\n```\n\nThe result will be something like this:\n\n![](img/simple-text-header.png)\n\nThe simple text header is compatible with the rows and columns offset.\n\n---\n\n### Simple text footer\n\nStarting by v1.9 MemPOI supports the addition of a textual footer after the exported data.\nTo add the text footer you can simply add a line in the desired `MempoiSheetBuilder` as follows:\n\n```Java\nMempoiSheetBuilder.aMempoiSheet()\n        .withSheetName(birdsSheetName)\n        .withSimpleFooterText(\"My simple footer\")\n        .withPrepStmt(conn.prepareStatement(birdsQuery))\n        .build();\n```\n\nThe result will be something like this:\n\n![](img/simple-text-footer.png)\n\nThe simple text footer is compatible with the rows and columns offset.\n\n---\n\n### Footers and subfooters\n\nMemPOI supports standard .xlsx footers and sub footers.\nWhereas footers are a simple wrapper of the Excel ones, subfooters are a MemPOI extension that allows you add some nice features to your report.\nFor example, you could choose to add the `NumberSumSubFooter` to your MemPOI report. It will result in an additional line at the end of the sheet containing the sum of the numeric columns. This is an example:\n\n```Java\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                    .withWorkbook(workbook)\n                    .withFile(fileDest)\n                    .addMempoiSheet(new MempoiSheet(prepStmt))\n                    .withMempoiSubFooter(new NumberSumSubFooter())\n                    .build();\n```\n\nList of available subfooters:\n\n- **NumberSumSubFooter**: places a cell containing the sum of the column (works only on numeric comlumns)\n- **NumberMaxSubFooter**: places a cell containing the maximum value of the column (works only on numeric comlumns)\n- **NumberMinSubFooter**: places a cell containing the minimum value of the column (works only on numeric comlumns)\n- **NumberAverageSubFooter**: places a cell containing the average value of the column (works only on numeric comlumns)\n\nBy default no footer and no subfooter are appended to the report.\n\nSubfooters are already supported by the MemPOI bundled templates.\n\n**IMPORTANT**: If you want to use a custom subfooter with cell formulas it needs to extend `FormulaSubFooter`\n\n**Accordingly with MS docs: \"Headers and footers are not displayed on the worksheet in Normal view — they are displayed only in Page Layout view and on the printed pages\"**\n\n---\n\n### Cell formulas\n\nYou can specify subfooter's cell formulas by applying a bundled subfooter or creating a custom one.\nBy default MemPOI attempts to postpone formulas evaluation by forcing Excel to evaluate them when it opens the report file.\nThis approach could fail if you use LibreOffice or something similar to open your report file (it could not evaluate formulas opening the document). So by setting `MempoiBuilder.evaluateCellFormulas` to `true` you can avoid this behaviour forcing MemPOI to evaluate cell formulas by itself.\n\nBut depending on which type of `Workbook` you are using you could encounter problems by following this way.\nFor example if you use an `SXSSFWorkbook` and your report is huge, some of your data rows maybe serialized and when MemPOI will try to evaluate cell formulas it will fail.\nFor this reason MemPOI tries to firstly save the report to a temporary file, then reopening it without using `SXSSFWorkbook`, applying cell formulas and continuing with the normal process.\n\nAlso this approach may fail because of that not using a `SXSSFWorkbook` will create a lot of memory problems if the dataset is huger than what the memory heap can support.\nTo solve this issue you could extend your JVM heap memory with the option `-Xmx2048m`\n\nSo actually the best solution for huge dataset is to force Excel to evaluate cell formulas when the report is open.\n\n---\n\n### Excel Table\n\nYou can ask MemPOI to create an Excel Table by using the same builder pattern. Keep in mind that only XSSF supports Excel Table.\nAn Excel Table is related to a sheet, so you have to create the MempoiTable object and then set it into the desired MempoiSheet as follows:\n\n```Java\nMempoiTableBuilder mempoiTableBuilder = MempoiTableBuilder.aMempoiTable()\n                .withWorkbook(workbook)\n                .withTableName(\"MyTable\")\n                .withDisplayTableName(\"MyTableName\")\n                .withAreaReferenceSource(\"A1:F100\");\n\nMempoiSheet mempoiSheet = MempoiSheetBuilder.aMempoiSheet()\n                .withWorkbook(workbook)\n                .withPrepStmt(prepStmt)\n                .withMempoiTableBuilder(mempoiTableBuilder)\n                .build();\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                .withWorkbook(workbook)\n                .withFile(fileDest)\n                .addMempoiSheet(mempoiSheet)\n                .build();\n```\n\nYou can also ask MemPOI to manage Excel Table area reference for you, adding all sheet data to the table by setting to true the variable `allSheetData` as follows:\n\n```Java\nMempoiTableBuilder mempoiTableBuilder = MempoiTableBuilder.aMempoiTable()\n                .withWorkbook(workbook)\n                .withTableName(\"MyTable\")\n                .withDisplayTableName(\"MyTableName\")\n                .withAllSheetData(true);\n```\n\nAuto filters will be automatically enabled.\n\n---\n\n### Excel Pivot Table\n\nMemPOI also supports Excel Pivot Table.  Keep in mind that only XSSF supports Excel Pivot Table.\nHere is a basic example:\n\n```Java\nMempoiPivotTableBuilder mempoiPivotTableBuilder = MempoiPivotTableBuilder.aMempoiPivotTable()\n                .withWorkbook(workbook)\n                .withAreaReferenceSource(\"A1:F100\")\n                .withPosition(new CellReference(\"H1\"));\n\nMempoiSheet mempoiSheet = MempoiSheetBuilder.aMempoiSheet()\n                .withSheetName(\"Nice sheet\")\n                .withPrepStmt(prepStmt)\n                .withMempoiPivotTableBuilder(mempoiPivotTableBuilder)\n                .build();\n```\n\n#### Pivot Table source\n\nYou can specify one source for the pivot table choosing from:\n- explicit area reference (in this case you can also specify a source sheet if different from the one in which place the pivot table)\n- a previously generated table (the table's sheet will be used as source sheet)\n\nUnfortunately Apache POI actually doesn't support table as source for a pivot table.\nMemPOI makes an abstraction that is only able to extract the table area reference and use it as source for the upcoming pivot table.\nThis means that if you open the generated excel file, you move the source table and update the pivot table, it will not be able to keep data consistency\n\nHere an example with area reference source on different sheet:\n\n```Java\nMempoiSheet mempoiSheet1 = MempoiSheetBuilder.aMempoiSheet()\n                .withSheetName(\"Oh sheet!\")\n                .withPrepStmt(prepStmt)\n                .build();\n\nMempoiPivotTableBuilder mempoiPivotTableBuilder = MempoiPivotTableBuilder.aMempoiPivotTable()\n                .withWorkbook(workbook)\n                .withMempoiSheetSource(mempoiSheet1)\n                .withAreaReferenceSource(\"A1:F100\")\n                .withPosition(new CellReference(\"H1\"));\n\nMempoiSheet mempoiSheet2 = MempoiSheetBuilder.aMempoiSheet()\n                .withSheetName(\"Second sheet\")\n                .withPrepStmt(prepStmt2)\n                .withMempoiPivotTableBuilder(mempoiPivotTableBuilder)\n                .build();\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n                .withWorkbook(workbook)\n                .withFile(fileDest)\n                .addMempoiSheet(mempoiSheet1)       // NOTE THAT SHEETS ORDER IS IMPORTANT\n                .addMempoiSheet(mempoiSheet2)\n                .build();\n```\n\nHere an example with table source:\n\n```Java\nMempoiTable mempoiTable = MempoiTableBuilder.aMempoiTable()\n                .withWorkbook(workbook)\n                .withTableName(\"MyTable\")\n                .withDisplayTableName(\"MyTableName\")\n                .withAreaReferenceSource(\"A1:F100\")\n                .build();\n\nMempoiPivotTableBuilder mempoiPivotTableBuilder = MempoiPivotTableBuilder.aMempoiPivotTable()\n                .withWorkbook(workbook)\n                .withMempoiTableSource(mempoiTable)\n                .withPosition(new CellReference(\"H1\"));\n\nMempoiSheet mempoiSheet = MempoiSheetBuilder.aMempoiSheet()\n                .withSheetName(\"Pets\")\n                .withPrepStmt(prepStmt)\n                .withMempoiTable(mempoiTable)\n                .withMempoiPivotTableBuilder(mempoiPivotTableBuilder)\n                .build();\n```\n\n#### Pivot Table filters and labels\n\nYou can specify row labels, column labels and report filters by passing the list of relative column names (in case of db queries that use AS clause you should use AS clause values):\n\n```Java\nEnumMap\u003cDataConsolidateFunction, List\u003cString\u003e\u003e columnLabelColumnsMap = new EnumMap\u003c\u003e(DataConsolidateFunction.class);\ncolumnLabelColumnsMap.put(DataConsolidateFunction.SUM, Arrays.asList(\"sum\"));\ncolumnLabelColumnsMap.put(DataConsolidateFunction.AVERAGE, Arrays.asList(\"average\"));\n\nList\u003cString\u003e rowLabelColumnList = Arrays.asList(\"name\", \"surname\");\n\nList\u003cString\u003e reportFilterColumnList = Arrays.asList(\"address\", \"city\");\n\nMempoiPivotTableBuilder mempoiPivotTableBuilder = MempoiPivotTableBuilder.aMempoiPivotTable()\n                 .withWorkbook(workbook)\n                 .withAreaReferenceSource(\"A1:F100\")\n                 .withPosition(new CellReference(\"H1\"))\n                 .withRowLabelColumns(rowLabelColumnList)\n                 .withColumnLabelColumns(columnLabelColumnsMap)\n                 .withReportFilterColumns(reportFilterColumnList);\n```\n\n---\n\n### Metadata\n\nStarting by v1.7.0 MemPOI returns an object as the result of the generation: `MempoiReport`.\nIt comes populated with the report data, as shown in the first steps of this readme, and with a lot of useful metadata about the generated document.\nIn this way you can apply every desired transformation by being informed on where to place your new data.\n\nMetadata are packed in the `MempoiSheetMetadata`. `MempoiReport` contains a map of these classes (one for each sheet), where the key is the sheet index inside the workbook and the value is the metadata class instance itself.\n\nFor example you could add a custom footer and, in order to decide on which line your footer should start on, you could leverage the `MempoiSheetMetadata.totalRows` property.\n\nBelow a table describing supported metadata\n\n| Property name               |      Description            | Nullable |\n|-----------------------------|-----------------------------|----------|\n| spreadsheetVersion | the version of the spreadsheet | No\n| sheetName | name of the represented sheet | Yes\n| sheetIndex | index of the represented sheet | No\n| totalRows | total number of rows interested by the generated data\u003cbr /\u003ethe count starts at row 0 and goes until the last row (included) with at least one populated cell | No\n| simpleTextHeaderRowIndex | index of the row containing the simple text header | Yes\n| simpleTextFooterRowIndex | index of the row containing the simple text footer | Yes\n| headerRowIndex | index of the row containing column headers | No\n| totalDataRows | total number of rows containing plain exported data (no pivot tables or other). it coincides with resultSet size | No\n| firstDataRow | index of the first row that contains plain exported data (no pivot tables or other) | No\n| lastDataRow | index of the last row that contains plain exported data (no pivot tables or other) | No\n| subfooterRowIndex | index of the row containing the subfooter | Yes\n| totalColumns | total number of columns interested by the generated data\u003cbr /\u003ethe count starts at column 0 and goes until the last column (included) with at least one populated cell | No\n| colsOffset | the offset applied from the left before starting the export | No (Default 0)\n| rowsOffset | the offset applied from the top before starting the export | No (Default 0)\n| firstDataColumn | index of the first column that contains plain exported data | No\n| lastDataColumn | index of the last column that contains plain exported data | No\n| firstTableRow | index of the first row that contains a table | Yes\n| lastTableRow | index of the last row that contains a table | Yes\n| firstTableColumn | index of the first column that contains a table | Yes\n| lastTableColumn | index of the last column that contains a table | Yes\n| firstPivotTablePositionRow | index of the first row that contains a pivot table | Yes\n| firstPivotTablePositionColumn | index of the first column that contains a pivot table | Yes\n| firstPivotTableSourceRow | index of the first row that contains a pivot table | Yes\n| lastPivotTableSourceRow | index of the last row that contains a pivot table | Yes\n| firstPivotTableSourceColumn | index of the first column that contains a pivot table | Yes\n| lastPivotTableSourceColumn | index of the last column that contains a pivot table | Yes\n\n---\n\n### Column Configuration\n\nMemPOI 1.5 introduces the concept of column configuration, allowing the user to add some column specific configurations.\nThe binding is made throughout column name and currently 2 configuration are supported: column cell style and data transformation functions\n\nHere is a basic example to create an empty column configuration for the column \"name\":\n\n```Java\nMempoiColumnConfig mempoiColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"name\")\n        .build();\n\nMempoiSheet mempoiSheet = MempoiSheetBuilder.aMempoiSheet()\n        .withPrepStmt(prepStmt)\n        .addMempoiColumnConfig(mempoiColumnConfig)\n        .build();\n```\n\nAs you can see, you add your desired `MempoiColumnConfig`s to the `MempoiSheet`, then MemPOI at runtime will search for the column identified by the name supplied and apply to it the desired customizations.\n\n#### Column cell style\n\nUp to v1.4 MemPOI applies cell styles basing on data type, from v1.5 you can supply custom cell styles that will be applied to particular columns.\nLook at the following example:\n\n```Java\nCellStyle nameColumnCellStyle = workbook.createCellStyle();\n        nameColumnCellStyle.setFillForegroundColor(IndexedColors.AQUA.getIndex());\n        nameColumnCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);\n\nMempoiColumnConfig mempoiColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(MempoiColumnConfigTestHelper.COLUMN_NAME)\n        .withCellStyle(nameColumnCellStyle)\n        .build();\n```\n\nThis will result in having the entire \"name\" column with an aqua background.\n\n---\n\n#### Data transformation functions\n\nIn certain situations could be necessary to apply a transformation to the data read from the DB. For example, you may want to write a custom string if a null value is received or more simply you may want to map a data type to another.\nTo address these situations, MemPOI v1.5 introduces data transformation functions, that rely on 4 principles:\n\n- bound to a specific column\n- supplied by the user\n- receives one of the Apache POI supported data types (`String`, `Double`, `Boolean`, `Date`) and returns the same type or another one of them\n- executed for each value of the selected column, just before the write to the Apache POI workbook operation\n\nMemPOI provides 4 types of data transformation functions, which reflect the data types supported by Apache POI:\n\n- `StringDataTransformationFunction` receives a String (data read from the DB and cast to String)\n- `DoubleDataTransformationFunction` receives a number (data read from the DB cast to Double)\n- `BooleanDataTransformationFunction` receives a Boolean (data read from the DB cast to Boolean)\n- `DateDataTransformationFunction` receives a Date (data read from the DB and cast to Date)\n\nA data transformation function can return whatever you want but in the set of data types supported by Apache POI, so again `String`, `Double`, `Boolean` or `Date`.\n\nIn the following example, we are returning \"NO NAME\" if the value read by the \"name\" column is `null`.\nPlease note that in order to receive `null` values within data transformation functions you must set [nullValuesOverPrimitiveDetaultOnes](#null-values-over-primitives-default-ones) to `true`.\n\n```Java\nMempoiColumnConfig mempoiColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"name\")\n        .withDataTransformationFunction(new StringDataTransformationFunction\u003cString\u003e() {\n            @Override\n            public String transform(final ResultSet rs, String value) throws MempoiException {\n                return null == value\n                    ? \"NO NAME\"\n                    : value;\n            }\n        })\n        .build();\n\nMempoiSheet mempoiSheet = MempoiSheetBuilder.aMempoiSheet()\n        .withPrepStmt(prepStmt)\n        .addMempoiColumnConfig(mempoiColumnConfig)\n        .build();\n```\n\nIn the following example we are changing data type to Integer:\n\n```Java\nMempoiColumnConfig mempoiColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"name\")\n        .withDataTransformationFunction(new StringDataTransformationFunction\u003cInteger\u003e() {\n            @Override\n            public Integer transform(final ResultSet rs, String value) throws MempoiException {\n                return 999;\n            }\n        })\n        .build();\n```\n\nIn some particular cases, you need to transform the data based on the current SQL statement values, for this reason, the current ResultSet is provided among the transformation params.\n\n```Java\nMempoiColumnConfig mempoiColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n    .withColumnName(\"name\")\n    .withDataTransformationFunction(new StringDataTransformationFunction\u003cString\u003e() {\n        @Override\n        public String transform(final ResultSet rs, String value) throws MempoiException {\n            try {\n                if (rs.getBoolean(\"valid\")){\n                    return value + \" validated\";\n                } else{\n                    return value;\n                }\n            } catch (SQLException e) {\n              throw new MempoiException(e);\n            }\n        }\n    })\n    .build(); \n```\n\n!!! BE AWARE !!! THIS IS AN ADVANCED FEATURE: EVERY ACTION MADE ON THE RESULTSET MAY INVALIDATE RESULTING DATA\n\n---\n\n#### Column header customization\n\nIf you need to change the column header display name without changing the SQL statement, you can configure the display name by setting the display name configuration.\n\nThe display name is only used to populate the column header cell value.\n\nIn this following example we want to configure an Excel sheet from this query\n\n```sql\nSELECT username, fname, lname, comment FROM person \n```\n\nAnd expect this result\n\n| username | First name | Last name | |   \n|----------|------------|-----------|-------| \n|demo | Demo | MEMPOI | Comment in column without title | \n\nIn this example :\n- The selected column 'username' doesn't need a custom configuration\n- The selected column 'fname' needs a custom configuration to display \"First name\"\n- The selected column 'lname' needs a custom configuration to display \"Last name\"\n- The selected column 'comment' needs a custom configuration to display an empty text\n\n```Java\n\nMempoiColumnConfig firstNameConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"fname\")\n        .withColumnDisplayName(\"First name\")\n        .build();\n\nMempoiColumnConfig lastNameConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"lname\")\n        .withColumnDisplayName(\"Last name\")\n        .build();\n\nMempoiColumnConfig commentWithoutHeaderTextConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"comment\")\n        .withColumnDisplayName(\"\")\n        .build();\n\nMempoiSheet mempoiSheet = MempoiSheetBuilder.aMempoiSheet()\n        .withPrepStmt(\"SELECT username, fname, lname, comment FROM person \")\n        .addMempoiColumnConfig(firstNameConfig)\n        .addMempoiColumnConfig(lastNameConfig)\n        .build();\n``` \n\nThanks to [bdzzaid](https://github.com/bdzzaid)\n\n---\n\n### Ignore Columns\n\nIf your query includes more fields than what you need, you can configure MemPOI to skip them.\nThe configuration takes place within the `MempoiColumnConfig`, here is an example:\n\n```Java\nPreparedStatement prepStmt = conn.prepareStatement(\"SELECT id, creation_date AS WONDERFUL DATE, \" \n        + \"dateTime, timeStamp, name, valid, usefulChar, decimalOne FROM test_table\");\n\nMempoiColumnConfig dateTimeColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"dateTime\")\n        .withIgnoreColumn(true)\n        .build();\n\nMempoiColumnConfig timeStampColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"timeStamp\")\n        .withIgnoreColumn(true)\n        .build();\n\nMempoiSheet mempoiSheet = MempoiSheetBuilder.aMempoiSheet()\n        .withPrepStmt(prepStmt)\n        .withMempoiColumnConfigList(Arrays.asList(dateTimeColumnConfig, timeStampColumnConfig))\n        .build();\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n    .addMempoiSheet(mempoiSheet)\n    .build();\n```\n\nThe generated file will not contain the `dateTime` and the `timeStamp` columns, as you can see in the image below.\n\n![](img/ignore-columns.png)\n\n---\n\n### Rearrange Columns\n\nIf your query specify a field order not respecting your requirements, you can configure MemPOI to rearrange them.\nColumns with an explicit order are placed at the beginning, ordered by their `positionOrder` value.\nThen the remaining columns are added in the same order in which they are met\n\nLook at the example below:\n\n```Java\nPreparedStatement prepStmt = conn.prepareStatement(\"SELECT id, creation_date AS WONDERFUL DATE, \" \n        + \"dateTime, timeStamp, name, valid, usefulChar, decimalOne FROM test_table\");\n\nMempoiColumnConfig decimalOneColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"decimalOne\")\n        .withPositionOrder(0)\n        .build();\n\nMempoiColumnConfig dateTimeColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"dateTime\")\n        .withPositionOrder(1)\n        .build();\n\nMempoiColumnConfig validColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"valid\")\n        .withPositionOrder(2)\n        .build();\n\nMempoiColumnConfig usefulCharColumnConfig = MempoiColumnConfigBuilder.aMempoiColumnConfig()\n        .withColumnName(\"usefulChar\")\n        .withIgnoreColumn(true)\n        .build();\n\nList\u003cMempoiColumnConfig\u003e mempoiColConfig = Arrays.asList(decimalOneColumnConfig, dateTimeColumnConfig,\n        validColumnConfig, usefulCharColumnConfig);\n\nMempoiSheet mempoiSheet = MempoiSheetBuilder.aMempoiSheet()\n        .withPrepStmt(prepStmt)\n        .withMempoiColumnConfigList(mempoiColConfig)\n        .build();\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n    .addMempoiSheet(mempoiSheet)\n    .build();\n```\n\nThe generated file will contain the all the columns but `usefulChar`, and the order is the one reported in the image below.\n\n![](img/rearrange-columns.png)\n\n---\n\n### Encryption\n\nSince v1.5 MemPOI supports encryption of workbooks, both for binary and xml-based files.\nAs shown in this example, to encrypt a document you must provide at least the password, MemPOI will automatically apply the `EncryptionMode.agile`:\n\n```Java\nMempoiEncryption mempoiEncryption = MempoiEncryption.MempoiEncryptionBuilder.aMempoiEncryption()\n        .withPassword(\"my_password\")\n        .build();\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n        .withFile(fileDest)\n        .addMempoiSheet(new MempoiSheet(prepStmt))\n        .withMempoiEncryption(mempoiEncryption)\n        .build();\n```\n\nOptionally you can set the `EncryptionInfo` to use in the encryption process.\nWhen MemPOI receives an `EncryptionInfo`, it passes the information directly to the Apache POI API, without applying any customization to the encryption process.\n\n```Java\nMempoiEncryption mempoiEncryption = MempoiEncryption.MempoiEncryptionBuilder.aMempoiEncryption()\n        .withPassword(\"my_password\")\n        .withEncryptionInfo(new EncryptionInfo(EncryptionMode.cryptoAPI)\n        .build();\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n        .withFile(fileDest)\n        .addMempoiSheet(new MempoiSheet(prepStmt))\n        .withMempoiEncryption(mempoiEncryption)\n        .build();\n```\n\nMemPOI encryption relies on the Apache POI one, so it obeys every [rule defined by Apache POI APIs](https://poi.apache.org/encryption.html).\n\n---\n\n### Null values over primitives default ones\n\nApache POI receives primitive data type in its `Cell.setCellValue` when dealing with numbers and booleans, so passing a null value read from the DB to the cell will result in the primitive default value (0.0 for double, false for boolean and so on).\nMemPOI v1.5 introduces the possibility to keep `null` values when read from DB, by setting the property `nullValuesOverPrimitiveDetaultOnes` of the MemPOI object to `true`.\nIn this case, cells that read a `null` value from the DB will be blank:\n\n```Java\nMempoiBuilder.aMemPOI()\n        .addMempoiSheet(new MempoiSheet(prepStmt))\n        .withNullValuesOverPrimitiveDetaultOnes(true)\n        .build();\n```\n\n---\n\n### Data post elaboration pipeline\n\nIn some cases it's useful to have a way to make a data elaboration after the export file is generated. A good example could be the creation of \u003ca href=\"https://poi.apache.org/components/spreadsheet/quick-guide.html#MergedCells\"\u003emerged regions\u003c/a\u003e.\nFor this reason MemPOI introduces the `Data post elaboration system`. The main concept resides in the list of `MempoiColumnElaborationStep` added to the `MempoiColumn` class.\n\nThe elaboration consists of 2 phases: analyzing data and applying transformation based on previously collected data.\nThis is the working process:\n\n- after each row is added to each sheet -\u003e analyze and collect data\n- after the last row is added to each sheet -\u003e close analysis making some final operations\n- after data export completion -\u003e apply data transformations\n\nYou can create your own `Data post elaboration system`'s implementation by 2 ways:\n\n- implementing the base interface `MempoiColumnElaborationStep`\n- extending the abstract class `StreamApiElaborationStep`\n\n#### MempoiColumnElaborationStep\n\nThis represents the base functionality and defines the methods you should implement to manage your desired data post elaboration flow.\nYou can find an example in `NotStreamApiMergedRegionsStep`.\n\n#### StreamApiElaborationStep\n\nThis class supplies some basic implementations to deal with \u003ca href=\"https://poi.apache.org/components/spreadsheet/how-to.html#sxssf\"\u003eApache POI stream API\u003c/a\u003e.\nThen you have to implement, as for `MempoiColumnElaborationStep`, the interface logic methods.\nYou can find an example in `StreamApiMergedRegionsStep`.\n\n#### Differences\n\nThe main difference resides in the underlying Apache POI system, so it is a good practice to use the right implementation depending on the used `Workbook` implementation.\nHowever we could list some behaviors:\n\n*MempoiColumnElaborationStep*\n- it should be used with `HSSF` or `XSSF`\n- it should access the generated `Workbook` as all in memory =\u003e document too large could saturate your memory causing an error\n- memory is never flushed\n\n*StreamApiElaborationStep*\n- it should be used with `SXSSF`\n- it should access only a portion of the generated `Workbook` keeping in mind that at each time only a subset of the created rows are loaded in memory\n- you could find your desired configuration for the workbook's `RandomAccessWindowSize` property or you could try with its default value.\n- memory is flushed in order to keep only a subset of the generated rows in memory\n- memory flush mechanism is automated but it is a fragile mechanism, as reported by Apache POI doc, so it has to be used carefully\n\n#### Adding data post elaboration steps\n\nYou can add as many steps as you want as follows:\n\n```Java\nMempoiSheetBuilder.aMempoiSheet()\n           .withSheetName(\"Multiple steps\")\n           .withPrepStmt(prepStmt)\n           .withDataElaborationStep(\"name\", step1)\n           .withDataElaborationStep(\"usefulChar\", step2)\n           .withDataElaborationStep(\"name\", step3);\n```\n\nNote that you can add more than one step on each column. Keep in mind that order matters: for each column, steps will be executed in the added order so be careful.\nBuilt-in steps (like Merged Regions) will be added firstly. If you want to change this behavior you could configure them without using built-in functionalities.\n\nFor example both the following codes will result in executing merged regions step and then the custom one:\n\n```Java\nMempoiSheetBuilder.aMempoiSheet()\n           .withSheetName(\"Multiple steps\")\n           .withPrepStmt(prepStmt)\n           .withMergedRegionColumns(new String[]{\"name\"})\n           .withDataElaborationStep(\"name\", customStep);\n```\n\n```Java\nMempoiSheetBuilder.aMempoiSheet()\n           .withSheetName(\"Multiple steps\")\n           .withPrepStmt(prepStmt)\n           .withDataElaborationStep(\"name\", customStep)\n           .withMergedRegionColumns(new String[]{\"name\"});\n```\n\nBut this one will execute firstly the custom step and then the merged regions one:\n\n```Java\nMempoiSheetBuilder.aMempoiSheet()\n           .withSheetName(\"Multiple steps\")\n           .withPrepStmt(prepStmt)\n           .withDataElaborationStep(\"name\", customStep)\n           .withDataElaborationStep(\"name\", new NotStreamApiMergedRegionsStep\u003c\u003e(columnList.get(colIndex).getCellStyle(), colIndex));\n```\n\n#### Merged Regions\n\nCurrently MemPOI supplies only one `Data post elaboration system`'s step in order to ease merged regions management.\nAll you have to do is to pass a String array to the `MempoiSheetBuilder` representing the list of columns to merge.\n\n```Java\nString[] mergedColumns = new String[]{\"name\"};\n\nMempoiSheet mempoiSheet = MempoiSheetBuilder.aMempoiSheet()\n    .withSheetName(\"Merged regions name column 2\")\n    .withPrepStmt(prepStmt)\n    .withMergedRegionColumns(mergedColumns)\n    .withStyleTemplate(new RoseStyleTemplate())\n    .build();\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n    .withFile(fileDest)\n    .withStyleTemplate(new ForestStyleTemplate())\n    .withWorkbook(new HSSFWorkbook())\n    .addMempoiSheet(mempoiSheet)\n    .build();\n\nmemPOI.prepareMempoiReport().get();\n```\n\n---\n\n### Column and Row offsets\n\nYou could want to apply a vertical or horizontal offset to the generated data, for example, aiming to enrich your document after the generation.\nTo let the user achieve this goal, MemPOI supports columns and rows offsets.\nThe below code will add:\n- vertical offset of 6 rows: exported data (header included) will start at row 7\n- horizontal offset of 3 columns: exported data will start at column 4\n\n```Java\nMempoiSheet mempoiSheet = MempoiSheetBuilder.aMempoiSheet()\n    .withPrepStmt(prepStmt)\n    .withRowsOffset(6)\n    .withColumnsOffset(3)\n    .build();\n\nMemPOI memPOI = MempoiBuilder.aMemPOI()\n    .withFile(fileDest)\n    .withAdjustColumnWidth(true)\n    .addMempoiSheet(mempoiSheet)\n    .build();\n```\n\nThe execution of the code above will result in the following export:\n\n![](img/offsets.png)\n\n---\n\n### Spring Framework example\n\nHere you can find a simple example project explaining how you can easily integrate MemPOI within Spring Framework: [MemPOI-Spring-Example](https://github.com/firegloves/MemPOI-Spring-Example)\n\n---\n\n### Force Generation\n\nMemPOI 1.2 introduces the `forceGeneration` property that helps you to ignore some errors, if possible.\nForce Generation is still experimental, here a temp list of the managed errors:\n\n- Specifying as sources for a Table an area reference and all sheet data, all sheet data takes precedence and the area reference will be ignored\n- Specifying no source for a Table will force the table to use all sheet data as a source\n- Specifying 2 sources for a PivotTable (one area reference and one table) the area reference takes precedence and the table is ignored\n- Specifying 2 sheet sources for a PivotTable (one sheet and one table) the table takes precedence and the sheet is ignored\n- If a post data elaboration step is added to a MempoiSheet after have set a null step map, the map is instantiated and the step added\n- Specifying a negative column or row offset will force it to 0\n\n---\n\n### Performance\n\nSince you might have to face foolish requests like exporting hundreds of thousands of rows in a few seconds, I added some speed tests.\nThere are 2 options that may dramatically slow down generation process on huge datasets:\n\n- `adjustColumnWidth`\n- `evaluateCellFormulas`\n\nBoth available into `MempoiBuilder` they could block your export or even make it fail.\nKeep in mind that if you can't use them for performance problems you could ask in exchange for speed that columns resizing and cell formula evaluations will be hand made by the final user.\n\nThe best performance choice between the available `Workbook` descendants is the `SXSSFWorkbook`.\n\n---\n\n### Sync VS Async\n\nMemPOI returns always a CompletableFuture so you can use it synchronously or asynchronously, depending on the requirement.\nIn the previous examples you can see how to block an async operation by calling the `get()` method, but using an appropriate environment (e.g. Spring Reactor, Akka or Vert.x) you can choose your favourite approach.\n\n---\n\n### Error handling\n\nDepending on the use of `CompletableFuture` usage, MemPOI can throw 2 different exceptions: `ExecutionException` and `CompletionException`, both containing a MempoiException accessible with `e.getCause()`.\nAccording to `CompletableFuture` you'll receive an `ExecutionException` if you call `CompletableFuture`'s `get()` method, whereas you'll receive a `CompletionException` if you call `CompletableFuture`'s `join()` method.\n\n---\n\n### Logging\n\nLogging is served through [SLF4J](http://www.slf4j.org/), leaving the logging configuration to the user and ensuring maximum flexibility.\n\nThanks to [zaplatynski](https://github.com/zaplatynski)\n\n---\n\n### Vulnerable dependency management\n\nStarting from v1.9.0, MemPOI pays particular attention to the dependency vulnerabilities and comes bundled with an enhanced version of Apache POI, where transitive and vulnerable dependencies are updated to the safest available versions.\nBy clicking on the Snyk badge you can inspect the relative security report.\n\n---\n\n### Apache POI version\n\nMemPOI comes with Apache POI 5.2.2 bundled. If you need to use a different version you can exclude the transitive dependency specifying your desired version.\n\n#### This is an example using Gradle:\n\n```Groovy\nimplementation (group: 'it.firegloves', name: 'mempoi', version: '1.10.1') {\n   exclude group: 'org.apache.poi', module: 'poi-ooxml'\n}\n\nimplementation group: 'org.apache.poi', name: 'poi-ooxml', version: '4.0.1'\n```\n\n#### This is an example using Maven:\n\n```XML\n\u003cdependency\u003e\n    \u003cgroupId\u003eit.firegloves\u003c/groupId\u003e\n    \u003cartifactId\u003emempoi\u003c/artifactId\u003e\n    \u003cversion\u003e1.10.1\u003c/version\u003e\n    \u003cexclusions\u003e\n        \u003cexclusion\u003e\n            \u003cgroupId\u003eorg.apache.poi\u003c/groupId\u003e\n            \u003cartifactId\u003epoi-ooxml\u003c/artifactId\u003e\n        \u003c/exclusion\u003e\n    \u003c/exclusions\u003e\n\u003c/dependency\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003eorg.apache.poi\u003c/groupId\u003e\n    \u003cartifactId\u003epoi-ooxml\u003c/artifactId\u003e\n    \u003cversion\u003e4.0.1\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n---\n\n### Contributing\n\nFeel free to contribute. The easiest way could be adding new templates, sub footers or data post elaboration steps.\nLook at the [contributing file](docs/CONTRIBUTING.md) to go deeper!\n\n---\n\n### Donate crypto\n\nMemPOI joined [Cardano](https://cardano.org/)'s vision and encourages cooperation over competition, sustainability over resource consumption.\n\nMemPOI joined [Brave](https://brave.com/)'s vision of protecting your privacy to keep the web a clean and safe place.\n\n### :tropical_drink: :tropical_drink: :tropical_drink:\nIf MemPOI has saved you precious time, you could reciprocate by offering me a good drink!\n### :tropical_drink: :tropical_drink: :tropical_drink:\n\nCardano wallet address: `addr1q84u2lkc22ec78d84nyggxea6s53tlh4lzuznrqf82qptvl0ryqgdg3fvrcnur6sjweg7jcgjj958x2zxavpcu6hrq7qavr0n6`\n\n![](img/crypto/cardano-wallet-qrcode.png)\n\n---\n\n#### Special thanks\n\nSpecial thanks to \u003ca href=\"http://www.collederfomento.net/\" target=\"_blank\"\u003eColle der Fomento\u003c/a\u003e that inspired MemPOI name with their new, fantastic, yearned LP, in particular with their song \u003ca href=\"https://youtu.be/xy05iaknmcY\" target=\"_blank\"\u003eMempo\u003c/a\u003e.\n\nDon't you know what I'm talking about? Discover what a \u003ca href=\"https://en.wikipedia.org/wiki/Men-yoroi\" target=\"_blank\"\u003emempo\u003c/a\u003e is!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffiregloves%2Fmempoi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffiregloves%2Fmempoi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffiregloves%2Fmempoi/lists"}