Skip to content

excel-ninja/excel-ninja-toolkit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

96 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ExcelNinja πŸ₯·

ExcelNinja Logo

ExcelNinja is a lightweight, modern Java library that makes Excel file handling as swift and precise as a ninja's blade.
Built on top of Apache POI, it provides a clean, annotation-driven API for seamless conversion between Java Object and Excel documents.


Key Features

  • Simple & Intuitive: One-line reads and writes with automatic type conversion
  • Annotation-Driven: Map Excel columns to DTO fields using @ExcelReadColumn and @ExcelWriteColumn
  • Bidirectional: Read Excel β†’ DTO lists, Write DTO lists β†’ Excel
  • ️Type-Safe: Built-in validation with domain-driven value objects
  • ️Modern Architecture: Clean hexagonal architecture with proper separation of concerns
  • Performance Logging: Built-in performance metrics and detailed logging
  • Java 8+ Compatible: Works with Java 8 and above

Quick Start

Gradle Dependency

dependencies {
    implementation 'io.github.excel-ninja:excelNinja:1.0.2'
}

Zero Configuration Required
ExcelNinja bundles all dependencies internally - no need to add Apache POI manually.

Basic Usage

1. Define Your DTO

public class User {
    @ExcelReadColumn(headerName = "ID")
    @ExcelWriteColumn(headerName = "ID", order = 0)
    private Long id;

    @ExcelReadColumn(headerName = "Name")
    @ExcelWriteColumn(headerName = "Name", order = 1)
    private String name;

    @ExcelReadColumn(headerName = "Age")
    @ExcelWriteColumn(headerName = "Age", order = 2)
    private Integer age;

    @ExcelReadColumn(headerName = "Email")
    @ExcelWriteColumn(headerName = "Email", order = 3)
    private String email;

    // Constructors, getters, and setters...
}

2. Read Excel to DTO List

// From file path - reads first sheet
List<User> users = NinjaExcel.read("users.xlsx", User.class);

// From File object - reads first sheet
File file = new File("users.xlsx");
List<User> users = NinjaExcel.read(file, User.class);

// Read specific sheet
List<User> users = NinjaExcel.readSheet("users.xlsx", "Sheet1", User.class);

// Read all sheets
Map<String, List<User>> allSheets = NinjaExcel.readAllSheets("users.xlsx", User.class);

// Get sheet names
List<String> sheetNames = NinjaExcel.getSheetNames("users.xlsx");

// read(), readSheet(), readSheets(), getSheetNames() only parse the sheets they need.

3. Write DTO List to Excel

List<User> users = Arrays.asList(
    new User(1L, "Alice", 28, "alice@example.com"),
    new User(2L, "Bob", 32, "bob@example.com")
);

// Create workbook with single sheet
ExcelWorkbook workbook = ExcelWorkbook.builder()
    .sheet("Users", users)
    .build();

// Write to file
NinjaExcel.write(workbook, "output.xlsx");

// Or write to OutputStream
try (FileOutputStream out = new FileOutputStream("output.xlsx")) {
    NinjaExcel.write(workbook, out);
}

// Multiple sheets
List<Employee> employees = Arrays.asList(/* employee data */);
ExcelWorkbook multiSheet = ExcelWorkbook.builder()
    .sheet("Users", users)
    .sheet("Employees", employees)
    .build();

NinjaExcel.write(multiSheet, "multi-sheet.xlsx");

Advanced Features

Custom Type Conversion

ExcelNinja includes built-in support for common types including LocalDate, numeric strings, and blank-cell defaults:

public class Employee {
    @ExcelReadColumn(headerName = "Hire Date")
    private LocalDate hireDate;
    
    @ExcelReadColumn(headerName = "Salary", defaultValue = "0")
    private Double salary;
    
    // Blank cells use defaultValue when provided.
    // Numeric strings like "123.45" also convert to numeric fields.
    // Supports various date formats automatically:
    // yyyy-MM-dd, dd/MM/yyyy, MM/dd/yyyy, etc.
}

Large File Processing

ExcelNinja automatically switches to streaming mode for large files (>10MB) to optimize memory usage:

// For very large files, read in chunks
try (ChunkReader<User> chunks = NinjaExcel.readInChunks("large-file.xlsx", User.class, 1000)) {
    while (chunks.hasNext()) {
        List<User> chunk = chunks.next();
        // Process chunk
    }
}
// Full iteration closes internal file resources automatically.
// try-with-resources also closes safely when you stop early.

// Read multiple specific sheets
List<String> sheetsToRead = Arrays.asList("Users", "Customers");
Map<String, List<User>> selectedSheets = NinjaExcel.readSheets("workbook.xlsx", User.class, sheetsToRead);

Workbook Builder API

For advanced workbook creation:

// Using builder pattern for complex workbooks
ExcelWorkbook workbook = ExcelWorkbook.builder()
    .sheet("Users", userList)
    .sheet("Products", productList)
    .metadata(new WorkbookMetadata()) // Optional metadata, persisted as workbook core properties
    .build();

// Auto-size is opt-in for write performance on large exports
ExcelSheet sizedSheet = ExcelSheet.builder()
    .name("Users")
    .headers("Name")
    .rows(Collections.singletonList(Collections.singletonList("Alice Johnson")))
    .autoSizeColumns()
    .build();

// Access workbook information
Set<String> sheetNames = workbook.getSheetNames();
ExcelSheet userSheet = workbook.getSheet("Users");
WorkbookMetadata metadata = workbook.getMetadata();

Architecture

ExcelNinja follows clean architecture principles:

πŸ“ Application Layer
β”œβ”€β”€ facade/
β”‚   └── NinjaExcel.java          # Main API facade
└── port/
    └── ConverterPort.java       # Type conversion interface

πŸ“ Domain Layer
β”œβ”€β”€ model/                       # Value objects & domain models
β”‚   β”œβ”€β”€ ExcelWorkbook.java      # Core workbook aggregate
β”‚   β”œβ”€β”€ ExcelSheet.java         # Sheet representation
β”‚   β”œβ”€β”€ Headers.java            # Header management
β”‚   β”œβ”€β”€ DocumentRows.java       # Row collection
β”‚   └── SheetName.java          # Sheet name validation
β”œβ”€β”€ annotation/                  # Column mapping annotations
β”œβ”€β”€ port/                       # Domain ports
β”‚   β”œβ”€β”€ WorkbookReader.java     # Reading interface
β”‚   └── WorkbookWriter.java     # Writing interface
└── exception/                   # Domain-specific exceptions

πŸ“ Infrastructure Layer
β”œβ”€β”€ io/                         # Apache POI & streaming adapters
β”‚   β”œβ”€β”€ PoiWorkbookReader.java  # Standard POI reader
β”‚   β”œβ”€β”€ PoiWorkbookWriter.java  # Standard POI writer
β”‚   └── StreamingWorkbookReader.java # Streaming reader for large files
β”œβ”€β”€ converter/                  # Type conversion implementation
β”œβ”€β”€ metadata/                   # Entity metadata handling
└── util/                       # Reflection utilities

Annotation Reference

@ExcelReadColumn

Maps DTO fields to Excel columns when reading:

@ExcelReadColumn(
    headerName = "Full Name",     // Required: Excel column header
    type = String.class,          // Optional: Override field type
    defaultValue = "Unknown"      // Optional: Default if cell is empty
)
private String name;

@ExcelWriteColumn

Maps DTO fields to Excel columns when writing:

@ExcelWriteColumn(
    headerName = "Employee ID",   // Required: Excel column header
    order = 0                     // Optional: Column order (default: field order)
)
private Long id;

Core Components

Component Description
NinjaExcel Main facade providing read() and write() methods
ExcelWorkbook Workbook representation supporting multiple sheets
@ExcelReadColumn Annotation for Excel β†’ DTO mapping
@ExcelWriteColumn Annotation for DTO β†’ Excel mapping
DefaultConverter Handles type conversion between Excel and Java types

Performance & Logging

ExcelNinja provides detailed performance metrics:

[NINJA-EXCEL] Reading Excel file: users.xlsx (245.2 KB)
[NINJA-EXCEL] Successfully read 1000 records from users.xlsx in 150 ms (6666.67 records/sec)

[NINJA-EXCEL] Writing Excel document with 500 records to output.xlsx
[NINJA-EXCEL] Successfully wrote 500 records to output.xlsx (89.4 KB) in 95 ms (5263.16 records/sec)

Error Handling

ExcelNinja provides comprehensive error handling with descriptive messages:

try {
    List<User> users = NinjaExcel.read("missing.xlsx", User.class);
} catch (DocumentConversionException e) {
    // Detailed error messages for:
    // - File not found
    // - Invalid Excel format
    // - Type conversion failures
    // - Missing headers
    // - Annotation configuration errors
}

Testing

ExcelNinja includes comprehensive test coverage:

  • βœ… Unit tests for all core components
  • βœ… Integration tests for end-to-end workflows
  • βœ… Value object validation tests
  • βœ… Exception handling tests
  • βœ… Performance benchmarks

Run tests with: ./gradlew test


Contributing

We welcome contributions! ExcelNinja is designed to be:

  • Extensible: Easy to add new type converters
  • Maintainable: Clean architecture with proper separation
  • Testable: Comprehensive test coverage
  • Documentation-first: Clear APIs and examples

Development Setup

git clone https://github.com/excel-ninja/excel-ninja-toolkit.git
cd excel-ninja-toolkit
./gradlew build

Contributing Guidelines

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Add tests for your changes
  4. Update documentation if needed
  5. Ensure all tests pass (./gradlew test)
  6. Submit a pull request

πŸ“ License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.


Performance

ExcelNinja is designed for high performance:

  • Automatic Optimization: Files >10MB automatically use streaming (SAX-based) for memory efficiency
  • Metadata Caching: Reflection metadata is cached in a thread-safe LRU cache (max 1000 entries)
  • Chunk Processing: Process large files in configurable chunks (default: 1000 rows)
  • Built-in Metrics: Automatic performance logging (records/sec, file size, duration)

Benchmarks (approximate, depends on hardware):

  • Small files (<10MB): ~5,000-10,000 records/sec (POI mode)
  • Large files (>10MB): ~3,000-8,000 records/sec (Streaming mode)
  • Memory usage: Streaming mode uses ~50-100MB regardless of file size

Notes

  • High-precision BigDecimal values that cannot be represented exactly as Excel numeric cells are written as text to preserve the exact value.

Support

If you find ExcelNinja helpful, please consider:

  • Starring this repository
  • Reporting issues on GitHub Issues
  • Suggesting features
  • Contributing code

For bug reports, please include:

  • ExcelNinja version
  • Java version
  • Sample code or Excel file (if possible)
  • Error messages and stack traces

Made by the ExcelNinja team

"Making Excel handling in Java as swift and precise as a ninja's blade"

About

A comprehensive Java toolkit based on Apache POI for reading, writing, validating, and styling Excel files

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages