diff --git a/README.adoc b/README.adoc index 38329f9..263a9ff 100644 --- a/README.adoc +++ b/README.adoc @@ -2,8 +2,8 @@ :toclevels: 2 = Poiji -:version: v4.4.0 -:branch: 4.4.0 +:version: v4.5.0 +:branch: 4.5.0 image:https://github.com/ozlerhakan/poiji/actions/workflows/maven.yml/badge.svg["Build Status"] image:https://app.codacy.com/project/badge/Grade/64f7e2cb9e604807b62334a4cfc3952d["Codacy code quality",link="https://www.codacy.com/gh/ozlerhakan/poiji/dashboard?utm_source=github.com&utm_medium=referral&utm_content=ozlerhakan/poiji&utm_campaign=Badge_Grade"] image:https://codecov.io/gh/ozlerhakan/poiji/branch/{branch}/graph/badge.svg?token=MN6V6xOWBq["Codecov",link="https://codecov.io/gh/ozlerhakan/poiji"] image:https://img.shields.io/badge/apache.poi-5.2.3-brightgreen.svg[] image:https://app.fossa.com/api/projects/git%2Bgithub.com%2Fozlerhakan%2Fpoiji.svg?type=shield["FOSSA Status",link="https://app.fossa.com/projects/git%2Bgithub.com%2Fozlerhakan%2Fpoiji?ref=badge_shield"] @@ -25,7 +25,7 @@ In your Maven/Gradle project, first add the corresponding dependency: com.github.ozlerhakan poiji - 4.4.0 + 4.5.0 ---- @@ -710,7 +710,7 @@ The `mandatoryHeader` field is compatible with XLS and XLSX files. [NOTE] ==== -The `mandatoryCell` field works **only** with XLS files. +The `mandatoryCell` field works **only** with XLS files and `Sheet` instances. XLS workbooks are opened with `RETURN_BLANK_AS_NULL` missing cell policy. If passing a `Sheet` instance it is up for the caller to make sure the missing cell policy of the parent workbook is set accordingly. ==== === Debug Cells Formats diff --git a/pom.xml b/pom.xml index b9992b7..23a8140 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.github.ozlerhakan poiji - 4.4.0 + 4.5.0 jar poiji diff --git a/src/main/java/com/poiji/bind/mapping/HSSFUnmarshallerFile.java b/src/main/java/com/poiji/bind/mapping/HSSFUnmarshallerFile.java index 077eb8e..a30777d 100644 --- a/src/main/java/com/poiji/bind/mapping/HSSFUnmarshallerFile.java +++ b/src/main/java/com/poiji/bind/mapping/HSSFUnmarshallerFile.java @@ -3,6 +3,7 @@ import com.poiji.bind.PoijiFile; import com.poiji.exception.PoijiException; import com.poiji.option.PoijiOptions; +import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; @@ -24,7 +25,9 @@ final class HSSFUnmarshallerFile extends HSSFUnmarshaller { @Override protected Workbook workbook() { try { - return WorkbookFactory.create(poijiFile.file(), options.getPassword(), true); + Workbook workbook = WorkbookFactory.create(poijiFile.file(), options.getPassword(), true); + workbook.setMissingCellPolicy(Row.MissingCellPolicy.RETURN_BLANK_AS_NULL); + return workbook; } catch (IOException e) { throw new PoijiException("Problem occurred while creating HSSFWorkbook", e); } diff --git a/src/main/java/com/poiji/bind/mapping/HSSFUnmarshallerStream.java b/src/main/java/com/poiji/bind/mapping/HSSFUnmarshallerStream.java index 9683d7e..3ed33c7 100644 --- a/src/main/java/com/poiji/bind/mapping/HSSFUnmarshallerStream.java +++ b/src/main/java/com/poiji/bind/mapping/HSSFUnmarshallerStream.java @@ -3,6 +3,7 @@ import com.poiji.bind.PoijiInputStream; import com.poiji.exception.PoijiException; import com.poiji.option.PoijiOptions; +import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; @@ -23,12 +24,14 @@ final class HSSFUnmarshallerStream extends HSSFUnmarshaller { @Override protected Workbook workbook() { try { - + Workbook workbook; if (options.getPassword() != null) { - return WorkbookFactory.create(poijiInputStream.stream(), options.getPassword()); + workbook = WorkbookFactory.create(poijiInputStream.stream(), options.getPassword()); + } else { + workbook = WorkbookFactory.create(poijiInputStream.stream()); } - - return WorkbookFactory.create(poijiInputStream.stream()); + workbook.setMissingCellPolicy(Row.MissingCellPolicy.RETURN_BLANK_AS_NULL); + return workbook; } catch (IOException e) { throw new PoijiException("Problem occurred while creating HSSFWorkbook", e); } diff --git a/src/test/java/com/poiji/deserialize/MandatoryCellsExceptionTest.java b/src/test/java/com/poiji/deserialize/MandatoryCellsExceptionTest.java index 0571b9f..14be6e1 100644 --- a/src/test/java/com/poiji/deserialize/MandatoryCellsExceptionTest.java +++ b/src/test/java/com/poiji/deserialize/MandatoryCellsExceptionTest.java @@ -2,18 +2,20 @@ import com.poiji.bind.Poiji; import com.poiji.deserialize.model.byname.MandatoryMissingCells; +import com.poiji.exception.PoijiExcelType; import com.poiji.exception.PoijiMultiRowException; import com.poiji.exception.PoijiMultiRowException.PoijiRowSpecificException; import com.poiji.option.PoijiOptions; - import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.junit.Test; -import java.io.IOException; +import java.io.*; import java.util.List; import static org.junit.Assert.assertEquals; @@ -22,7 +24,7 @@ public class MandatoryCellsExceptionTest { @Test - public void testExcelMandatoryColumn() { + public void shouldThrowExceptionForMissingCell() { try { Poiji.fromExcel(createDummyExcel(), MandatoryMissingCells.class, PoijiOptions.PoijiOptionsBuilder .settings() @@ -38,6 +40,58 @@ public void testExcelMandatoryColumn() { fail("Expected exception: " + PoijiMultiRowException.class.getName()); } + @Test + public void shouldThrowExceptionForBlankCellInSheet() throws IOException { + try (InputStream stream = new FileInputStream("src/test/resources/blank-cell.xlsx"); + XSSFWorkbook workbook = new XSSFWorkbook(stream)) { + workbook.setMissingCellPolicy(Row.MissingCellPolicy.RETURN_BLANK_AS_NULL); + XSSFSheet sheet = workbook.getSheetAt(0); + Poiji.fromExcel(sheet, MandatoryMissingCells.class, PoijiOptions.PoijiOptionsBuilder + .settings() + .build()); + } catch (PoijiMultiRowException e) { + List errors = e.getErrors(); + assertEquals(1, errors.size()); + assertEquals("Address", errors.get(0).getColumnName()); + assertEquals("address", errors.get(0).getFieldName()); + assertEquals((Integer) 1, errors.get(0).getRowNum()); + return; + } + fail("Expected exception: " + PoijiMultiRowException.class.getName()); + } + + @Test + public void shouldThrowExceptionForBlankCellInFile() { + try { + Poiji.fromExcel(new File("src/test/resources/blank-cell.xls"), MandatoryMissingCells.class, + PoijiOptions.PoijiOptionsBuilder.settings().build()); + } catch (PoijiMultiRowException e) { + List errors = e.getErrors(); + assertEquals(1, errors.size()); + assertEquals("Address", errors.get(0).getColumnName()); + assertEquals("address", errors.get(0).getFieldName()); + assertEquals((Integer) 1, errors.get(0).getRowNum()); + return; + } + fail("Expected exception: " + PoijiMultiRowException.class.getName()); + } + + @Test + public void shouldThrowExceptionForBlankCellInStream() throws IOException { + try (InputStream stream = new FileInputStream("src/test/resources/blank-cell.xls")) { + Poiji.fromExcel(stream, PoijiExcelType.XLS, MandatoryMissingCells.class, + PoijiOptions.PoijiOptionsBuilder.settings().build()); + } catch (PoijiMultiRowException e) { + List errors = e.getErrors(); + assertEquals(1, errors.size()); + assertEquals("Address", errors.get(0).getColumnName()); + assertEquals("address", errors.get(0).getFieldName()); + assertEquals((Integer) 1, errors.get(0).getRowNum()); + return; + } + fail("Expected exception: " + PoijiMultiRowException.class.getName()); + } + private Sheet createDummyExcel() { Workbook workbook = new HSSFWorkbook(); diff --git a/src/test/java/com/poiji/parser/NumberParserTest.java b/src/test/java/com/poiji/parser/NumberParserTest.java new file mode 100644 index 0000000..5508786 --- /dev/null +++ b/src/test/java/com/poiji/parser/NumberParserTest.java @@ -0,0 +1,27 @@ +package com.poiji.parser; + +import org.junit.Test; + +import com.poiji.option.PoijiOptions; +import com.poiji.option.PoijiOptions.PoijiOptionsBuilder; + +import static org.junit.Assert.assertEquals; + +import java.text.NumberFormat; + +public class NumberParserTest { + @Test + public void parseNumber() { + PoijiOptions options = PoijiOptionsBuilder.settings().build(); + NumberParser numParser = new NumberParser(NumberFormat.getInstance(options.getLocale())); + Number expectedNumber = numParser.parse("1").doubleValue(); + assertEquals(expectedNumber.doubleValue(), 1.0, 0); + } + + @Test(expected = NumberFormatException.class) + public void parseNullNumber() { + PoijiOptions options = PoijiOptionsBuilder.settings().build(); + NumberParser numParser = new NumberParser(NumberFormat.getInstance(options.getLocale())); + numParser.parse(null).doubleValue(); + } +} diff --git a/src/test/java/com/poiji/util/DefaultCastingTest.java b/src/test/java/com/poiji/util/DefaultCastingTest.java index ccf4fab..07c76c8 100644 --- a/src/test/java/com/poiji/util/DefaultCastingTest.java +++ b/src/test/java/com/poiji/util/DefaultCastingTest.java @@ -266,6 +266,12 @@ public void castBigDecimal() { assertEquals(BigDecimal.valueOf(81.56891), testVal); } + @Test + public void castEmptyString() { + Object testVal = casting.castValue(String.class, "", options); + assertEquals("", testVal); + } + static class MyConfig extends DefaultCasting { Object castValue(Class fieldType, String value, PoijiOptions options) { return getValueObject(null, -1, -1, options, value, fieldType); diff --git a/src/test/resources/blank-cell.xls b/src/test/resources/blank-cell.xls new file mode 100644 index 0000000..b11c0b3 Binary files /dev/null and b/src/test/resources/blank-cell.xls differ diff --git a/src/test/resources/blank-cell.xlsx b/src/test/resources/blank-cell.xlsx new file mode 100644 index 0000000..d89082f Binary files /dev/null and b/src/test/resources/blank-cell.xlsx differ