From 2131f617a54118bf7c89ad00aeeb37076d631877 Mon Sep 17 00:00:00 2001 From: Gowri Shankar Date: Mon, 22 Jul 2024 15:13:45 +0530 Subject: [PATCH 01/10] [reader]: added read to Map support to SpreadsheetReader, impls --- .../ss/handler/RowContentsAsMapHandler.java | 118 ++++++++++++++++++ .../ss/reader/AbstractSpreadsheetReader.java | 31 +++++ .../poi/ss/reader/SpreadsheetReader.java | 54 ++++++++ .../millij/poi/ss/reader/XlsReader.java | 87 ++++++++++++- .../millij/poi/ss/reader/XlsxReader.java | 91 ++++++++++++++ .../github/millij/poi/util/Spreadsheet.java | 31 +++++ 6 files changed, 406 insertions(+), 6 deletions(-) create mode 100644 src/main/java/io/github/millij/poi/ss/handler/RowContentsAsMapHandler.java diff --git a/src/main/java/io/github/millij/poi/ss/handler/RowContentsAsMapHandler.java b/src/main/java/io/github/millij/poi/ss/handler/RowContentsAsMapHandler.java new file mode 100644 index 0000000..a26b50b --- /dev/null +++ b/src/main/java/io/github/millij/poi/ss/handler/RowContentsAsMapHandler.java @@ -0,0 +1,118 @@ +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; + + +public class RowContentsAsMapHandler extends AbstractSheetContentsHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(RowContentsAsMapHandler.class); + + private final RowListener> listener; + + private final int headerRowNum; + private final Map headerCellRefsMap; + + private final int lastRowNum; + + + // Constructors + // ------------------------------------------------------------------------ + + public RowContentsAsMapHandler(RowListener> 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 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 headerCellRefs = this.asHeaderNameToCellRefMap(rowDataMap); + headerCellRefsMap.putAll(headerCellRefs); + return; + } + + // Check for Column Definitions before processing NON-Header ROWs + + // Row As Bean + final Map 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 asHeaderNameToCellRefMap(final Map headerRowData) { + // Sanity checks + if (Objects.isNull(headerRowData) || headerRowData.isEmpty()) { + return new HashMap<>(); + } + + // Get Bean Column definitions + final Map headerCellRefs = new HashMap(); + 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; + } + + +} diff --git a/src/main/java/io/github/millij/poi/ss/reader/AbstractSpreadsheetReader.java b/src/main/java/io/github/millij/poi/ss/reader/AbstractSpreadsheetReader.java index fa42bf5..0d1c5e8 100644 --- a/src/main/java/io/github/millij/poi/ss/reader/AbstractSpreadsheetReader.java +++ b/src/main/java/io/github/millij/poi/ss/reader/AbstractSpreadsheetReader.java @@ -2,6 +2,7 @@ import java.io.InputStream; import java.util.List; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -72,4 +73,34 @@ public List read(final Class beanClz, final InputStream is, final int } + // + // Read to Map + + @Override + public List> read(final InputStream is) throws SpreadsheetReadException { + // Row Collector + final RowBeanCollector> beanCollector = new RowBeanCollector<>(); + + // Read with callback to fill list + this.read(is, beanCollector); + + // Result + final List> beans = beanCollector.getBeans(); + return beans; + } + + @Override + public List> read(final InputStream is, final int sheetNo) throws SpreadsheetReadException { + // Row Collector + final RowBeanCollector> beanCollector = new RowBeanCollector<>(); + + // Read with callback to fill list + this.read(is, sheetNo, beanCollector); + + // Result + final List> beans = beanCollector.getBeans(); + return beans; + } + + } diff --git a/src/main/java/io/github/millij/poi/ss/reader/SpreadsheetReader.java b/src/main/java/io/github/millij/poi/ss/reader/SpreadsheetReader.java index 9e76a8a..62c73e5 100644 --- a/src/main/java/io/github/millij/poi/ss/reader/SpreadsheetReader.java +++ b/src/main/java/io/github/millij/poi/ss/reader/SpreadsheetReader.java @@ -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; @@ -195,5 +196,58 @@ default List read(Class 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> 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> 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> 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> read(InputStream is, int sheetNo) throws SpreadsheetReadException; + + } diff --git a/src/main/java/io/github/millij/poi/ss/reader/XlsReader.java b/src/main/java/io/github/millij/poi/ss/reader/XlsReader.java index e9633c2..41d7585 100644 --- a/src/main/java/io/github/millij/poi/ss/reader/XlsReader.java +++ b/src/main/java/io/github/millij/poi/ss/reader/XlsReader.java @@ -81,7 +81,6 @@ public void read(final Class beanClz, final InputStream is, final RowList LOGGER.error(errMsg, ex); throw new SpreadsheetReadException(errMsg, ex); } - } @Override @@ -109,14 +108,90 @@ public void read(final Class beanClz, final InputStream is, final int she } + // + // Read to Map + + @Override + public void read(final InputStream is, final RowListener> listener) + throws SpreadsheetReadException { + try { + final HSSFWorkbook wb = new HSSFWorkbook(is); + final int sheetCount = wb.getNumberOfSheets(); + LOGGER.debug("Total no. of sheets found in HSSFWorkbook : #{}", sheetCount); + + // Iterate over sheets + for (int i = 0; i < sheetCount; i++) { + final HSSFSheet sheet = wb.getSheetAt(i); + LOGGER.debug("Processing HSSFSheet at No. : {}", i); + + // Process Sheet + this.processSheet(sheet, listener); + } + + // Close workbook + wb.close(); + } catch (Exception ex) { + String errMsg = String.format("Error reading HSSFSheet, to Map : %s", ex.getMessage()); + LOGGER.error(errMsg, ex); + throw new SpreadsheetReadException(errMsg, ex); + } + } + + @Override + public void read(final InputStream is, final int sheetNo, final RowListener> listener) + throws SpreadsheetReadException { + try { + final HSSFWorkbook wb = new HSSFWorkbook(is); + final HSSFSheet sheet = wb.getSheetAt(sheetNo - 1); // subtract 1 as Workbook follows 0-based index + + // Process Sheet + this.processSheet(sheet, listener); + + // Close workbook + wb.close(); + } catch (Exception ex) { + String errMsg = String.format("Error reading sheet %d, to Map : %s", sheetNo, ex.getMessage()); + LOGGER.error(errMsg, ex); + throw new SpreadsheetReadException(errMsg, ex); + } + } + + // // Protected Methods // ------------------------------------------------------------------------ + protected void processSheet(final HSSFSheet sheet, final RowListener> eventHandler) { + // Header column - name mapping + final HSSFRow headerRowObj = sheet.getRow(headerRowIdx); + final Map headerCellRefsMap = this.asHeaderNameToCellRefMap(headerRowObj, false); + + final Iterator rows = sheet.rowIterator(); + while (rows.hasNext()) { + // Process Row Data + final HSSFRow row = (HSSFRow) rows.next(); + final int rowNum = row.getRowNum(); + + // Skip rows before Header ROW and after Last ROW + if (rowNum < headerRowIdx || rowNum > lastRowIdx) { + continue; + } + + final Map rowDataMap = this.extractRowDataAsMap(row); + if (rowDataMap == null || rowDataMap.isEmpty()) { + continue; + } + + // Row data as Bean + final Map rowBean = Spreadsheet.rowAsMap(headerCellRefsMap, rowDataMap); + eventHandler.row(rowNum, rowBean); + } + } + protected void processSheet(final Class beanClz, final HSSFSheet sheet, final RowListener eventHandler) { // Header column - name mapping final HSSFRow headerRowObj = sheet.getRow(headerRowIdx); - final Map headerCellRefsMap = this.asHeaderNameToCellRefMap(headerRowObj); + final Map headerCellRefsMap = this.asHeaderNameToCellRefMap(headerRowObj, true); // Bean Properties - column name mapping final Map propColumnMap = Spreadsheet.getPropertyToColumnDefMap(beanClz); @@ -147,7 +222,7 @@ protected void processSheet(final Class beanClz, final HSSFSheet sheet, f // Private Methods // ------------------------------------------------------------------------ - private Map asHeaderNameToCellRefMap(final HSSFRow headerRow) { + private Map asHeaderNameToCellRefMap(final HSSFRow headerRow, final boolean normalizeHeaderName) { // Sanity checks if (Objects.isNull(headerRow)) { return new HashMap<>(); @@ -164,9 +239,9 @@ private Map asHeaderNameToCellRefMap(final HSSFRow headerRow) { // Cell Value final Object header = this.getCellValue(cell); - final String headerName = Objects.isNull(header) ? "" : String.valueOf(header); - final String normalHeaderName = Spreadsheet.normalize(headerName); - headerCellRefs.put(normalHeaderName, cellColRef); + final String rawHeaderName = Objects.isNull(header) ? "" : String.valueOf(header); + final String headerName = normalizeHeaderName ? Spreadsheet.normalize(rawHeaderName) : rawHeaderName; + headerCellRefs.put(headerName, cellColRef); } return headerCellRefs; diff --git a/src/main/java/io/github/millij/poi/ss/reader/XlsxReader.java b/src/main/java/io/github/millij/poi/ss/reader/XlsxReader.java index 761b07c..f043e1f 100644 --- a/src/main/java/io/github/millij/poi/ss/reader/XlsxReader.java +++ b/src/main/java/io/github/millij/poi/ss/reader/XlsxReader.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.io.InputStream; +import java.util.Map; import javax.xml.parsers.ParserConfigurationException; @@ -23,6 +24,7 @@ import org.xml.sax.XMLReader; import io.github.millij.poi.SpreadsheetReadException; +import io.github.millij.poi.ss.handler.RowContentsAsMapHandler; import io.github.millij.poi.ss.handler.RowContentsHandler; import io.github.millij.poi.ss.handler.RowListener; import io.github.millij.poi.util.Beans; @@ -133,6 +135,78 @@ public void read(final Class beanClz, final InputStream is, final int she } + // + // Read to Map + + @Override + public void read(final InputStream is, final RowListener> listener) + throws SpreadsheetReadException { + + // Read + try (final OPCPackage opcPkg = OPCPackage.open(is)) { + // XSSF Reader + final XSSFReader xssfReader = new XSSFReader(opcPkg); + + // XML Reader + final XMLReader xmlReader = this.newXMLReaderInstance(opcPkg, xssfReader, listener); + + // Iterate over sheets + for (SheetIterator worksheets = (SheetIterator) xssfReader.getSheetsData(); worksheets.hasNext();) { + final InputStream sheetInpStream = worksheets.next(); + final String sheetName = worksheets.getSheetName(); + LOGGER.debug("Reading XLSX Sheet :: ", sheetName); + + // Parse sheet + xmlReader.parse(new InputSource(sheetInpStream)); + sheetInpStream.close(); + } + + } catch (Exception ex) { + String errMsg = String.format("Error reading sheet data, to Map : %s", ex.getMessage()); + LOGGER.error(errMsg, ex); + throw new SpreadsheetReadException(errMsg, ex); + } + + } + + @Override + public void read(final InputStream is, final int sheetNo, final RowListener> listener) + throws SpreadsheetReadException { + try (final OPCPackage opcPkg = OPCPackage.open(is)) { + // XSSF Reader + final XSSFReader xssfReader = new XSSFReader(opcPkg); + + // XML Reader + final XMLReader xmlReader = this.newXMLReaderInstance(opcPkg, xssfReader, listener); + + // Iterate over sheets + final SheetIterator worksheets = (SheetIterator) xssfReader.getSheetsData(); + for (int i = 1; worksheets.hasNext(); i++) { + // Get Sheet + final InputStream sheetInpStream = worksheets.next(); + final String sheetName = worksheets.getSheetName(); + + // Check for Sheet No. + if (i != sheetNo) { + continue; + } + + LOGGER.debug("Reading XLSX Sheet :: #{} - {}", i, sheetName); + + // Parse Sheet + xmlReader.parse(new InputSource(sheetInpStream)); + sheetInpStream.close(); + } + + } catch (Exception ex) { + String errMsg = String.format("Error reading sheet %d, to Map : %s", sheetNo, ex.getMessage()); + LOGGER.error(errMsg, ex); + throw new SpreadsheetReadException(errMsg, ex); + } + + } + + // Private Methods // ------------------------------------------------------------------------ @@ -164,4 +238,21 @@ private XMLReader newXMLReaderInstance(final Class beanClz, final OPCPack return xmlReader; } + private XMLReader newXMLReaderInstance(final OPCPackage opcPkg, final XSSFReader xssfReader, + final RowListener> listener) + throws InvalidFormatException, IOException, SAXException, ParserConfigurationException { + // Content Handler + final StylesTable styles = xssfReader.getStylesTable(); + final ReadOnlySharedStringsTable ssTable = new ReadOnlySharedStringsTable(opcPkg); + final SheetContentsHandler sheetHandler = new RowContentsAsMapHandler(listener, headerRowIdx, lastRowIdx); + + final ContentHandler handler = new XSSFSheetXMLHandler(styles, ssTable, sheetHandler, true); + + // XML Reader + final XMLReader xmlReader = XMLHelper.newXMLReader(); + xmlReader.setContentHandler(handler); + + return xmlReader; + } + } diff --git a/src/main/java/io/github/millij/poi/util/Spreadsheet.java b/src/main/java/io/github/millij/poi/util/Spreadsheet.java index 2ab8309..2ab0287 100644 --- a/src/main/java/io/github/millij/poi/util/Spreadsheet.java +++ b/src/main/java/io/github/millij/poi/util/Spreadsheet.java @@ -206,6 +206,37 @@ public static Map asRowDataMap(final Object beanObj, final List< // Write to Bean :: from Row data // ------------------------------------------------------------------------ + public static Map rowAsMap(final Map headerCellRefsMap, + final Map rowDataMap) { + // + try { + // Create new Instance + final Map beanMap = new HashMap(); + + for (final String propColName : headerCellRefsMap.keySet()) { + // Get the Header Cell Ref + final String propCellRef = headerCellRefsMap.get(propColName); + if (Objects.isNull(propCellRef) || propCellRef.isBlank()) { + continue; + } + + // Property Value and Format + final Object propValue = rowDataMap.get(propCellRef); + + // set + beanMap.put(propColName, propValue); + } + + return beanMap; + } catch (Exception ex) { + String errMsg = String.format("Error while creating Row Map, from - %s", rowDataMap); + LOGGER.error(errMsg, ex); + } + + return null; + } + + public static T rowAsBean(Class beanClz, Map propColumnMap, Map headerCellRefsMap, Map rowDataMap) { // Sanity checks From 189d9e9a6e80698e90ccd4357b26c7775993ec19 Mon Sep 17 00:00:00 2001 From: Gowri Shankar Date: Mon, 22 Jul 2024 15:14:33 +0530 Subject: [PATCH 02/10] [test]: added log4j2 impl for test-cases log --- build.gradle | 3 +++ src/test/resources/log4j2.properties | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/test/resources/log4j2.properties diff --git a/build.gradle b/build.gradle index a45efbc..eb63f3c 100644 --- a/build.gradle +++ b/build.gradle @@ -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' } diff --git a/src/test/resources/log4j2.properties b/src/test/resources/log4j2.properties new file mode 100644 index 0000000..012ed7c --- /dev/null +++ b/src/test/resources/log4j2.properties @@ -0,0 +1,15 @@ +# Properties + +# Root Logger Config +rootLogger.level=INFO +rootLogger.appenderRefs=console +rootLogger.appenderRef.console.ref=STDOUT + +# Appenders Config +appenders=console + +appender.console.type=Console +appender.console.name=STDOUT +appender.console.layout.type=PatternLayout +appender.console.layout.pattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n + From 2c030c79b6b5c2aa3023cbba375f2fd377c130dc Mon Sep 17 00:00:00 2001 From: Gowri Shankar Date: Mon, 22 Jul 2024 15:17:31 +0530 Subject: [PATCH 03/10] [test]: added test-cases for reading excel sheets as Map --- .../millij/poi/ss/reader/XlsReaderTest.java | 26 +++++++++++++++++++ .../millij/poi/ss/reader/XlsxReaderTest.java | 14 +++++----- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/test/java/io/github/millij/poi/ss/reader/XlsReaderTest.java b/src/test/java/io/github/millij/poi/ss/reader/XlsReaderTest.java index fd1917c..b143957 100644 --- a/src/test/java/io/github/millij/poi/ss/reader/XlsReaderTest.java +++ b/src/test/java/io/github/millij/poi/ss/reader/XlsReaderTest.java @@ -7,6 +7,7 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.junit.After; import org.junit.Assert; @@ -169,6 +170,7 @@ public void row(int rowNum, Employee employee) { employees.add(employee); LOGGER.info("test_read_xls_single_sheet_with_callback :: Output - {}", employee); + // ? } }); @@ -177,4 +179,28 @@ public void row(int rowNum, Employee employee) { Assert.assertTrue(employees.size() > 0); } + + // Read to Map + + @Test + public void test_read_xlsx_as_Map() throws SpreadsheetReadException, FileNotFoundException { + // Excel Reader + LOGGER.info("test_read_xlsx_as_Map :: Reading file - {}", _filepath_xls_single_sheet); + + // File + final File xlsxFile = new File(_filepath_xls_single_sheet); + + // Reader + final XlsReader reader = new XlsReader(); + + List> employees = reader.read(new FileInputStream(xlsxFile), 1); + Assert.assertNotNull(employees); + Assert.assertTrue(employees.size() > 0); + + for (Map emp : employees) { + LOGGER.info("test_read_xlsx_as_Map :: Output - {}", emp); + } + + } + } diff --git a/src/test/java/io/github/millij/poi/ss/reader/XlsxReaderTest.java b/src/test/java/io/github/millij/poi/ss/reader/XlsxReaderTest.java index cf87a36..e6e6c18 100644 --- a/src/test/java/io/github/millij/poi/ss/reader/XlsxReaderTest.java +++ b/src/test/java/io/github/millij/poi/ss/reader/XlsxReaderTest.java @@ -7,11 +7,11 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -181,25 +181,25 @@ public void row(int rowNum, Employee employee) { // Read to Map - - @Ignore @Test - public void test_read_xlsx_as_Map() throws FileNotFoundException { + public void test_read_xlsx_as_Map() throws SpreadsheetReadException, FileNotFoundException { // Excel Reader LOGGER.info("test_read_xlsx_as_Map :: Reading file - {}", _filepath_xlsx_single_sheet); - /* + // File + final File xlsxFile = new File(_filepath_xlsx_single_sheet); + // Reader final XlsxReader reader = new XlsxReader(); - List> employees = reader.readAsMap(new File(_filepath_xlsx_single_sheet), 1); + List> employees = reader.read(new FileInputStream(xlsxFile), 1); Assert.assertNotNull(employees); Assert.assertTrue(employees.size() > 0); for (Map emp : employees) { LOGGER.info("test_read_xlsx_single_sheet :: Output - {}", emp); } - */ + } From f6d3ee62c435a03ba910f18944f5a1a2a03af442 Mon Sep 17 00:00:00 2001 From: Gowri Shankar Date: Mon, 22 Jul 2024 15:43:57 +0530 Subject: [PATCH 04/10] [gradle]: updated the ver to 3.1.0 in gradle; updated README docs --- README.md | 19 ++++++++++++++++--- build.gradle | 2 +- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ac951c1..1f7757f 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ This library is available in [Maven Central](https://mvnrepository.com/artifact/ io.github.millij poi-object-mapper - 3.0.0 + 3.1.0 ``` @@ -76,12 +76,25 @@ Reading spreadsheet rows as objects .. ```java ... - final File xlsxFile = new File(""); + final File xlsFile = new File(""); final XlsReader reader = new XlsReader(); - final List employees = reader.read(Employee.class, xlsxFile); + final List employees = reader.read(Employee.class, xlsFile); + ... +``` + +##### Reading Rows as Map (when there is no mapping bean) + +Reading spreadsheet rows as `Map` Objects .. + +```java + ... + final File xlsxFile = new File(""); + final XlsxReader reader = new XlsxReader(); // OR XlsReader as needed + final List> rowObjects = reader.read(xlsxFile); ... ``` + ##### Writing a collection of objects to file Similar to `Reader`, the mapped Java Beans can be written to files. diff --git a/build.gradle b/build.gradle index eb63f3c..5151abf 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ sourceCompatibility = 1.11 targetCompatibility = 1.11 group = 'io.github.millij' -version = '3.0.0' +version = '3.1.0' dependencies { From 66fd0f6f6d7bbb755f6cb94fc31a9fcf99fb461d Mon Sep 17 00:00:00 2001 From: Gowri Shankar Date: Mon, 22 Jul 2024 15:58:56 +0530 Subject: [PATCH 05/10] [bug]: #63 update bean value setter to be skipped when input prop/cell val is NULL --- .../java/io/github/millij/poi/util/Beans.java | 11 ++++++++--- .../xlsx_sample_multiple_sheets.xlsx | Bin 6295 -> 6658 bytes 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/github/millij/poi/util/Beans.java b/src/main/java/io/github/millij/poi/util/Beans.java index 9cb6984..4ab68ce 100644 --- a/src/main/java/io/github/millij/poi/util/Beans.java +++ b/src/main/java/io/github/millij/poi/util/Beans.java @@ -27,7 +27,7 @@ */ public final class Beans { - private static final Logger LOGGER = LoggerFactory.getLogger(Spreadsheet.class); + private static final Logger LOGGER = LoggerFactory.getLogger(Beans.class); private Beans() { super(); @@ -110,9 +110,14 @@ public static boolean isInstantiableType(final Class clz) { public static void setProperty(final Object target, final String propName, final Object propValue, final String format, final DateTimeType dateTimeType) throws Exception { + // Sanity checks + if (Objects.isNull(propValue)) { + return; // Skip Setter if property value is NULL + } + // Calculate the property type final PropertyDescriptor descriptor = PROP_UTILS_BEAN.getPropertyDescriptor(target, propName); - if (descriptor == null || descriptor.getWriteMethod() == null) { + if (Objects.isNull(descriptor) || Objects.isNull(descriptor.getWriteMethod())) { return; // Skip this property setter } @@ -120,7 +125,7 @@ public static void setProperty(final Object target, final String propName, final final Class type = descriptor.getPropertyType(); // Check PropValue (expected non-null and string) - if (Objects.isNull(propValue) || !(propValue instanceof String)) { + if (!(propValue instanceof String)) { setProperty(target, propName, type, propValue); return; } diff --git a/src/test/resources/sample-files/xlsx_sample_multiple_sheets.xlsx b/src/test/resources/sample-files/xlsx_sample_multiple_sheets.xlsx index 9b00f632f9cea9bfdbafae8db0225cdb5a365032..970e148fc048aed210b83e35470e1df023831ded 100644 GIT binary patch delta 5642 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 delta 5273 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 From d1be7a0e3b249092de96c628eed98238f72e7391 Mon Sep 17 00:00:00 2001 From: Gowri Shankar Date: Mon, 22 Jul 2024 16:07:53 +0530 Subject: [PATCH 06/10] [bug]: #47 fixed PropertyDescriptor reference in Beans#getFieldValueAsString mthd --- src/main/java/io/github/millij/poi/util/Beans.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/github/millij/poi/util/Beans.java b/src/main/java/io/github/millij/poi/util/Beans.java index 4ab68ce..aefdacc 100644 --- a/src/main/java/io/github/millij/poi/util/Beans.java +++ b/src/main/java/io/github/millij/poi/util/Beans.java @@ -35,6 +35,13 @@ private Beans() { } + // + // Constants + + private static final PropertyUtilsBean PROP_UTILS_BEAN = new PropertyUtilsBean(); + private static final ConvertUtilsBean CONVERT_UTILS_BEAN = new ConvertUtilsBean(); + + // Static Utilities // ------------------------------------------------------------------------ @@ -68,7 +75,7 @@ public static String getFieldName(final Method method) { */ public static String getFieldValueAsString(final Object beanObj, final String fieldName) throws Exception { // Property Descriptor - final PropertyDescriptor pd = new PropertyDescriptor(fieldName, beanObj.getClass()); + final PropertyDescriptor pd = PROP_UTILS_BEAN.getPropertyDescriptor(beanObj, fieldName); final Method getterMtd = pd.getReadMethod(); final Object value = getterMtd.invoke(beanObj); @@ -105,9 +112,6 @@ public static boolean isInstantiableType(final Class clz) { // Set Property // ------------------------------------------------------------------------ - private static final PropertyUtilsBean PROP_UTILS_BEAN = new PropertyUtilsBean(); - private static final ConvertUtilsBean CONVERT_UTILS_BEAN = new ConvertUtilsBean(); - public static void setProperty(final Object target, final String propName, final Object propValue, final String format, final DateTimeType dateTimeType) throws Exception { // Sanity checks From 4a0bd440ceb83ed37239e05a324d14e9f38353e0 Mon Sep 17 00:00:00 2001 From: Gowri Shankar Date: Mon, 22 Jul 2024 17:28:45 +0530 Subject: [PATCH 07/10] [util]: moved normalize util to new Strings utility --- .../ss/handler/RowContentsAsMapHandler.java | 5 ++ .../poi/ss/handler/RowContentsHandler.java | 3 +- .../millij/poi/ss/reader/XlsReader.java | 3 +- .../github/millij/poi/util/Spreadsheet.java | 18 ++---- .../io/github/millij/poi/util/Strings.java | 55 +++++++++++++++++++ 5 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 src/main/java/io/github/millij/poi/util/Strings.java diff --git a/src/main/java/io/github/millij/poi/ss/handler/RowContentsAsMapHandler.java b/src/main/java/io/github/millij/poi/ss/handler/RowContentsAsMapHandler.java index a26b50b..01a74dc 100644 --- a/src/main/java/io/github/millij/poi/ss/handler/RowContentsAsMapHandler.java +++ b/src/main/java/io/github/millij/poi/ss/handler/RowContentsAsMapHandler.java @@ -10,6 +10,11 @@ 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); diff --git a/src/main/java/io/github/millij/poi/ss/handler/RowContentsHandler.java b/src/main/java/io/github/millij/poi/ss/handler/RowContentsHandler.java index db6d9c0..6822d17 100644 --- a/src/main/java/io/github/millij/poi/ss/handler/RowContentsHandler.java +++ b/src/main/java/io/github/millij/poi/ss/handler/RowContentsHandler.java @@ -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 extends AbstractSheetContentsHandler { @@ -114,7 +115,7 @@ private Map asHeaderNameToCellRefMap(final Map 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); } diff --git a/src/main/java/io/github/millij/poi/ss/reader/XlsReader.java b/src/main/java/io/github/millij/poi/ss/reader/XlsReader.java index 41d7585..99775fe 100644 --- a/src/main/java/io/github/millij/poi/ss/reader/XlsReader.java +++ b/src/main/java/io/github/millij/poi/ss/reader/XlsReader.java @@ -22,6 +22,7 @@ import io.github.millij.poi.ss.handler.RowListener; import io.github.millij.poi.ss.model.Column; import io.github.millij.poi.util.Spreadsheet; +import io.github.millij.poi.util.Strings; /** @@ -240,7 +241,7 @@ private Map asHeaderNameToCellRefMap(final HSSFRow headerRow, fi final Object header = this.getCellValue(cell); final String rawHeaderName = Objects.isNull(header) ? "" : String.valueOf(header); - final String headerName = normalizeHeaderName ? Spreadsheet.normalize(rawHeaderName) : rawHeaderName; + final String headerName = normalizeHeaderName ? Strings.normalize(rawHeaderName) : rawHeaderName; headerCellRefs.put(headerName, cellColRef); } diff --git a/src/main/java/io/github/millij/poi/util/Spreadsheet.java b/src/main/java/io/github/millij/poi/util/Spreadsheet.java index 2ab0287..48f70be 100644 --- a/src/main/java/io/github/millij/poi/util/Spreadsheet.java +++ b/src/main/java/io/github/millij/poi/util/Spreadsheet.java @@ -261,7 +261,7 @@ public static T rowAsBean(Class beanClz, Map propColumnMa final String propColName = propColDef.getName(); // Get the Header Cell Ref - final String normalizedColName = Spreadsheet.normalize(propColName); + final String normalizedColName = Strings.normalize(propColName); final String propCellRef = headerCellRefsMap.get(normalizedColName); if (Objects.isNull(propCellRef) || propCellRef.isBlank()) { LOGGER.debug("{} :: No Cell Ref found [Prop - Col] : [{} - {}]", beanClz, propName, propColName); @@ -303,7 +303,7 @@ private static boolean validateRowData(final Map rowDataMap, // Prop Column Definition final Column propColDef = propColumnMap.get(propName); final String propColName = propColDef.getName(); - final String normalizedColName = Spreadsheet.normalize(propColName); + final String normalizedColName = Strings.normalize(propColName); // Get the Header Cell Ref final String propCellRef = headerCellRefsMap.containsKey(propColName) // @@ -334,18 +334,12 @@ private static boolean validateRowData(final Map rowDataMap, /** * Normalize the string. typically used for case-insensitive comparison. + * + * @deprecated in favor of {@link Strings#normalize(String)} */ + @Deprecated public static String normalize(final String inStr) { - // Sanity checks - if (Objects.isNull(inStr)) { - return ""; - } - - // Special characters - final String cleanStr = inStr.replaceAll("–", " ").replaceAll("[-\\[\\]/{}:.,;#%=()*+?\\^$|<>&\"\'\\\\]", " "); - final String normalizedStr = cleanStr.toLowerCase().trim().replaceAll("\\s+", "_"); - - return normalizedStr; + return Strings.normalize(inStr); } diff --git a/src/main/java/io/github/millij/poi/util/Strings.java b/src/main/java/io/github/millij/poi/util/Strings.java new file mode 100644 index 0000000..0a8722d --- /dev/null +++ b/src/main/java/io/github/millij/poi/util/Strings.java @@ -0,0 +1,55 @@ +package io.github.millij.poi.util; + +import java.util.Objects; + + +/** + * Odd ball String Utilities + * + * @since 3.1.0 + */ +public final class Strings { + + private Strings() { + super(); + // Utility Class + } + + + // Util Methods + // ------------------------------------------------------------------------ + + /** + * Normalize the string by removing unwanted characters from the String. + * + * @param inStr Input String + * @param replacement Replacement character for the unwanted characters + * + * @return Clean / Normalized String + */ + public static String normalize(final String inStr, final String replacement) { + // Sanity checks + if (Objects.isNull(inStr)) { + return ""; + } + + // Special characters + final String cleanStr = inStr.replaceAll("–", " ").replaceAll("[-\\[\\]/{}:.,;#%=()*+?\\^$|<>&\"\'\\\\]", " "); + final String normalizedStr = cleanStr.toLowerCase().trim().replaceAll("\\s+", replacement); + + return normalizedStr; + } + + /** + * Normalize the string by replacing unwanted characters from the String with "_". + * + * @param inStr Input String + * + * @return Clean / Normalized String + */ + public static String normalize(final String inStr) { + return normalize(inStr, "_"); + } + + +} From 30df4eda45fe5c50cdace51e2a6fc5f5fe7f5b81 Mon Sep 17 00:00:00 2001 From: Gowri Shankar Date: Mon, 22 Jul 2024 17:31:43 +0530 Subject: [PATCH 08/10] [util]: refactored Beans util; added cleanup step for Boolean types in #setProperty --- .../java/io/github/millij/poi/util/Beans.java | 141 ++++++++++-------- 1 file changed, 82 insertions(+), 59 deletions(-) diff --git a/src/main/java/io/github/millij/poi/util/Beans.java b/src/main/java/io/github/millij/poi/util/Beans.java index aefdacc..8a9b430 100644 --- a/src/main/java/io/github/millij/poi/util/Beans.java +++ b/src/main/java/io/github/millij/poi/util/Beans.java @@ -109,9 +109,52 @@ public static boolean isInstantiableType(final Class clz) { } - // Set Property + // Bean Property :: Get // ------------------------------------------------------------------------ + public static Object getProperty(final Object bean, final String propName) throws Exception { + final Object value = PROP_UTILS_BEAN.getSimpleProperty(bean, propName); + return value; + } + + + // Bean Property :: Set + // ------------------------------------------------------------------------ + + /** + */ + public static void setProperty(final Object target, final String propName, final Class propType, + final Object propValue) throws Exception { + // Sanity checks + if (Objects.isNull(propValue)) { + return; // Skip Setter if property value is NULL + } + + try { + // Convert the specified value to the required type + final Object newValue; + if (propValue instanceof String) { + newValue = CONVERT_UTILS_BEAN.convert((String) propValue, propType); + } else { + final Converter converter = CONVERT_UTILS_BEAN.lookup(propType); + if (converter != null) { + newValue = converter.convert(propType, propValue); + } else { + newValue = propValue; + } + } + + // Invoke the setter method + PROP_UTILS_BEAN.setProperty(target, propName, newValue); + + } catch (Exception ex) { + // + } + } + + + /** + */ public static void setProperty(final Object target, final String propName, final Object propValue, final String format, final DateTimeType dateTimeType) throws Exception { // Sanity checks @@ -126,23 +169,36 @@ public static void setProperty(final Object target, final String propName, final } // Property Type - final Class type = descriptor.getPropertyType(); + final Class propType = descriptor.getPropertyType(); - // Check PropValue (expected non-null and string) - if (!(propValue instanceof String)) { - setProperty(target, propName, type, propValue); + // + // Handle Date/Time/Duration Cases + if (!DateTimeType.NONE.equals(dateTimeType) || propType.equals(Date.class)) { + setDateTimeProperty(target, propName, propType, propValue, format, dateTimeType); return; } // - // Handle Date/Time/Duration Cases - - // Check if its a Date time property - if (!type.equals(Date.class) && DateTimeType.NONE.equals(dateTimeType)) { - setProperty(target, propName, type, propValue); + // Handle Boolean + if (propType.equals(Boolean.class) && (propValue instanceof String)) { + // Cleanup Boolean String + final String cleanBoolStr = Strings.normalize((String) propValue); + setProperty(target, propName, propType, cleanBoolStr); return; } + // + // Default Handling (for all other Types) + setProperty(target, propName, propType, propValue); + + } + + + /** + * Set the Date/Time property of the Target Bean. + */ + private static void setDateTimeProperty(final Object target, final String propName, final Class propType, + final Object propValue, final String format, final DateTimeType dateTimeType) throws Exception { // Input value Format final String dateFormatStr = Objects.isNull(format) || format.isBlank() ? "dd/MM/yyyy" : format; @@ -150,62 +206,29 @@ public static void setProperty(final Object target, final String propName, final final SimpleDateFormat dateFmt = new SimpleDateFormat(dateFormatStr); final Date dateValue = dateFmt.parse((String) propValue); - // check if the PropType is Date - if (type.equals(Date.class)) { - setProperty(target, propName, type, dateValue); - return; - } - - // Convert to Long - final Long longValue; - if (DateTimeType.DURATION.equals(dateTimeType)) { - final Calendar calendar = Calendar.getInstance(); - calendar.setTime(dateValue); - final long durationMillis = calendar.get(HOUR_OF_DAY) * 3600_000 + // - calendar.get(MINUTE) * 60_000 + // - calendar.get(SECOND) * 1_000; + // Check if the PropType is Date + if (propType.equals(Date.class)) { + setProperty(target, propName, propType, dateValue); - longValue = durationMillis; } else { - longValue = dateValue.getTime(); - } - - setProperty(target, propName, type, longValue); - return; - } - - /** - */ - public static void setProperty(final Object target, final String propName, final Class type, - final Object propValue) throws Exception { - try { - // Convert the specified value to the required type - final Object newValue; - if (propValue instanceof String) { - newValue = CONVERT_UTILS_BEAN.convert((String) propValue, type); + // Convert to Long + final Long longValue; + if (DateTimeType.DURATION.equals(dateTimeType)) { + final Calendar calendar = Calendar.getInstance(); + calendar.setTime(dateValue); + final long durationMillis = calendar.get(HOUR_OF_DAY) * 3600_000 + // + calendar.get(MINUTE) * 60_000 + // + calendar.get(SECOND) * 1_000; + + longValue = durationMillis; } else { - final Converter converter = CONVERT_UTILS_BEAN.lookup(type); - if (converter != null) { - newValue = converter.convert(type, propValue); - } else { - newValue = propValue; - } + longValue = dateValue.getTime(); } - // Invoke the setter method - PROP_UTILS_BEAN.setProperty(target, propName, newValue); - - } catch (Exception ex) { - // + setProperty(target, propName, propType, longValue); } - } - /** - */ - public static Object getProperty(final Object bean, final String propName) throws Exception { - final Object value = PROP_UTILS_BEAN.getSimpleProperty(bean, propName); - return value; + // } - } From ebb84419ded04f4412025e36dddc10e122023ae4 Mon Sep 17 00:00:00 2001 From: Gowri Shankar Date: Mon, 22 Jul 2024 17:48:09 +0530 Subject: [PATCH 09/10] [test]: added test case for verifying column data type conversions --- .../io/github/millij/bean/DataTypesBean.java | 160 ++++++++++++++++++ .../ss/reader/XlsxReaderDataTypesTest.java | 64 +++++++ .../sample-files/xlsx_sample_data_types.xlsx | Bin 0 -> 5638 bytes 3 files changed, 224 insertions(+) create mode 100644 src/test/java/io/github/millij/bean/DataTypesBean.java create mode 100644 src/test/java/io/github/millij/poi/ss/reader/XlsxReaderDataTypesTest.java create mode 100644 src/test/resources/sample-files/xlsx_sample_data_types.xlsx diff --git a/src/test/java/io/github/millij/bean/DataTypesBean.java b/src/test/java/io/github/millij/bean/DataTypesBean.java new file mode 100644 index 0000000..cb8283d --- /dev/null +++ b/src/test/java/io/github/millij/bean/DataTypesBean.java @@ -0,0 +1,160 @@ +package io.github.millij.bean; + +import static io.github.millij.poi.ss.model.DateTimeType.DATE; +import static io.github.millij.poi.ss.model.DateTimeType.DURATION; + +import java.util.Date; + +import io.github.millij.poi.ss.model.annotations.Sheet; +import io.github.millij.poi.ss.model.annotations.SheetColumn; + + +@Sheet +public class DataTypesBean { + + @SheetColumn("ID") + private String id; + + @SheetColumn("Name") + private String name; + + + // Enum + + @SheetColumn("Gender") + private Gender gender; + + + // Numerical + + @SheetColumn("Age") + private Integer age; + + @SheetColumn("Height") + private Double height; + + + // DateTime fields + + @SheetColumn(value = "Date", datetime = DATE, format = "dd-MM-yyy") + private Date date; + + @SheetColumn(value = "Timestamp", datetime = DATE, format = "dd-MM-yyy HH:mm") + private Long timestamp; // Timestamp + + @SheetColumn(value = "Duration", datetime = DURATION, format = "HH:mm:ss") + private Long duration; + + + // Boolean + + @SheetColumn("Is Active") + private Boolean isActive; + + @SheetColumn("Is Complete") + private Boolean isComplete; + + + // Constructors + // ------------------------------------------------------------------------ + + public DataTypesBean() { + // Default + } + + + // Getters and Setters + // ------------------------------------------------------------------------ + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Gender getGender() { + return gender; + } + + public void setGender(Gender gender) { + this.gender = gender; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } + + public Double getHeight() { + return height; + } + + public void setHeight(Double height) { + this.height = height; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public Long getTimestamp() { + return timestamp; + } + + public void setTimestamp(Long timestamp) { + this.timestamp = timestamp; + } + + public Long getDuration() { + return duration; + } + + public void setDuration(Long duration) { + this.duration = duration; + } + + public Boolean getIsActive() { + return isActive; + } + + public void setIsActive(Boolean isActive) { + this.isActive = isActive; + } + + public Boolean getIsComplete() { + return isComplete; + } + + public void setIsComplete(Boolean isComplete) { + this.isComplete = isComplete; + } + + + // Object Methods + // ------------------------------------------------------------------------ + + @Override + public String toString() { + return "DataTypesBean [id=" + id + ", name=" + name + ", gender=" + gender + ", age=" + age + ", height=" + + height + ", date=" + date + ", timestamp=" + timestamp + ", duration=" + duration + ", isActive=" + + isActive + ", isComplete=" + isComplete + "]"; + } + +} diff --git a/src/test/java/io/github/millij/poi/ss/reader/XlsxReaderDataTypesTest.java b/src/test/java/io/github/millij/poi/ss/reader/XlsxReaderDataTypesTest.java new file mode 100644 index 0000000..a870779 --- /dev/null +++ b/src/test/java/io/github/millij/poi/ss/reader/XlsxReaderDataTypesTest.java @@ -0,0 +1,64 @@ +package io.github.millij.poi.ss.reader; + +import java.io.File; +import java.text.ParseException; +import java.util.List; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import io.github.millij.bean.DataTypesBean; +import io.github.millij.poi.SpreadsheetReadException; + + +public class XlsxReaderDataTypesTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(XlsxReaderDataTypesTest.class); + + // XLSX + private String _filepath_xlsx_data_types; + + + // Setup + // ------------------------------------------------------------------------ + + @Before + public void setup() throws ParseException { + // sample files + _filepath_xlsx_data_types = "src/test/resources/sample-files/xlsx_sample_data_types.xlsx"; + } + + @After + public void teardown() { + // nothing to do + } + + + // Tests + // ------------------------------------------------------------------------ + + + // Read from file + + @Test + public void test_read_xlsx_data_types() throws SpreadsheetReadException { + // Excel Reader + LOGGER.info("test_read_xlsx_data_types :: Reading file - {}", _filepath_xlsx_data_types); + XlsxReader reader = new XlsxReader(); + + // Read + List beans = reader.read(DataTypesBean.class, new File(_filepath_xlsx_data_types)); + Assert.assertNotNull(beans); + Assert.assertTrue(beans.size() > 0); + + for (final DataTypesBean bean : beans) { + LOGGER.info("test_read_xlsx_data_types :: Output - {}", bean); + } + } + + +} diff --git a/src/test/resources/sample-files/xlsx_sample_data_types.xlsx b/src/test/resources/sample-files/xlsx_sample_data_types.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f04c30292542f10e3fc81b72bf762e59a2082fa3 GIT binary patch literal 5638 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 VAv#33DC6Og;XX<@NUZ$n^*;gqoOl2L literal 0 HcmV?d00001 From 3c165cbbc422b7e2786f436fe555f3a2b3a5b828 Mon Sep 17 00:00:00 2001 From: Gowri Shankar Date: Mon, 22 Jul 2024 18:11:36 +0530 Subject: [PATCH 10/10] [util]: updated Beans#setProperty, added Enum types property Value handling --- src/main/java/io/github/millij/poi/util/Beans.java | 12 +++++++++++- .../java/io/github/millij/poi/util/Spreadsheet.java | 5 +++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/github/millij/poi/util/Beans.java b/src/main/java/io/github/millij/poi/util/Beans.java index 8a9b430..4884f0d 100644 --- a/src/main/java/io/github/millij/poi/util/Beans.java +++ b/src/main/java/io/github/millij/poi/util/Beans.java @@ -155,6 +155,7 @@ public static void setProperty(final Object target, final String propName, final /** */ + @SuppressWarnings({"unchecked", "rawtypes"}) public static void setProperty(final Object target, final String propName, final Object propValue, final String format, final DateTimeType dateTimeType) throws Exception { // Sanity checks @@ -178,11 +179,20 @@ public static void setProperty(final Object target, final String propName, final return; } + // + // Handle ENUM + if (propType.isEnum() && (propValue instanceof String)) { + final String cleanEnumStr = Strings.normalize((String) propValue).toUpperCase(); + final Enum enumValue = Enum.valueOf((Class) propType, cleanEnumStr); + setProperty(target, propName, propType, enumValue); + return; + } + // // Handle Boolean if (propType.equals(Boolean.class) && (propValue instanceof String)) { // Cleanup Boolean String - final String cleanBoolStr = Strings.normalize((String) propValue); + final String cleanBoolStr = Strings.normalize((String) propValue); // for cases like "FALSE()", "TRUE()" setProperty(target, propName, propType, cleanBoolStr); return; } diff --git a/src/main/java/io/github/millij/poi/util/Spreadsheet.java b/src/main/java/io/github/millij/poi/util/Spreadsheet.java index 48f70be..3057513 100644 --- a/src/main/java/io/github/millij/poi/util/Spreadsheet.java +++ b/src/main/java/io/github/millij/poi/util/Spreadsheet.java @@ -278,8 +278,9 @@ public static T rowAsBean(Class beanClz, Map propColumnMa // Set the property value in the current row object bean Beans.setProperty(bean, propName, propValue, dataFormat, datetimeType); } catch (Exception ex) { - String errMsg = String.format("Failed to set bean property - %s, value - %s", propName, propValue); - LOGGER.error(errMsg, ex); + String exMsg = ex.getMessage(); + String errMsg = String.format("Error setting prop - %s, val - %s : %s", propName, propValue, exMsg); + LOGGER.error(errMsg); } }