Skip to content

Commit 81ba3ed

Browse files
committed
Merge branch 'v3.x.x'
2 parents 87cfd8d + ef7ed01 commit 81ba3ed

18 files changed

+875
-95
lines changed

README.md

+16-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ This library is available in [Maven Central](https://mvnrepository.com/artifact/
2222
<dependency>
2323
<groupId>io.github.millij</groupId>
2424
<artifactId>poi-object-mapper</artifactId>
25-
<version>3.0.0</version>
25+
<version>3.1.0</version>
2626
</dependency>
2727
```
2828

@@ -76,12 +76,25 @@ Reading spreadsheet rows as objects ..
7676

7777
```java
7878
...
79-
final File xlsxFile = new File("<path_to_file>");
79+
final File xlsFile = new File("<path_to_file>");
8080
final XlsReader reader = new XlsReader();
81-
final List<Employee> employees = reader.read(Employee.class, xlsxFile);
81+
final List<Employee> employees = reader.read(Employee.class, xlsFile);
82+
...
83+
```
84+
85+
##### Reading Rows as Map (when there is no mapping bean)
86+
87+
Reading spreadsheet rows as `Map<String, Object>` Objects ..
88+
89+
```java
90+
...
91+
final File xlsxFile = new File("<path_to_file>");
92+
final XlsxReader reader = new XlsxReader(); // OR XlsReader as needed
93+
final List<Map<String, Object>> rowObjects = reader.read(xlsxFile);
8294
...
8395
```
8496

97+
8598
##### Writing a collection of objects to file
8699

87100
Similar to `Reader`, the mapped Java Beans can be written to files.

build.gradle

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ sourceCompatibility = 1.11
1515
targetCompatibility = 1.11
1616

1717
group = 'io.github.millij'
18-
version = '3.0.0'
18+
version = '3.1.0'
1919

2020

2121
dependencies {
@@ -37,6 +37,9 @@ dependencies {
3737
// Test compile
3838
// ----------------------------------------------------------------------------------
3939

40+
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.19.0'
41+
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j2-impl', version: '2.19.0'
42+
4043
testImplementation group: 'junit', name: 'junit', version: '4.12'
4144

4245
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package io.github.millij.poi.ss.handler;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
import java.util.Objects;
6+
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
import io.github.millij.poi.util.Spreadsheet;
11+
12+
13+
/**
14+
* SheetContentsHandler impl for reading row as {@link Map}
15+
*
16+
* @since 3.1.0
17+
*/
18+
public class RowContentsAsMapHandler extends AbstractSheetContentsHandler {
19+
20+
private static final Logger LOGGER = LoggerFactory.getLogger(RowContentsAsMapHandler.class);
21+
22+
private final RowListener<Map<String, Object>> listener;
23+
24+
private final int headerRowNum;
25+
private final Map<String, String> headerCellRefsMap;
26+
27+
private final int lastRowNum;
28+
29+
30+
// Constructors
31+
// ------------------------------------------------------------------------
32+
33+
public RowContentsAsMapHandler(RowListener<Map<String, Object>> listener, int headerRowNum, int lastRowNum) {
34+
super();
35+
36+
// init
37+
this.listener = listener;
38+
39+
this.headerRowNum = headerRowNum;
40+
this.headerCellRefsMap = new HashMap<>();
41+
42+
this.lastRowNum = lastRowNum;
43+
}
44+
45+
46+
// AbstractSheetContentsHandler Methods
47+
// ------------------------------------------------------------------------
48+
49+
@Override
50+
void beforeRowStart(final int rowNum) {
51+
try {
52+
// Row Callback
53+
listener.beforeRow(rowNum);
54+
} catch (Exception ex) {
55+
String errMsg = String.format("Error calling #beforeRow callback row - %d", rowNum);
56+
LOGGER.error(errMsg, ex);
57+
}
58+
}
59+
60+
61+
@Override
62+
void afterRowEnd(final int rowNum, final Map<String, Object> rowDataMap) {
63+
// Sanity Checks
64+
if (Objects.isNull(rowDataMap) || rowDataMap.isEmpty()) {
65+
LOGGER.debug("INVALID Row data Passed - Row #{}", rowNum);
66+
return;
67+
}
68+
69+
// Skip rows before Header ROW and after Last ROW
70+
if (rowNum < headerRowNum || rowNum > lastRowNum) {
71+
return;
72+
}
73+
74+
// Process Header ROW
75+
if (rowNum == headerRowNum) {
76+
final Map<String, String> headerCellRefs = this.asHeaderNameToCellRefMap(rowDataMap);
77+
headerCellRefsMap.putAll(headerCellRefs);
78+
return;
79+
}
80+
81+
// Check for Column Definitions before processing NON-Header ROWs
82+
83+
// Row As Bean
84+
final Map<String, Object> rowBean = Spreadsheet.rowAsMap(headerCellRefsMap, rowDataMap);
85+
if (Objects.isNull(rowBean)) {
86+
LOGGER.debug("Unable to construct Row data Bean object - Row #{}", rowNum);
87+
return;
88+
}
89+
90+
// Row Callback
91+
try {
92+
listener.row(rowNum, rowBean);
93+
} catch (Exception ex) {
94+
String errMsg = String.format("Error calling #row callback row - %d, bean - %s", rowNum, rowBean);
95+
LOGGER.error(errMsg, ex);
96+
}
97+
}
98+
99+
100+
// Private Methods
101+
// ------------------------------------------------------------------------
102+
103+
private Map<String, String> asHeaderNameToCellRefMap(final Map<String, Object> headerRowData) {
104+
// Sanity checks
105+
if (Objects.isNull(headerRowData) || headerRowData.isEmpty()) {
106+
return new HashMap<>();
107+
}
108+
109+
// Get Bean Column definitions
110+
final Map<String, String> headerCellRefs = new HashMap<String, String>();
111+
for (final String colRef : headerRowData.keySet()) {
112+
final Object header = headerRowData.get(colRef);
113+
114+
final String headerName = Objects.isNull(header) ? "" : String.valueOf(header);
115+
headerCellRefs.put(headerName, colRef);
116+
}
117+
118+
LOGGER.debug("Header Name to Cell Refs : {}", headerCellRefs);
119+
return headerCellRefs;
120+
}
121+
122+
123+
}

src/main/java/io/github/millij/poi/ss/handler/RowContentsHandler.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import io.github.millij.poi.ss.model.Column;
1111
import io.github.millij.poi.util.Spreadsheet;
12+
import io.github.millij.poi.util.Strings;
1213

1314

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

116117
final String headerName = Objects.isNull(header) ? "" : String.valueOf(header);
117-
final String normalHeaderName = Spreadsheet.normalize(headerName);
118+
final String normalHeaderName = Strings.normalize(headerName);
118119
headerCellRefs.put(normalHeaderName, colRef);
119120
}
120121

src/main/java/io/github/millij/poi/ss/reader/AbstractSpreadsheetReader.java

+31
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.io.InputStream;
44
import java.util.List;
5+
import java.util.Map;
56

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

7475

76+
//
77+
// Read to Map
78+
79+
@Override
80+
public List<Map<String, Object>> read(final InputStream is) throws SpreadsheetReadException {
81+
// Row Collector
82+
final RowBeanCollector<Map<String, Object>> beanCollector = new RowBeanCollector<>();
83+
84+
// Read with callback to fill list
85+
this.read(is, beanCollector);
86+
87+
// Result
88+
final List<Map<String, Object>> beans = beanCollector.getBeans();
89+
return beans;
90+
}
91+
92+
@Override
93+
public List<Map<String, Object>> read(final InputStream is, final int sheetNo) throws SpreadsheetReadException {
94+
// Row Collector
95+
final RowBeanCollector<Map<String, Object>> beanCollector = new RowBeanCollector<>();
96+
97+
// Read with callback to fill list
98+
this.read(is, sheetNo, beanCollector);
99+
100+
// Result
101+
final List<Map<String, Object>> beans = beanCollector.getBeans();
102+
return beans;
103+
}
104+
105+
75106
}

src/main/java/io/github/millij/poi/ss/reader/SpreadsheetReader.java

+54
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.io.IOException;
66
import java.io.InputStream;
77
import java.util.List;
8+
import java.util.Map;
89

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

197198

199+
//
200+
// Read to Map
201+
202+
/**
203+
* Reads the spreadsheet file as Generic {@link Map} beans. Note that only the requested sheet (sheet numbers are
204+
* indexed from 0) will be read.
205+
*
206+
* @param is {@link InputStream} of the spreadsheet file
207+
* @param listener Custom {@link RowListener} implementation for row data callbacks.
208+
*
209+
* @throws SpreadsheetReadException when the file data is not readable or row data to bean mapping failed.
210+
*/
211+
void read(InputStream is, RowListener<Map<String, Object>> listener) throws SpreadsheetReadException;
212+
213+
/**
214+
* Reads the spreadsheet file as Generic {@link Map} beans. Note that only the requested sheet (sheet numbers are
215+
* indexed from 0) will be read.
216+
*
217+
* @param is {@link InputStream} of the spreadsheet file
218+
* @param sheetNo index of the Sheet to be read (index starts from 1)
219+
* @param listener Custom {@link RowListener} implementation for row data callbacks.
220+
*
221+
* @throws SpreadsheetReadException when the file data is not readable or row data to bean mapping failed.
222+
*/
223+
void read(InputStream is, int sheetNo, RowListener<Map<String, Object>> listener) throws SpreadsheetReadException;
224+
225+
226+
/**
227+
* Reads the spreadsheet file as Generic {@link Map} beans. Note that only the requested sheet (sheet numbers are
228+
* indexed from 0) will be read.
229+
*
230+
* @param is {@link InputStream} of the spreadsheet file
231+
*
232+
* @return a {@link List} of {@link Map} objects
233+
*
234+
* @throws SpreadsheetReadException when the file data is not readable or row data to bean mapping failed.
235+
*/
236+
List<Map<String, Object>> read(InputStream is) throws SpreadsheetReadException;
237+
238+
/**
239+
* Reads the spreadsheet file as Generic {@link Map} beans. Note that only the requested sheet (sheet numbers are
240+
* indexed from 0) will be read.
241+
*
242+
* @param is {@link InputStream} of the spreadsheet file
243+
* @param sheetNo index of the Sheet to be read (index starts from 1)
244+
*
245+
* @return a {@link List} of {@link Map} objects
246+
*
247+
* @throws SpreadsheetReadException when the file data is not readable or row data to bean mapping failed.
248+
*/
249+
List<Map<String, Object>> read(InputStream is, int sheetNo) throws SpreadsheetReadException;
250+
251+
198252
}
199253

0 commit comments

Comments
 (0)