SheetMapper is a lightweight and intuitive Java library designed to map rows from a CSV file directly to your Java POJO (Plain Old Java Object) classes. By using a straightforward, annotation-based approach, it eliminates boilerplate code and makes parsing CSV data a breeze.
This library is perfect for projects that need a simple, no-fuss way to handle CSV to Java object mapping. It currently provides robust support for CSV files, with plans to support Excel formats (.xls
, .xlsx
) in the future.
- Annotation-Driven Mapping: Use the
@Column
annotation to link CSV columns to your Java object fields. - Automatic Header Detection: The library automatically reads the header row of your CSV to map columns by name, not by index.
- Extensible Type Conversion: Comes with built-in converters for common Java types (
String
,Integer
,Long
,Double
,Boolean
, and their primitive counterparts). - Custom Converters: Easily register your own
TypeConverter
for custom data types likeLocalDate
,BigDecimal
, or any other class. - Fluent API: A clean and modern API for easy integration.
- Lightweight: Minimal dependencies to keep your project lean.
SheetMapper is available on Maven Central. You can add it to your project using your favorite build tool.
<dependency>
<groupId>io.github.serkankarabulut</groupId>
<artifactId>sheet-mapper</artifactId>
<version>0.1.0</version> <!-- Replace it with the latest version -->
</dependency>
implementation 'io.github.serkankarabulut:sheet-mapper:0.1.0' // Replace with the latest version
Mapping a CSV file to a list of objects is a simple, three-step process.
First, create a Java class that will hold your data. This class must have a no-argument constructor. Use the @Column
annotation on the fields you want to map from the CSV.
- If the
@Column(name = "...")
attribute is set, the library will look for a column with that exact name in the CSV header. - If the
name
attribute is omitted, the library will use the field's name as the column name.
Example User.java
:
import io.github.serkankarabulut.sheetmapper.annotation.Column;
public class User {
@Column(name = "user_id")
private long id;
@Column // Will map to a column named "username"
private String username;
@Column(name = "email_address")
private String email;
@Column(name = "is_active")
private boolean isActive;
// A public no-arg constructor is required
public User() {
}
// Getters and Setters (optional, but good practice)
// ...
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", email='" + email + '\'' +
", isActive=" + isActive +
'}';
}
}
Create a CSV file with a header row that matches the names specified in your @Column
annotations or field names.
Example users.csv
:
user_id,username,email_address,is_active
101,johndoe,john.doe@example.com,true
102,janedoe,jane.doe@example.com,false
103,sammy.s,sam.smith@example.com,true
Use the SheetMapper
class to perform the mapping.
import io.github.serkankarabulut.sheetmapper.SheetMapper;
import io.github.serkankarabulut.sheetmapper.exception.SheetMappingException;
import java.io.File;
import java.util.List;
public class MainApplication {
public static void main(String[] args) {
try {
// Get the file from the resources folder
File csvFile = new File(MainApplication.class.getResource("/users.csv").getFile());
// Create a SheetMapper instance and map the data
List<User> users = SheetMapper.forCsv().map(csvFile, User.class);
// Print the results
users.forEach(System.out::println);
} catch (SheetMappingException e) {
System.err.println("Error mapping the sheet: " + e.getMessage());
e.printStackTrace();
}
}
}
Output:
User{id=101, username='johndoe', email='john.doe@example.com', isActive=true}
User{id=102, username='janedoe', email='jane.doe@example.com', isActive=false}
User{id=103, username='sammy.s', email='sam.smith@example.com', isActive=true}
SheetMapper allows you to handle custom data types or special string formats by registering your own TypeConverter
.
For example, let's say your CSV contains dates in yyyy-MM-dd
format, and you want to map them to java.time.LocalDate
.
1. Update Your POJO:
Add a LocalDate
field to your User.java
class.
// ... inside User.java
import java.time.LocalDate;
public class User {
// ... other fields
@Column(name = "registration_date")
private LocalDate registrationDate;
// ... constructor, getters, setters, etc.
}
2. Update Your CSV:
Add the new column to users.csv
.
user_id,username,email_address,is_active,registration_date
101,johndoe,john.doe@example.com,true,2024-01-15
102,janedoe,jane.doe@example.com,false,2024-03-22
103,sammy.s,sam.smith@example.com,true,2025-07-21
3. Register the Custom Converter:
Create a ConverterRegistry
, register your custom converter for LocalDate
, and pass it to the SheetMapper
.
import io.github.serkankarabulut.sheetmapper.SheetMapper;
import io.github.serkankarabulut.sheetmapper.converter.ConverterRegistry;
import io.github.serkankarabulut.sheetmapper.exception.SheetMappingException;
import java.io.File;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
public class AdvancedMain {
public static void main(String[] args) {
try {
// 1. Create a custom converter registry
ConverterRegistry customRegistry = new ConverterRegistry();
// 2. Define and register your converter for LocalDate
// The TypeConverter interface is a @FunctionalInterface, so you can use a lambda
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
customRegistry.register(LocalDate.class, value -> LocalDate.parse(value, formatter));
// 3. Create a SheetMapper instance with the custom registry
SheetMapper sheetMapper = SheetMapper.forCsv(customRegistry);
// 4. Map as usual
File csvFile = new File(AdvancedMain.class.getResource("/users.csv").getFile());
List<User> users = sheetMapper.map(csvFile, User.class);
users.forEach(System.out::println);
} catch (SheetMappingException e) {
System.err.println("Error mapping the sheet: " + e.getMessage());
e.printStackTrace();
}
}
}
Contributions are always welcome! Whether you find a bug, have a feature request, or want to contribute to the code, please feel free to open an issue or a pull request.
If you find this project useful, please consider giving it a star ⭐!
This project is licensed under the MIT License - see the LICENSE file for details.