diff --git a/.gitignore b/.gitignore index 68f0d82..c66539f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,193 @@ + +# Created by https://www.gitignore.io/api/linux,macos,windows,intellij,libreoffice,microsoftoffice +# Edit at https://www.gitignore.io/?templates=linux,macos,windows,intellij,libreoffice,microsoftoffice + +### Intellij ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Intellij Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +.idea/**/sonarlint/ + +# SonarQube Plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator/ + +### LibreOffice ### +# LibreOffice locks +.~lock.*# + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### MicrosoftOffice ### +*.tmp + +# Word temporary +~$*.doc* + +# Word Auto Backup File +Backup of *.doc* + +# Excel temporary +~$*.xls* + +# Excel Backup File +*.xlk + +# PowerPoint temporary +~$*.ppt* + +# Visio autosave temporary files +*.~vsd* + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.gitignore.io/api/linux,macos,windows,intellij,libreoffice,microsoftoffice + +# User added + .idea p2o.iml target/ diff --git a/src/main/java/com/poiji/annotation/ExcelUnknownCells.java b/src/main/java/com/poiji/annotation/ExcelUnknownCells.java new file mode 100644 index 0000000..fabd30b --- /dev/null +++ b/src/main/java/com/poiji/annotation/ExcelUnknownCells.java @@ -0,0 +1,18 @@ +package com.poiji.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotations allows you to put every unknown cell (neither mapped by name, nor by index) into a {@code Map} + * + * @author Pascal Breuer + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Documented +public @interface ExcelUnknownCells { +} diff --git a/src/main/java/com/poiji/bind/mapping/HSSFUnmarshaller.java b/src/main/java/com/poiji/bind/mapping/HSSFUnmarshaller.java index e9ac2e3..9b46019 100644 --- a/src/main/java/com/poiji/bind/mapping/HSSFUnmarshaller.java +++ b/src/main/java/com/poiji/bind/mapping/HSSFUnmarshaller.java @@ -4,6 +4,7 @@ import com.poiji.annotation.ExcelCellName; import com.poiji.annotation.ExcelCellRange; import com.poiji.annotation.ExcelRow; +import com.poiji.annotation.ExcelUnknownCells; import com.poiji.bind.Unmarshaller; import com.poiji.config.Casting; import com.poiji.exception.IllegalCastException; @@ -17,10 +18,16 @@ import org.apache.poi.ss.usermodel.Workbook; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Spliterator; +import java.util.Spliterators; import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import static java.lang.String.valueOf; @@ -33,7 +40,8 @@ abstract class HSSFUnmarshaller implements Unmarshaller { private final DataFormatter dataFormatter; protected final PoijiOptions options; private final Casting casting; - private Map titles; + private Map columnIndexPerTitle; + private Map titlePerColumnIndex; private int limit; private int internalCount; @@ -41,7 +49,8 @@ abstract class HSSFUnmarshaller implements Unmarshaller { this.options = options; this.limit = options.getLimit(); dataFormatter = new DataFormatter(); - titles = new HashMap<>(); + columnIndexPerTitle = new HashMap<>(); + titlePerColumnIndex = new HashMap<>(); casting = options.getCasting(); } @@ -61,7 +70,7 @@ public void unmarshal(Class type, Consumer consumer) { if (!skip(currentRow, skip) && !isRowEmpty(currentRow)) { internalCount += 1; - if(limit != 0 && internalCount > limit) + if (limit != 0 && internalCount > limit) return; T t = deserialize0(currentRow, type); @@ -75,81 +84,117 @@ private Sheet getSheetToProcess(Workbook workbook, PoijiOptions options, String int requestedIndex = options.sheetIndex(); Sheet sheet = null; if (options.ignoreHiddenSheets()) { - for (int i = 0; i < workbook.getNumberOfSheets(); i++) { - if (!workbook.isSheetHidden(i) && !workbook.isSheetVeryHidden(i)) { - if (sheetName == null) { - if (nonHiddenSheetIndex == requestedIndex) { - return workbook.getSheetAt(i); + for (int i = 0; i < workbook.getNumberOfSheets(); i++) { + if (!workbook.isSheetHidden(i) && !workbook.isSheetVeryHidden(i)) { + if (sheetName == null) { + if (nonHiddenSheetIndex == requestedIndex) { + return workbook.getSheetAt(i); + } + } else { + if (workbook.getSheetName(i).equalsIgnoreCase(sheetName)) { + return workbook.getSheetAt(i); + } + } + nonHiddenSheetIndex++; } - } else { - if (workbook.getSheetName(i).equalsIgnoreCase(sheetName)) { - return workbook.getSheetAt(i); - } - } - nonHiddenSheetIndex++; } - } } else { - if (sheetName == null) { - sheet = workbook.getSheetAt(requestedIndex); - } else { - sheet = workbook.getSheet(sheetName); - } + if (sheetName == null) { + sheet = workbook.getSheetAt(requestedIndex); + } else { + sheet = workbook.getSheet(sheetName); + } } return sheet; - } + } private void loadColumnTitles(Sheet sheet, int maxPhysicalNumberOfRows) { if (maxPhysicalNumberOfRows > 0) { int row = options.getHeaderStart(); Row firstRow = sheet.getRow(row); for (Cell cell : firstRow) { - titles.put(cell.getStringCellValue(), cell.getColumnIndex()); + columnIndexPerTitle.put(cell.getStringCellValue(), cell.getColumnIndex()); + + titlePerColumnIndex.put(cell.getColumnIndex(), + getTitleNameForMap(cell.getStringCellValue(), cell.getColumnIndex())); } } } + private String getTitleNameForMap(String cellContent, int columnIndex) { + String titleName; + if (titlePerColumnIndex.containsValue(cellContent) + || cellContent.isEmpty()) { + titleName = cellContent + "@" + columnIndex; + } else { + titleName = cellContent; + } + return titleName; + } + private T deserialize0(Row currentRow, Class type) { T instance = ReflectUtil.newInstanceOf(type); return setFieldValue(currentRow, type, instance); } private T tailSetFieldValue(Row currentRow, Class type, T instance) { + List mappedColumnIndices = new ArrayList<>(); + List unknownCells = new ArrayList<>(); + for (Field field : type.getDeclaredFields()) { ExcelRow excelRow = field.getAnnotation(ExcelRow.class); + ExcelCellRange excelCellRange = field.getAnnotation(ExcelCellRange.class); + ExcelUnknownCells excelUnknownCells = field.getAnnotation(ExcelUnknownCells.class); if (excelRow != null) { Object o; o = casting.castValue(field.getType(), valueOf(currentRow.getRowNum()), currentRow.getRowNum(), -1, options); setFieldData(instance, field, o); - } - ExcelCellRange excelCellRange = field.getAnnotation(ExcelCellRange.class); - if (excelCellRange != null) { + } else if (excelCellRange != null) { + Class o = field.getType(); Object ins = ReflectUtil.newInstanceOf(o); for (Field f : o.getDeclaredFields()) { - tailSetFieldValue(currentRow, ins, f); + mappedColumnIndices.add(tailSetFieldValue(currentRow, ins, f)); } setFieldData(instance, field, ins); + } else if (excelUnknownCells != null) { + unknownCells.add(field); } else { - tailSetFieldValue(currentRow, instance, field); + mappedColumnIndices.add(tailSetFieldValue(currentRow, instance, field)); } } + + Map excelUnknownCellsMap = StreamSupport + .stream(Spliterators.spliteratorUnknownSize(currentRow.cellIterator(), Spliterator.ORDERED), false) + .filter(cell -> !mappedColumnIndices.contains(cell.getColumnIndex())) + .filter(cell -> !cell.toString().isEmpty()) + .collect(Collectors.toMap( + cell -> titlePerColumnIndex.get(cell.getColumnIndex()), + Object::toString + )); + + unknownCells.forEach(field -> setFieldData(instance, field, excelUnknownCellsMap)); + return instance; } - private void tailSetFieldValue(Row currentRow, T instance, Field field) { + private Integer tailSetFieldValue(Row currentRow, T instance, Field field) { ExcelCell index = field.getAnnotation(ExcelCell.class); if (index != null) { constructTypeValue(currentRow, instance, field, index.value()); + return index.value(); } else { ExcelCellName excelCellName = field.getAnnotation(ExcelCellName.class); if (excelCellName != null) { - Integer titleColumn = titles.get(excelCellName.value()); + Integer titleColumn = columnIndexPerTitle.get(excelCellName.value()); if (titleColumn != null) { constructTypeValue(currentRow, instance, field, titleColumn); + return titleColumn; } } } + + return null; } private void constructTypeValue(Row currentRow, T instance, Field field, int column) { diff --git a/src/main/java/com/poiji/bind/mapping/PoijiHandler.java b/src/main/java/com/poiji/bind/mapping/PoijiHandler.java index acec623..14dfc60 100644 --- a/src/main/java/com/poiji/bind/mapping/PoijiHandler.java +++ b/src/main/java/com/poiji/bind/mapping/PoijiHandler.java @@ -4,6 +4,7 @@ import com.poiji.annotation.ExcelCellName; import com.poiji.annotation.ExcelCellRange; import com.poiji.annotation.ExcelRow; +import com.poiji.annotation.ExcelUnknownCells; import com.poiji.config.Casting; import com.poiji.exception.IllegalCastException; import com.poiji.option.PoijiOptions; @@ -16,6 +17,7 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; +import java.util.stream.Stream; import static java.lang.String.valueOf; @@ -37,7 +39,8 @@ final class PoijiHandler implements SheetContentsHandler { private PoijiOptions options; private final Casting casting; - private Map titles; + private Map columnIndexPerTitle; + private Map titlePerColumnIndex; // New maps used to speed up computing and handle inner objects private Map fieldInstances; private Map columnToField; @@ -50,7 +53,8 @@ final class PoijiHandler implements SheetContentsHandler { this.limit = options.getLimit(); casting = options.getCasting(); - titles = new HashMap<>(); + columnIndexPerTitle = new HashMap<>(); + titlePerColumnIndex = new HashMap<>(); columnToField = new HashMap<>(); columnToSuperClassField = new HashMap<>(); } @@ -80,37 +84,61 @@ private Object getInstance(Field field) { private boolean setValue(String content, Class type, int column) { - for (Field field : type.getDeclaredFields()) { - ExcelRow excelRow = field.getAnnotation(ExcelRow.class); - if (excelRow != null) { - Object o = casting.castValue(field.getType(), valueOf(internalCount), options); - setFieldData(field, o, instance); - columnToField.put(-1, field); - } - ExcelCellRange range = field.getAnnotation(ExcelCellRange.class); - if (range != null) { - Object ins = null; - ins = getInstance(field); - for (Field f : field.getType().getDeclaredFields()) { - if (setValue(f, column, content, ins)) { - setFieldData(field, ins, instance); - columnToField.put(column, f); - columnToSuperClassField.put(column, field); -// return true; + + Stream.of(type.getDeclaredFields()) + .filter(field -> field.getAnnotation(ExcelUnknownCells.class) == null) + .forEach(field -> { + ExcelRow excelRow = field.getAnnotation(ExcelRow.class); + if (excelRow != null) { + Object o = casting.castValue(field.getType(), valueOf(internalRow), options); + setFieldData(field, o, instance); + columnToField.put(-1, field); } - } - } else { - if(setValue(field, column, content, instance)) { - columnToField.put(column, field); + ExcelCellRange range = field.getAnnotation(ExcelCellRange.class); + if (range != null) { + Object ins = null; + ins = getInstance(field); + for (Field f : field.getType().getDeclaredFields()) { + if (setValue(f, column, content, ins)) { + setFieldData(field, ins, instance); + columnToField.put(column, f); + columnToSuperClassField.put(column, field); +// return true; + } + } + } else { + if(setValue(field, column, content, instance)) { + columnToField.put(column, field); // return true; - } - } - } + } + } + }); + + Stream.of(type.getDeclaredFields()) + .filter(field -> field.getAnnotation(ExcelUnknownCells.class) != null) + .forEach(field -> { + if (!columnToField.containsKey(column)) { + try { + Map excelUnknownCellsMap; + field.setAccessible(true); + if (field.get(instance) == null) { + excelUnknownCellsMap = new HashMap<>(); + setFieldData(field, excelUnknownCellsMap, instance); + } else { + excelUnknownCellsMap = (Map) field.get(instance); + } + + excelUnknownCellsMap.put(titlePerColumnIndex.get(column), content); + } catch (IllegalAccessException e) { + throw new IllegalCastException("Could not read content of field " + field.getName() + " on Object {" + instance + "}"); + } + } + }); // For ExcelRow annotation if(columnToField.containsKey(-1)) { Field field = columnToField.get(-1); - Object o = casting.castValue(field.getType(), valueOf(internalCount), options); + Object o = casting.castValue(field.getType(), valueOf(internalRow), options); setFieldData(field, o, instance); } if(columnToField.containsKey(column)) { @@ -136,12 +164,13 @@ private boolean setValue(Field field, int column, String content, Object ins) { if (column == index.value()) { Object o = casting.castValue(fieldType, content, options); setFieldData(field, o, ins); + return true; } } else { ExcelCellName excelCellName = field.getAnnotation(ExcelCellName.class); if (excelCellName != null) { Class fieldType = field.getType(); - Integer titleColumn = titles.get(excelCellName.value() ); + Integer titleColumn = columnIndexPerTitle.get(excelCellName.value() ); //Fix both columns mapped to name passing this condition below if (titleColumn != null && titleColumn == column) { Object o = casting.castValue(fieldType, content, options); @@ -191,7 +220,9 @@ public void cell(String cellReference, String formattedValue, XSSFComment commen int column = cellAddress.getColumn(); if (row <= headers) { - titles.put(formattedValue, column); + columnIndexPerTitle.put(formattedValue, column); + + titlePerColumnIndex.put(column, getTitleNameForMap(formattedValue, column)); } if (row + 1 <= options.skip()) { @@ -207,6 +238,17 @@ public void cell(String cellReference, String formattedValue, XSSFComment commen setFieldValue(formattedValue, type, column); } + private String getTitleNameForMap(String cellContent, int columnIndex) { + String titleName; + if (titlePerColumnIndex.containsValue(cellContent) + || cellContent.isEmpty()) { + titleName = cellContent + "@" + columnIndex; + } else { + titleName = cellContent; + } + return titleName; + } + @Override public void headerFooter(String text, boolean isHeader, String tagName) { //no-op diff --git a/src/test/java/com/poiji/deserialize/MissingRowIndexTest.java b/src/test/java/com/poiji/deserialize/MissingRowIndexTest.java new file mode 100644 index 0000000..f093b75 --- /dev/null +++ b/src/test/java/com/poiji/deserialize/MissingRowIndexTest.java @@ -0,0 +1,49 @@ +package com.poiji.deserialize; + +import com.poiji.bind.Poiji; +import com.poiji.deserialize.model.byname.OrganisationByName; +import com.poiji.option.PoijiOptions; +import org.junit.Test; + +import java.io.File; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +public class MissingRowIndexTest { + + @Test + public void emptyLine() { + + List organisations = Poiji.fromExcel( + new File("src/test/resources/missing-row-1.xlsx"), + OrganisationByName.class, + PoijiOptions.PoijiOptionsBuilder.settings() + .sheetName("Organisation") + .build() + ); + assertThat(organisations, notNullValue()); + assertThat(organisations.size(), is(2)); + assertThat(organisations.stream().map(OrganisationByName::getRowIndex).min(Integer::compareTo).get(), is(2)); + assertThat(organisations.stream().map(OrganisationByName::getRowIndex).max(Integer::compareTo).get(), is(3)); + } + + @Test + public void nullLine() { + + List organisations = Poiji.fromExcel( + new File("src/test/resources/missing-row-2.xlsx"), + OrganisationByName.class, + PoijiOptions.PoijiOptionsBuilder.settings() + .sheetName("Organisation") + .build() + ); + + assertThat(organisations, notNullValue()); + assertThat(organisations.size(), is(4)); + assertThat(organisations.stream().map(OrganisationByName::getRowIndex).min(Integer::compareTo).get(), is(2)); + assertThat(organisations.stream().map(OrganisationByName::getRowIndex).max(Integer::compareTo).get(), is(5)); + } +} diff --git a/src/test/java/com/poiji/deserialize/UnknownCellsTest.java b/src/test/java/com/poiji/deserialize/UnknownCellsTest.java new file mode 100644 index 0000000..3d2ee01 --- /dev/null +++ b/src/test/java/com/poiji/deserialize/UnknownCellsTest.java @@ -0,0 +1,93 @@ +package com.poiji.deserialize; + +import com.poiji.bind.Poiji; +import com.poiji.deserialize.model.byid.OrgWithUnknownCells; +import com.poiji.deserialize.model.byname.OrgWithUnknownCellsByName; +import com.poiji.option.PoijiOptions; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; + +@RunWith(Parameterized.class) +public class UnknownCellsTest { + + private String path; + + public UnknownCellsTest(String path) { + this.path = path; + } + + @Parameterized.Parameters + public static List excel() { + return Arrays.asList( + "src/test/resources/unknown-cells.xlsx", + "src/test/resources/unknown-cells.xls" + ); + } + + @Test + public void byName() { + List organisations = Poiji.fromExcel( + new File(path), + OrgWithUnknownCellsByName.class, + PoijiOptions.PoijiOptionsBuilder.settings() + .sheetName("Organisation") + .build() + ); + + assertThat(organisations, notNullValue()); + assertThat(organisations.size(), is(2)); + + OrgWithUnknownCellsByName firstRow = organisations.stream() + .filter(org -> org.getId().equals("CrEaTe")) + .findFirst() + .get(); + assertThat(firstRow.getUnknownCells().size(), is(1)); + assertThat(firstRow.getUnknownCells().get("Region"), is("EMEA")); + + + OrgWithUnknownCellsByName secondRow = organisations.stream() + .filter(org -> org.getId().equals("8d9e6430-8626-4556-8004-079085d2df2d")) + .findFirst() + .get(); + assertThat(secondRow.getUnknownCells().size(), is(1)); + assertThat(secondRow.getUnknownCells().get("Region"), is("NA")); + } + + @Test + public void byIndex() { + List organisations = Poiji.fromExcel( + new File(path), + OrgWithUnknownCells.class, + PoijiOptions.PoijiOptionsBuilder.settings() + .sheetName("Organisation") + .build() + ); + + assertThat(organisations, notNullValue()); + assertThat(organisations.size(), is(2)); + + OrgWithUnknownCells firstRow = organisations.stream() + .filter(org -> org.getId().equals("CrEaTe")) + .findFirst() + .get(); + assertThat(firstRow.getUnknownCells().size(), is(1)); + assertThat(firstRow.getUnknownCells().get("Region"), is("EMEA")); + + + OrgWithUnknownCells secondRow = organisations.stream() + .filter(org -> org.getId().equals("8d9e6430-8626-4556-8004-079085d2df2d")) + .findFirst() + .get(); + assertThat(secondRow.getUnknownCells().size(), is(1)); + assertThat(secondRow.getUnknownCells().get("Region"), is("NA")); + } +} diff --git a/src/test/java/com/poiji/deserialize/model/byid/OrgWithUnknownCells.java b/src/test/java/com/poiji/deserialize/model/byid/OrgWithUnknownCells.java new file mode 100644 index 0000000..c14b77f --- /dev/null +++ b/src/test/java/com/poiji/deserialize/model/byid/OrgWithUnknownCells.java @@ -0,0 +1,72 @@ +package com.poiji.deserialize.model.byid; + +import com.poiji.annotation.ExcelCell; +import com.poiji.annotation.ExcelRow; +import com.poiji.annotation.ExcelUnknownCells; + +import java.util.Map; + +public class OrgWithUnknownCells { + + @ExcelRow + private int rowIndex; + + @ExcelCell(0) + private String id; + + @ExcelCell(1) + private String externalId; + + @ExcelUnknownCells + private Map unknownCells; + + public Map getUnknownCells() { + return unknownCells; + } + + @ExcelCell(2) + private String name; + + @ExcelCell(3) + private String customerExternalId; + + public int getRowIndex() { + return rowIndex; + } + + public void setRowIndex(int rowIndex) { + this.rowIndex = rowIndex; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCustomerExternalId() { + return customerExternalId; + } + + public void setCustomerExternalId(String customerExternalId) { + this.customerExternalId = customerExternalId; + } +} diff --git a/src/test/java/com/poiji/deserialize/model/byname/OrgWithUnknownCellsByName.java b/src/test/java/com/poiji/deserialize/model/byname/OrgWithUnknownCellsByName.java new file mode 100644 index 0000000..66464ee --- /dev/null +++ b/src/test/java/com/poiji/deserialize/model/byname/OrgWithUnknownCellsByName.java @@ -0,0 +1,77 @@ +package com.poiji.deserialize.model.byname; + +import com.poiji.annotation.ExcelCellName; +import com.poiji.annotation.ExcelRow; +import com.poiji.annotation.ExcelUnknownCells; + +import java.util.Map; + +public class OrgWithUnknownCellsByName { + + public static final String HEADER_ORGANISATION_ID = "Organisation ID"; + public static final String HEADER_CUSTOMER_EXTERNAL_ID = "Customer External ID"; + public static final String HEADER_ORGANISATION_EXTERNAL_ID = "Organisation External ID"; + public static final String HEADER_ORGANISATION_NAME = "Organisation Name"; + + @ExcelRow + private int rowIndex; + + @ExcelCellName(HEADER_ORGANISATION_ID) + private String id; + + @ExcelCellName(HEADER_ORGANISATION_EXTERNAL_ID) + private String externalId; + + @ExcelUnknownCells + private Map unknownCells; + + public Map getUnknownCells() { + return unknownCells; + } + + @ExcelCellName(HEADER_ORGANISATION_NAME) + private String name; + + @ExcelCellName(HEADER_CUSTOMER_EXTERNAL_ID) + private String customerExternalId; + + public int getRowIndex() { + return rowIndex; + } + + public void setRowIndex(int rowIndex) { + this.rowIndex = rowIndex; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCustomerExternalId() { + return customerExternalId; + } + + public void setCustomerExternalId(String customerExternalId) { + this.customerExternalId = customerExternalId; + } +} diff --git a/src/test/java/com/poiji/deserialize/model/byname/OrganisationByName.java b/src/test/java/com/poiji/deserialize/model/byname/OrganisationByName.java new file mode 100644 index 0000000..d9c436e --- /dev/null +++ b/src/test/java/com/poiji/deserialize/model/byname/OrganisationByName.java @@ -0,0 +1,67 @@ +package com.poiji.deserialize.model.byname; + +import com.poiji.annotation.ExcelCellName; +import com.poiji.annotation.ExcelRow; + +public class OrganisationByName { + + public static final String HEADER_ORGANISATION_ID = "Organisation ID"; + public static final String HEADER_CUSTOMER_EXTERNAL_ID = "Customer External ID"; + public static final String HEADER_ORGANISATION_EXTERNAL_ID = "Organisation External ID"; + public static final String HEADER_ORGANISATION_NAME = "Organisation Name"; + + @ExcelRow + private int rowIndex; + + @ExcelCellName(HEADER_ORGANISATION_ID) + private String id; + + @ExcelCellName(HEADER_ORGANISATION_EXTERNAL_ID) + private String externalId; + + @ExcelCellName(HEADER_ORGANISATION_NAME) + private String name; + + @ExcelCellName(HEADER_CUSTOMER_EXTERNAL_ID) + private String customerExternalId; + + public int getRowIndex() { + return rowIndex; + } + + public void setRowIndex(int rowIndex) { + this.rowIndex = rowIndex; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getExternalId() { + return externalId; + } + + public void setExternalId(String externalId) { + this.externalId = externalId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCustomerExternalId() { + return customerExternalId; + } + + public void setCustomerExternalId(String customerExternalId) { + this.customerExternalId = customerExternalId; + } +} diff --git a/src/test/resources/missing-row-1.xlsx b/src/test/resources/missing-row-1.xlsx new file mode 100644 index 0000000..5f4b8c2 Binary files /dev/null and b/src/test/resources/missing-row-1.xlsx differ diff --git a/src/test/resources/missing-row-2.xlsx b/src/test/resources/missing-row-2.xlsx new file mode 100644 index 0000000..5697ebf Binary files /dev/null and b/src/test/resources/missing-row-2.xlsx differ diff --git a/src/test/resources/unknown-cells.xls b/src/test/resources/unknown-cells.xls new file mode 100644 index 0000000..632bbc0 Binary files /dev/null and b/src/test/resources/unknown-cells.xls differ diff --git a/src/test/resources/unknown-cells.xlsx b/src/test/resources/unknown-cells.xlsx new file mode 100644 index 0000000..0a772f0 Binary files /dev/null and b/src/test/resources/unknown-cells.xlsx differ