diff --git a/README.adoc b/README.adoc index 6e5ca83..7e66a19 100644 --- a/README.adoc +++ b/README.adoc @@ -2,8 +2,8 @@ :toclevels: 2 = Poiji -:version: v4.2.0 -:branch: 4.2.0 +:version: v4.3.0 +:branch: 4.3.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.2.0 + 4.3.0 ---- diff --git a/pom.xml b/pom.xml index bf595ca..b1af229 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.github.ozlerhakan poiji - 4.2.0 + 4.3.0 jar poiji diff --git a/src/main/java/com/poiji/annotation/ExcelCellName.java b/src/main/java/com/poiji/annotation/ExcelCellName.java index 9bd09ca..8d51cbc 100644 --- a/src/main/java/com/poiji/annotation/ExcelCellName.java +++ b/src/main/java/com/poiji/annotation/ExcelCellName.java @@ -16,7 +16,7 @@ /** * Specifies the column name where the corresponding value is mapped from the - * excel data + * Excel data * * @return column name */ @@ -35,4 +35,12 @@ * @return mandatory cell signal. Default is false. */ boolean mandatoryCell() default false; + + /** + * Specifies the column regular expression where the corresponding value is mapped from the + * Excel data + * + * @return column regular expression + */ + String expression() default ""; } diff --git a/src/main/java/com/poiji/annotation/ExcelCellsJoinedByName.java b/src/main/java/com/poiji/annotation/ExcelCellsJoinedByName.java new file mode 100644 index 0000000..7f5fedd --- /dev/null +++ b/src/main/java/com/poiji/annotation/ExcelCellsJoinedByName.java @@ -0,0 +1,20 @@ +package com.poiji.annotation; + +import java.lang.annotation.*; + +/** + * Created by aerfus on 18/02/2024 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Documented +public @interface ExcelCellsJoinedByName { + + /** + * Specifies the column regular expression where the corresponding values are mapped from the + * Excel data + * + * @return column regular expression + */ + String expression(); +} diff --git a/src/main/java/com/poiji/bind/mapping/HSSFUnmarshaller.java b/src/main/java/com/poiji/bind/mapping/HSSFUnmarshaller.java index eeece4d..d48f01e 100644 --- a/src/main/java/com/poiji/bind/mapping/HSSFUnmarshaller.java +++ b/src/main/java/com/poiji/bind/mapping/HSSFUnmarshaller.java @@ -6,6 +6,7 @@ import com.poiji.annotation.ExcelCellRange; import com.poiji.annotation.ExcelRow; import com.poiji.annotation.ExcelUnknownCells; +import com.poiji.annotation.ExcelCellsJoinedByName; import com.poiji.bind.Unmarshaller; import com.poiji.config.Casting; import com.poiji.config.Formatting; @@ -15,6 +16,8 @@ import com.poiji.option.PoijiOptions; import com.poiji.util.AnnotationUtil; import com.poiji.util.ReflectUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MultiValuedMap; import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.formula.BaseFormulaEvaluator; @@ -25,6 +28,7 @@ import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.util.NumberToTextConverter; +import org.apache.poi.util.StringUtil; import java.lang.reflect.Field; import java.util.ArrayList; @@ -35,6 +39,7 @@ import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Consumer; +import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -245,11 +250,18 @@ private Integer tailSetFieldValue(Row currentRow, T instance, Field field) { if (annotationDetail.getColumn() != null) { constructTypeValue(currentRow, instance, field, annotationDetail); } + + if (CollectionUtils.isNotEmpty(annotationDetail.getColumns())) { + for (Integer column : annotationDetail.getColumns()) { + annotationDetail.setColumn(column); + constructTypeValue(currentRow, instance, field, annotationDetail); + } + } + return annotationDetail.getColumn(); } private FieldAnnotationDetail getFieldColumn(final Field field) { - ExcelCell index = field.getAnnotation(ExcelCell.class); DisableCellFormatXLS disableCellFormat = field.getAnnotation(DisableCellFormatXLS.class); final FieldAnnotationDetail annotationDetail = new FieldAnnotationDetail(); @@ -257,22 +269,57 @@ private FieldAnnotationDetail getFieldColumn(final Field field) { annotationDetail.setDisabledCellFormat(disableCellFormat.value()); } + ExcelCell index = field.getAnnotation(ExcelCell.class); if (index != null) { annotationDetail.setColumn(index.value()); annotationDetail.setMandatoryCell(index.mandatoryCell()); - } else { - ExcelCellName excelCellName = field.getAnnotation(ExcelCellName.class); - if (excelCellName != null) { - annotationDetail.setMandatoryCell(excelCellName.mandatoryCell()); - annotationDetail.setColumnName(excelCellName.value()); - final String titleName = formatting.transform(options, excelCellName.value()); - Integer column = titleToIndex.get(titleName); - annotationDetail.setColumn(column); - } } + + ExcelCellName excelCellName = field.getAnnotation(ExcelCellName.class); + if (excelCellName != null) { + annotationDetail.setMandatoryCell(excelCellName.mandatoryCell()); + annotationDetail.setColumnName(excelCellName.value()); + Integer column = findTitleColumn(excelCellName); + annotationDetail.setColumn(column); + } + + ExcelCellsJoinedByName excelCellsJoinedByName = field.getAnnotation(ExcelCellsJoinedByName.class); + if (excelCellsJoinedByName != null) { + String expression = excelCellsJoinedByName.expression(); + Pattern pattern = Pattern.compile(expression); + + List columns = indexToTitle.entrySet().stream() + .filter(entry -> pattern.matcher( + entry.getValue().replaceAll("@[0-9]+", "")) + .matches()) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + + annotationDetail.setColumns(columns); + annotationDetail.setMultiValueMap(CollectionUtils.isNotEmpty(columns)); + } + return annotationDetail; } + public Integer findTitleColumn(ExcelCellName excelCellName) { + if (!StringUtil.isBlank(excelCellName.value())) { + final String titleName = formatting.transform(options, excelCellName.value()); + return titleToIndex.get(titleName); + } + + if (!StringUtil.isBlank(excelCellName.expression())) { + final String titleName = formatting.transform(options, excelCellName.expression()); + Pattern pattern = Pattern.compile(titleName); + return titleToIndex.entrySet().stream() + .filter(entry -> pattern.matcher(entry.getKey()).matches()) + .findFirst() + .map(Map.Entry::getValue) + .orElse(null); + } + return null; + } + private void constructTypeValue(Row currentRow, T instance, Field field, FieldAnnotationDetail annotationDetail) { Cell cell = currentRow.getCell(annotationDetail.getColumn()); @@ -289,7 +336,14 @@ private void constructTypeValue(Row currentRow, T instance, Field field, } Object data = casting.castValue(field, value, currentRow.getRowNum(), annotationDetail.getColumn(), options); - setFieldData(instance, field, data); + + if (!annotationDetail.isMultiValueMap()) { + setFieldData(instance, field, data); + } else { + String titleColumn = indexToTitle.get(annotationDetail.getColumn()); + titleColumn = titleColumn.replaceAll("@[0-9]+", ""); + putFieldMultiValueMapData(instance, field, titleColumn, data); + } } else if (annotationDetail.isMandatoryCell()) { throw new PoijiRowSpecificException(annotationDetail.getColumnName(), field.getName(), currentRow.getRowNum()); @@ -311,6 +365,16 @@ private void setFieldData(T instance, Field field, Object data) { } } + public void putFieldMultiValueMapData(Object instance, Field field, String columnName, Object o) { + try { + field.setAccessible(true); + MultiValuedMap multiValuedMap = (MultiValuedMap) field.get(instance); + multiValuedMap.put(columnName, o); + } catch (ClassCastException | IllegalAccessException e) { + throw new IllegalCastException("Unexpected cast type {" + o + "} of field" + field.getName()); + } + } + private T setFieldValuesFromRowIntoInstance(Row currentRow, Class subclass, T instance) { return subclass == null ? instance @@ -338,6 +402,10 @@ private static class FieldAnnotationDetail { private boolean disabledCellFormat; private boolean mandatoryCell; + private List columns; + + private boolean multiValueMap; + Integer getColumn() { return column; } @@ -370,6 +438,21 @@ public void setMandatoryCell(boolean mandatoryCell) { this.mandatoryCell = mandatoryCell; } + public List getColumns() { + return columns; + } + + public void setColumns(List columns) { + this.columns = columns; + } + + public boolean isMultiValueMap() { + return multiValueMap; + } + + public void setMultiValueMap(boolean multiValueMap) { + this.multiValueMap = multiValueMap; + } } } diff --git a/src/main/java/com/poiji/bind/mapping/PoijiHandler.java b/src/main/java/com/poiji/bind/mapping/PoijiHandler.java index cf8e080..065718f 100644 --- a/src/main/java/com/poiji/bind/mapping/PoijiHandler.java +++ b/src/main/java/com/poiji/bind/mapping/PoijiHandler.java @@ -5,6 +5,7 @@ import com.poiji.annotation.ExcelCellRange; import com.poiji.annotation.ExcelRow; import com.poiji.annotation.ExcelUnknownCells; +import com.poiji.annotation.ExcelCellsJoinedByName; import com.poiji.config.Casting; import com.poiji.config.Formatting; import com.poiji.exception.IllegalCastException; @@ -12,6 +13,7 @@ import com.poiji.util.AnnotationUtil; import com.poiji.util.ReflectUtil; import org.apache.poi.ss.util.CellAddress; +import org.apache.poi.util.StringUtil; import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler; import org.apache.poi.xssf.usermodel.XSSFComment; @@ -21,6 +23,7 @@ import java.util.Map; import java.util.Set; import java.util.function.Consumer; +import java.util.regex.Pattern; import java.util.stream.Stream; import static java.lang.String.valueOf; @@ -167,23 +170,55 @@ private boolean setValue(Field field, int column, String content, Object ins) { ReflectUtil.setFieldData(field, o, ins); return true; } - } else { - ExcelCellName excelCellName = field.getAnnotation(ExcelCellName.class); - if (excelCellName != null) { - excelCellNameAnnotations.add(excelCellName); - final String titleName = formatting.transform(options, excelCellName.value()); - final Integer titleColumn = titleToIndex.get(titleName); - // Fix both columns mapped to name passing this condition below - if (titleColumn != null && titleColumn == column) { - Object o = casting.castValue(field, content, internalRow, column, options); - ReflectUtil.setFieldData(field, o, ins); - return true; - } + } + + ExcelCellName excelCellName = field.getAnnotation(ExcelCellName.class); + if (excelCellName != null) { + excelCellNameAnnotations.add(excelCellName); + final Integer titleColumn = findTitleColumn(excelCellName); + // Fix both columns mapped to name passing this condition below + if (titleColumn != null && titleColumn == column) { + Object o = casting.castValue(field, content, internalRow, column, options); + ReflectUtil.setFieldData(field, o, ins); + return true; } } + + ExcelCellsJoinedByName excelCellsJoinedByName = field.getAnnotation(ExcelCellsJoinedByName.class); + if (excelCellsJoinedByName != null) { + String titleColumn = indexToTitle.get(column).replaceAll("@[0-9]+", ""); + + String expression = excelCellsJoinedByName.expression(); + Pattern pattern = Pattern.compile(expression); + if (pattern.matcher(titleColumn).matches()) { + Object o = casting.castValue(field, content, internalRow, column, options); + ReflectUtil.putFieldMultiValueMapData(field, titleColumn, o, ins); + return true; + } + } + return false; } + public Integer findTitleColumn(ExcelCellName excelCellName) { + if (!StringUtil.isBlank(excelCellName.value())) { + final String titleName = formatting.transform(options, excelCellName.value()); + return titleToIndex.get(titleName); + } + + if (!StringUtil.isBlank(excelCellName.expression())) { + final String titleName = formatting.transform(options, excelCellName.expression()); + Pattern pattern = Pattern.compile(titleName); + return titleToIndex.entrySet().stream() + .filter(entry -> pattern.matcher(entry.getKey()).matches()) + .findFirst() + .map(Map.Entry::getValue) + .orElse(null); + } + + return null; + } + @Override public void startRow(int rowNum) { if (rowNum + 1 > options.skip()) { diff --git a/src/main/java/com/poiji/util/ReflectUtil.java b/src/main/java/com/poiji/util/ReflectUtil.java index 3f95382..278c3d0 100644 --- a/src/main/java/com/poiji/util/ReflectUtil.java +++ b/src/main/java/com/poiji/util/ReflectUtil.java @@ -3,6 +3,7 @@ import com.poiji.annotation.ExcelCellRange; import com.poiji.exception.IllegalCastException; import com.poiji.exception.PoijiInstantiationException; +import org.apache.commons.collections4.MultiValuedMap; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; @@ -64,4 +65,15 @@ public static void setFieldData(Field field, Object o, Object instance) { throw new IllegalCastException("Unexpected cast type {" + o + "} of field" + field.getName()); } } + + @SuppressWarnings("unchecked") + public static void putFieldMultiValueMapData(Field field, String columnName, Object o, Object instance) { + try { + field.setAccessible(true); + MultiValuedMap multiValuedMap = (MultiValuedMap) field.get(instance); + multiValuedMap.put(columnName, o); + } catch (IllegalAccessException | IllegalAccessError e) { + throw new IllegalCastException("Unexpected cast type {" + o + "} of field" + field.getName()); + } + } } diff --git a/src/test/java/com/poiji/bind/mapping/HSSFUnmarshallerTest.java b/src/test/java/com/poiji/bind/mapping/HSSFUnmarshallerTest.java new file mode 100644 index 0000000..7f39071 --- /dev/null +++ b/src/test/java/com/poiji/bind/mapping/HSSFUnmarshallerTest.java @@ -0,0 +1,47 @@ +package com.poiji.bind.mapping; + +import com.poiji.annotation.ExcelCellName; +import com.poiji.deserialize.model.InventoryData; +import com.poiji.option.PoijiOptions; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.lang.reflect.Field; +import java.util.List; + +import static org.junit.Assert.assertNull; + +@RunWith(Parameterized.class) +public class HSSFUnmarshallerTest { + + private final ExcelCellName annotation; + + public HSSFUnmarshallerTest(String fieldName) throws NoSuchFieldException { + Field author = InventoryData.class.getDeclaredField(fieldName); + annotation = author.getAnnotation(ExcelCellName.class); + } + + @Parameterized.Parameters(name = "{index}: ({0})={1}") + public static Iterable queries() { + return List.of(new Object[][] { + { + "id" + }, + { + "author" + }, + { "empty" } + }); + } + + @Test + public void shouldFindTitleColumn() { + HSSFUnmarshallerFile hssfUnmarshallerFile = new HSSFUnmarshallerFile(null, + PoijiOptions.PoijiOptionsBuilder.settings().build()); + + Integer titleColumn = hssfUnmarshallerFile.findTitleColumn(annotation); + + assertNull(titleColumn); + } +} \ No newline at end of file diff --git a/src/test/java/com/poiji/bind/mapping/PoijiHandlerTest.java b/src/test/java/com/poiji/bind/mapping/PoijiHandlerTest.java new file mode 100644 index 0000000..e6756b0 --- /dev/null +++ b/src/test/java/com/poiji/bind/mapping/PoijiHandlerTest.java @@ -0,0 +1,48 @@ +package com.poiji.bind.mapping; + +import com.poiji.annotation.ExcelCellName; +import com.poiji.deserialize.model.InventoryData; +import com.poiji.option.PoijiOptions; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.lang.reflect.Field; +import java.util.List; + +import static org.junit.Assert.*; + +@RunWith(Parameterized.class) +public class PoijiHandlerTest { + + private final ExcelCellName annotation; + + public PoijiHandlerTest(String fieldName) throws NoSuchFieldException { + Field author = InventoryData.class.getDeclaredField(fieldName); + annotation = author.getAnnotation(ExcelCellName.class); + } + + @Parameterized.Parameters(name = "{index}: ({0})={1}") + public static Iterable queries() { + return List.of(new Object[][] { + { + "id" + }, + { + "author" + }, + { "empty" } + }); + } + + @Test + public void shouldFindTitleColumn() { + PoijiHandler poijiHandler = new PoijiHandler<>(InventoryData.class, + PoijiOptions.PoijiOptionsBuilder.settings().build(), o -> { + }); + + Integer titleColumn = poijiHandler.findTitleColumn(annotation); + + assertNull(titleColumn); + } +} \ No newline at end of file diff --git a/src/test/java/com/poiji/deserialize/ReadExcelWithRegexAndJoinValuesTest.java b/src/test/java/com/poiji/deserialize/ReadExcelWithRegexAndJoinValuesTest.java new file mode 100644 index 0000000..8e6fc8c --- /dev/null +++ b/src/test/java/com/poiji/deserialize/ReadExcelWithRegexAndJoinValuesTest.java @@ -0,0 +1,55 @@ +package com.poiji.deserialize; + +import com.poiji.bind.Poiji; +import com.poiji.deserialize.model.Album; +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.List; + +import static com.poiji.option.PoijiOptions.PoijiOptionsBuilder.settings; +import static com.poiji.util.Data.unmarshallingAlbums; +import static org.junit.Assert.assertEquals; + +/** + * Test for Reading Excel columns with Regular expression (Regex) + */ +@RunWith(Parameterized.class) +public class ReadExcelWithRegexAndJoinValuesTest { + private final String path; + private final List expectedData; + private final PoijiOptions options; + + public ReadExcelWithRegexAndJoinValuesTest(String path, List expectedData, PoijiOptions options) { + this.path = path; + this.expectedData = expectedData; + this.options = options; + } + + @Parameterized.Parameters(name = "{index}: ({0})={1}") + public static Iterable queries() { + return List.of(new Object[][]{ + { + "src/test/resources/regex/album.xlsx", + unmarshallingAlbums(), + settings().sheetName("Sheet 1").build() + }, + { + "src/test/resources/regex/album.xls", + unmarshallingAlbums(), + settings().sheetName("Sheet 1").build() + }, + }); + } + + @Test + public void shouldReadAlbumData() { + List actualData = Poiji.fromExcel(new File(path), Album.class, options); + + assertEquals(expectedData, actualData); + } + +} diff --git a/src/test/java/com/poiji/deserialize/ReadExcelWithRegexInColumnNameTest.java b/src/test/java/com/poiji/deserialize/ReadExcelWithRegexInColumnNameTest.java new file mode 100644 index 0000000..6ab16aa --- /dev/null +++ b/src/test/java/com/poiji/deserialize/ReadExcelWithRegexInColumnNameTest.java @@ -0,0 +1,65 @@ +package com.poiji.deserialize; + +import com.poiji.bind.Poiji; +import com.poiji.deserialize.model.InventoryData; +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.List; + +import static com.poiji.option.PoijiOptions.PoijiOptionsBuilder.settings; +import static com.poiji.util.Data.unmarshallingInventoryData; +import static org.junit.Assert.assertEquals; + +/** + * Test for Reading Excel columns with Regular expression (Regex) + */ +@RunWith(Parameterized.class) +public class ReadExcelWithRegexInColumnNameTest { + private final String path; + private final List expectedData; + private final PoijiOptions options; + + public ReadExcelWithRegexInColumnNameTest(String path, List expectedData, PoijiOptions options) { + this.path = path; + this.expectedData = expectedData; + this.options = options; + } + + @Parameterized.Parameters(name = "{index}: ({0})={1}") + public static Iterable queries() { + return List.of(new Object[][]{ + { + "src/test/resources/regex/inventory.xlsx", + unmarshallingInventoryData(), + settings().sheetName("Books").build() + }, + { + "src/test/resources/regex/inventory.xlsx", + unmarshallingInventoryData(), + settings().sheetName("Songs").build() + }, + { + "src/test/resources/regex/inventory.xls", + unmarshallingInventoryData(), + settings().sheetName("Books").build() + }, + { + "src/test/resources/regex/inventory.xls", + unmarshallingInventoryData(), + settings().sheetName("Songs").build() + }, + }); + } + + @Test + public void shouldReadInventoryData() { + List actualData = Poiji.fromExcel(new File(path), InventoryData.class, options); + + assertEquals(expectedData, actualData); + } + +} diff --git a/src/test/java/com/poiji/deserialize/model/Album.java b/src/test/java/com/poiji/deserialize/model/Album.java new file mode 100644 index 0000000..0b8632c --- /dev/null +++ b/src/test/java/com/poiji/deserialize/model/Album.java @@ -0,0 +1,47 @@ +package com.poiji.deserialize.model; + +import com.poiji.annotation.ExcelCellsJoinedByName; +import org.apache.commons.collections4.MultiValuedMap; +import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; + +import java.util.Objects; + +/** + * An Album POJO. + */ +public class Album { + @ExcelCellsJoinedByName(expression = "Artist") + private MultiValuedMap artists = new ArrayListValuedHashMap<>(); + + @ExcelCellsJoinedByName(expression = "Track[0-9]+") + private MultiValuedMap tracks = new ArrayListValuedHashMap<>(); + + public void setArtists(MultiValuedMap artists) { + this.artists = artists; + } + + public void setTracks(MultiValuedMap tracks) { + this.tracks = tracks; + } + + @Override + public String toString() { + return "Album{" + + "artists=" + artists + + ", tracks=" + tracks + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Album album = (Album) o; + return Objects.equals(artists, album.artists) && Objects.equals(tracks, album.tracks); + } + + @Override + public int hashCode() { + return Objects.hash(artists, tracks); + } +} diff --git a/src/test/java/com/poiji/deserialize/model/InventoryData.java b/src/test/java/com/poiji/deserialize/model/InventoryData.java new file mode 100644 index 0000000..fc7f26a --- /dev/null +++ b/src/test/java/com/poiji/deserialize/model/InventoryData.java @@ -0,0 +1,50 @@ +package com.poiji.deserialize.model; + +import com.poiji.annotation.ExcelCellName; + +import java.util.Objects; + +/** + * An InventoryData POJO. + */ +public class InventoryData { + @ExcelCellName(value = "Id") + private Integer id; + + @ExcelCellName(value = "", expression = "Author|Composer") + private String author; + + @ExcelCellName(value = "") + private String empty; + + public void setId(Integer id) { + this.id = id; + } + + public void setAuthor(String author) { + this.author = author; + } + + @Override + public String toString() { + return "InventoryData{" + + "id='" + id + '\'' + + ", author='" + author + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + InventoryData that = (InventoryData) o; + return Objects.equals(id, that.id) && Objects.equals(author, that.author); + } + + @Override + public int hashCode() { + return Objects.hash(id, author); + } +} diff --git a/src/test/java/com/poiji/util/Data.java b/src/test/java/com/poiji/util/Data.java index fc09097..87b88fe 100644 --- a/src/test/java/com/poiji/util/Data.java +++ b/src/test/java/com/poiji/util/Data.java @@ -1,9 +1,12 @@ package com.poiji.util; +import com.poiji.deserialize.model.Album; +import com.poiji.deserialize.model.InventoryData; import com.poiji.deserialize.model.Student; import com.poiji.deserialize.model.byid.Employee; import com.poiji.deserialize.model.byid.Person; import com.poiji.deserialize.model.byid.Sample; +import org.apache.commons.collections4.multimap.ArrayListValuedHashMap; import java.util.ArrayList; import java.util.List; @@ -126,4 +129,36 @@ public static List unmarshallingStudents() { students.add(student); return students; } + + + public static List unmarshallingInventoryData() { + InventoryData record1 = new InventoryData(); + record1.setId(1); + record1.setAuthor("Peter"); + + InventoryData record2 = new InventoryData(); + record2.setId(2); + record2.setAuthor("Maria"); + + return List.of(record1, record2); + } + + + public static List unmarshallingAlbums() { + ArrayListValuedHashMap artists = new ArrayListValuedHashMap<>(); + + artists.put("Artist", "Michael Jackson"); + artists.put("Artist", "Lionel Richie"); + artists.put("Artist", "Stevie Wonder"); + + ArrayListValuedHashMap tracks = new ArrayListValuedHashMap<>(); + tracks.put("Track1", "We are the World"); + tracks.put("Track2", "We are the World (instrumental)"); + + Album album = new Album(); + album.setArtists(artists); + album.setTracks(tracks); + + return List.of(album); + } } diff --git a/src/test/java/com/poiji/util/ReflectUtilTest.java b/src/test/java/com/poiji/util/ReflectUtilTest.java index c0e6014..a4086d7 100644 --- a/src/test/java/com/poiji/util/ReflectUtilTest.java +++ b/src/test/java/com/poiji/util/ReflectUtilTest.java @@ -1,10 +1,13 @@ package com.poiji.util; +import com.poiji.annotation.ExcelCellsJoinedByName; import com.poiji.exception.PoijiExcelType; import com.poiji.exception.PoijiInstantiationException; + import org.junit.BeforeClass; import org.junit.Test; +import java.lang.reflect.Field; import java.lang.reflect.ReflectPermission; import static org.junit.Assert.assertNotNull; @@ -49,7 +52,18 @@ public void newInstanceOfEnum() { ReflectUtil.newInstanceOf(PoijiExcelType.class); } + @Test(expected = ClassCastException.class) + public void illegalCast() throws NoSuchFieldException, SecurityException { + PackageModel pm = new PackageModel(); + Object o = "new_value"; + Field field = PackageModel.class.getDeclaredField("field"); + + ReflectUtil.putFieldMultiValueMapData(field, "Artist", o, pm); + } + static class PackageModel { + @ExcelCellsJoinedByName(expression = "Artist") + private String field = ""; } static class PackageModelWithPrivateConstructor { diff --git a/src/test/resources/regex/album.xls b/src/test/resources/regex/album.xls new file mode 100644 index 0000000..1df8c76 Binary files /dev/null and b/src/test/resources/regex/album.xls differ diff --git a/src/test/resources/regex/album.xlsx b/src/test/resources/regex/album.xlsx new file mode 100644 index 0000000..d952d47 Binary files /dev/null and b/src/test/resources/regex/album.xlsx differ diff --git a/src/test/resources/regex/inventory.xls b/src/test/resources/regex/inventory.xls new file mode 100644 index 0000000..8db604c Binary files /dev/null and b/src/test/resources/regex/inventory.xls differ diff --git a/src/test/resources/regex/inventory.xlsx b/src/test/resources/regex/inventory.xlsx new file mode 100644 index 0000000..4f02ae8 Binary files /dev/null and b/src/test/resources/regex/inventory.xlsx differ