Skip to content

Commit

Permalink
Merge branch 'v3.x.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
millij committed Jul 22, 2024
2 parents 87cfd8d + ef7ed01 commit 81ba3ed
Show file tree
Hide file tree
Showing 18 changed files with 875 additions and 95 deletions.
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ This library is available in [Maven Central](https://mvnrepository.com/artifact/
<dependency>
<groupId>io.github.millij</groupId>
<artifactId>poi-object-mapper</artifactId>
<version>3.0.0</version>
<version>3.1.0</version>
</dependency>
```

Expand Down Expand Up @@ -76,12 +76,25 @@ Reading spreadsheet rows as objects ..

```java
...
final File xlsxFile = new File("<path_to_file>");
final File xlsFile = new File("<path_to_file>");
final XlsReader reader = new XlsReader();
final List<Employee> employees = reader.read(Employee.class, xlsxFile);
final List<Employee> employees = reader.read(Employee.class, xlsFile);
...
```

##### Reading Rows as Map (when there is no mapping bean)

Reading spreadsheet rows as `Map<String, Object>` Objects ..

```java
...
final File xlsxFile = new File("<path_to_file>");
final XlsxReader reader = new XlsxReader(); // OR XlsReader as needed
final List<Map<String, Object>> rowObjects = reader.read(xlsxFile);
...
```


##### Writing a collection of objects to file

Similar to `Reader`, the mapped Java Beans can be written to files.
Expand Down
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ sourceCompatibility = 1.11
targetCompatibility = 1.11

group = 'io.github.millij'
version = '3.0.0'
version = '3.1.0'


dependencies {
Expand All @@ -37,6 +37,9 @@ dependencies {
// Test compile
// ----------------------------------------------------------------------------------

testImplementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.19.0'
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j2-impl', version: '2.19.0'

testImplementation group: 'junit', name: 'junit', version: '4.12'

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package io.github.millij.poi.ss.handler;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.github.millij.poi.util.Spreadsheet;


/**
* SheetContentsHandler impl for reading row as {@link Map}
*
* @since 3.1.0
*/
public class RowContentsAsMapHandler extends AbstractSheetContentsHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(RowContentsAsMapHandler.class);

private final RowListener<Map<String, Object>> listener;

private final int headerRowNum;
private final Map<String, String> headerCellRefsMap;

private final int lastRowNum;


// Constructors
// ------------------------------------------------------------------------

public RowContentsAsMapHandler(RowListener<Map<String, Object>> listener, int headerRowNum, int lastRowNum) {
super();

// init
this.listener = listener;

this.headerRowNum = headerRowNum;
this.headerCellRefsMap = new HashMap<>();

this.lastRowNum = lastRowNum;
}


// AbstractSheetContentsHandler Methods
// ------------------------------------------------------------------------

@Override
void beforeRowStart(final int rowNum) {
try {
// Row Callback
listener.beforeRow(rowNum);
} catch (Exception ex) {
String errMsg = String.format("Error calling #beforeRow callback row - %d", rowNum);
LOGGER.error(errMsg, ex);
}
}


@Override
void afterRowEnd(final int rowNum, final Map<String, Object> rowDataMap) {
// Sanity Checks
if (Objects.isNull(rowDataMap) || rowDataMap.isEmpty()) {
LOGGER.debug("INVALID Row data Passed - Row #{}", rowNum);
return;
}

// Skip rows before Header ROW and after Last ROW
if (rowNum < headerRowNum || rowNum > lastRowNum) {
return;
}

// Process Header ROW
if (rowNum == headerRowNum) {
final Map<String, String> headerCellRefs = this.asHeaderNameToCellRefMap(rowDataMap);
headerCellRefsMap.putAll(headerCellRefs);
return;
}

// Check for Column Definitions before processing NON-Header ROWs

// Row As Bean
final Map<String, Object> rowBean = Spreadsheet.rowAsMap(headerCellRefsMap, rowDataMap);
if (Objects.isNull(rowBean)) {
LOGGER.debug("Unable to construct Row data Bean object - Row #{}", rowNum);
return;
}

// Row Callback
try {
listener.row(rowNum, rowBean);
} catch (Exception ex) {
String errMsg = String.format("Error calling #row callback row - %d, bean - %s", rowNum, rowBean);
LOGGER.error(errMsg, ex);
}
}


// Private Methods
// ------------------------------------------------------------------------

private Map<String, String> asHeaderNameToCellRefMap(final Map<String, Object> headerRowData) {
// Sanity checks
if (Objects.isNull(headerRowData) || headerRowData.isEmpty()) {
return new HashMap<>();
}

// Get Bean Column definitions
final Map<String, String> headerCellRefs = new HashMap<String, String>();
for (final String colRef : headerRowData.keySet()) {
final Object header = headerRowData.get(colRef);

final String headerName = Objects.isNull(header) ? "" : String.valueOf(header);
headerCellRefs.put(headerName, colRef);
}

LOGGER.debug("Header Name to Cell Refs : {}", headerCellRefs);
return headerCellRefs;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import io.github.millij.poi.ss.model.Column;
import io.github.millij.poi.util.Spreadsheet;
import io.github.millij.poi.util.Strings;


public class RowContentsHandler<T> extends AbstractSheetContentsHandler {
Expand Down Expand Up @@ -114,7 +115,7 @@ private Map<String, String> asHeaderNameToCellRefMap(final Map<String, Object> h
final Object header = headerRowData.get(colRef);

final String headerName = Objects.isNull(header) ? "" : String.valueOf(header);
final String normalHeaderName = Spreadsheet.normalize(headerName);
final String normalHeaderName = Strings.normalize(headerName);
headerCellRefs.put(normalHeaderName, colRef);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.InputStream;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -72,4 +73,34 @@ public <T> List<T> read(final Class<T> beanClz, final InputStream is, final int
}


//
// Read to Map

@Override
public List<Map<String, Object>> read(final InputStream is) throws SpreadsheetReadException {
// Row Collector
final RowBeanCollector<Map<String, Object>> beanCollector = new RowBeanCollector<>();

// Read with callback to fill list
this.read(is, beanCollector);

// Result
final List<Map<String, Object>> beans = beanCollector.getBeans();
return beans;
}

@Override
public List<Map<String, Object>> read(final InputStream is, final int sheetNo) throws SpreadsheetReadException {
// Row Collector
final RowBeanCollector<Map<String, Object>> beanCollector = new RowBeanCollector<>();

// Read with callback to fill list
this.read(is, sheetNo, beanCollector);

// Result
final List<Map<String, Object>> beans = beanCollector.getBeans();
return beans;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

import io.github.millij.poi.SpreadsheetReadException;
import io.github.millij.poi.ss.handler.RowListener;
Expand Down Expand Up @@ -195,5 +196,58 @@ default <T> List<T> read(Class<T> beanClz, File file, int sheetNo) throws Spread
}


//
// Read to Map

/**
* Reads the spreadsheet file as Generic {@link Map} beans. Note that only the requested sheet (sheet numbers are
* indexed from 0) will be read.
*
* @param is {@link InputStream} of the spreadsheet file
* @param listener Custom {@link RowListener} implementation for row data callbacks.
*
* @throws SpreadsheetReadException when the file data is not readable or row data to bean mapping failed.
*/
void read(InputStream is, RowListener<Map<String, Object>> listener) throws SpreadsheetReadException;

/**
* Reads the spreadsheet file as Generic {@link Map} beans. Note that only the requested sheet (sheet numbers are
* indexed from 0) will be read.
*
* @param is {@link InputStream} of the spreadsheet file
* @param sheetNo index of the Sheet to be read (index starts from 1)
* @param listener Custom {@link RowListener} implementation for row data callbacks.
*
* @throws SpreadsheetReadException when the file data is not readable or row data to bean mapping failed.
*/
void read(InputStream is, int sheetNo, RowListener<Map<String, Object>> listener) throws SpreadsheetReadException;


/**
* Reads the spreadsheet file as Generic {@link Map} beans. Note that only the requested sheet (sheet numbers are
* indexed from 0) will be read.
*
* @param is {@link InputStream} of the spreadsheet file
*
* @return a {@link List} of {@link Map} objects
*
* @throws SpreadsheetReadException when the file data is not readable or row data to bean mapping failed.
*/
List<Map<String, Object>> read(InputStream is) throws SpreadsheetReadException;

/**
* Reads the spreadsheet file as Generic {@link Map} beans. Note that only the requested sheet (sheet numbers are
* indexed from 0) will be read.
*
* @param is {@link InputStream} of the spreadsheet file
* @param sheetNo index of the Sheet to be read (index starts from 1)
*
* @return a {@link List} of {@link Map} objects
*
* @throws SpreadsheetReadException when the file data is not readable or row data to bean mapping failed.
*/
List<Map<String, Object>> read(InputStream is, int sheetNo) throws SpreadsheetReadException;


}

Loading

0 comments on commit 81ba3ed

Please sign in to comment.