Skip to content

Commit d3632a3

Browse files
Copilotozlerhakan
andcommitted
Add tests for @ExcelCellsJoinedByName with records
Co-authored-by: ozlerhakan <[email protected]>
1 parent 5c264ab commit d3632a3

File tree

8 files changed

+101
-8
lines changed

8 files changed

+101
-8
lines changed

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@
236236
<exclude>**/model/byname/EmployeeRecord.java</exclude>
237237
<exclude>**/model/byname/PersonRecord.java</exclude>
238238
<exclude>**/model/byname/OrgWithUnknownCellsRecord.java</exclude>
239+
<exclude>**/model/AlbumRecord.java</exclude>
239240
<exclude>**/RecordDeserializationTest.java</exclude>
240241
</testExcludes>
241242
</configuration>

src/main/java/com/poiji/bind/mapping/HSSFUnmarshaller.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,13 @@ private <T> void constructTypeValueForRecord(Row currentRow, Map<String, Object>
297297
} else {
298298
String titleColumn = indexToTitle.get(annotationDetail.getColumn());
299299
titleColumn = titleColumn.replaceAll("@[0-9]+", "");
300-
// For records with MultiValuedMap, we can't use the same approach
301-
// Store it as a simple value for now
302-
recordValues.put(field.getName(), data);
300+
// For records with MultiValuedMap, we need to collect values into the map
301+
MultiValuedMap<String, Object> fieldMap = (MultiValuedMap<String, Object>) recordValues.get(field.getName());
302+
if (fieldMap == null) {
303+
fieldMap = new org.apache.commons.collections4.multimap.ArrayListValuedHashMap<>();
304+
recordValues.put(field.getName(), fieldMap);
305+
}
306+
fieldMap.put(titleColumn, data);
303307
}
304308
} else if (annotationDetail.isMandatoryCell()) {
305309
throw new PoijiRowSpecificException(annotationDetail.getColumnName(), field.getName(),

src/main/java/com/poiji/bind/mapping/PoijiHandler.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.poiji.option.PoijiOptions;
1313
import com.poiji.util.AnnotationUtil;
1414
import com.poiji.util.ReflectUtil;
15+
import org.apache.commons.collections4.MultiValuedMap;
1516
import org.apache.poi.ss.util.CellAddress;
1617
import org.apache.poi.util.StringUtil;
1718
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
@@ -233,8 +234,13 @@ private boolean setValue(Field field, int column, String content, Object ins) {
233234
if (pattern.matcher(titleColumn).matches()) {
234235
Object o = casting.castValue(field, content, internalRow, column, options);
235236
if (isRecord && ins == null) {
236-
// For records, MultiValuedMap is not supported in the same way
237-
recordValues.put(field.getName(), o);
237+
// For records, we need to collect values into a MultiValuedMap
238+
MultiValuedMap<String, Object> fieldMap = (MultiValuedMap<String, Object>) recordValues.get(field.getName());
239+
if (fieldMap == null) {
240+
fieldMap = new org.apache.commons.collections4.multimap.ArrayListValuedHashMap<>();
241+
recordValues.put(field.getName(), fieldMap);
242+
}
243+
fieldMap.put(titleColumn, o);
238244
} else {
239245
ReflectUtil.putFieldMultiValueMapData(field, titleColumn, o, ins);
240246
}

src/main/java/com/poiji/util/ReflectUtil.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,20 @@ public static <T> T newRecordInstance(Class<T> type, Map<String, Object> recordV
7070
parameterTypes[i] = componentType;
7171
Object value = recordValues.get(componentName);
7272

73-
// If value is null, use default values for primitives
74-
if (value == null && componentType.isPrimitive()) {
75-
value = getDefaultValue(componentType);
73+
// If value is null, use default values for primitives or create empty MultiValuedMap
74+
if (value == null) {
75+
if (componentType.isPrimitive()) {
76+
value = getDefaultValue(componentType);
77+
} else if (componentType.getName().contains("MultiValuedMap")) {
78+
// Create empty MultiValuedMap for null values
79+
try {
80+
value = Class.forName("org.apache.commons.collections4.multimap.ArrayListValuedHashMap")
81+
.getDeclaredConstructor()
82+
.newInstance();
83+
} catch (Exception e) {
84+
// If we can't create ArrayListValuedHashMap, leave as null
85+
}
86+
}
7687
}
7788

7889
args[i] = value;

src/test/java/com/poiji/deserialize/RecordDeserializationTest.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.poiji.deserialize;
22

33
import com.poiji.bind.Poiji;
4+
import com.poiji.deserialize.model.AlbumRecord;
45
import com.poiji.deserialize.model.byid.CalculationRecord;
56
import com.poiji.deserialize.model.byname.EmployeeRecord;
67
import com.poiji.deserialize.model.byname.OrgWithUnknownCellsRecord;
@@ -345,4 +346,58 @@ public void shouldMapXLSToRecordWithUnknownCells() {
345346
assertThat(firstRow.unknownCells(), notNullValue());
346347
assertThat(firstRow.unknownCells().containsKey("Region"), is(true));
347348
}
349+
350+
@Test
351+
public void shouldMapExcelToRecordWithExcelCellsJoinedByName() {
352+
// Test with @ExcelCellsJoinedByName annotation
353+
List<AlbumRecord> albums = Poiji.fromExcel(
354+
new File("src/test/resources/regex/album.xlsx"),
355+
AlbumRecord.class,
356+
PoijiOptions.PoijiOptionsBuilder.settings()
357+
.sheetName("Sheet 1")
358+
.build()
359+
);
360+
361+
assertThat(albums, notNullValue());
362+
assertThat(albums.size(), is(1));
363+
364+
AlbumRecord album = albums.get(0);
365+
366+
// Verify artists are collected correctly
367+
assertThat(album.artists(), notNullValue());
368+
assertThat(album.artists().get("Artist").size(), is(3));
369+
assertThat(album.artists().get("Artist").contains("Michael Jackson"), is(true));
370+
assertThat(album.artists().get("Artist").contains("Lionel Richie"), is(true));
371+
assertThat(album.artists().get("Artist").contains("Stevie Wonder"), is(true));
372+
373+
// Verify tracks are collected correctly with regex pattern
374+
assertThat(album.tracks(), notNullValue());
375+
assertThat(album.tracks().get("Track1").size(), is(1));
376+
assertThat(album.tracks().get("Track1").contains("We are the World"), is(true));
377+
assertThat(album.tracks().get("Track2").size(), is(1));
378+
assertThat(album.tracks().get("Track2").contains("We are the World (instrumental)"), is(true));
379+
}
380+
381+
@Test
382+
public void shouldMapXLSToRecordWithExcelCellsJoinedByName() {
383+
// Test XLS format with @ExcelCellsJoinedByName annotation
384+
List<AlbumRecord> albums = Poiji.fromExcel(
385+
new File("src/test/resources/regex/album.xls"),
386+
AlbumRecord.class,
387+
PoijiOptions.PoijiOptionsBuilder.settings()
388+
.sheetName("Sheet 1")
389+
.build()
390+
);
391+
392+
assertThat(albums, notNullValue());
393+
assertThat(albums.size(), is(1));
394+
395+
AlbumRecord album = albums.get(0);
396+
397+
// Verify collected values work correctly in XLS format
398+
assertThat(album.artists(), notNullValue());
399+
assertThat(album.artists().get("Artist").size(), is(3));
400+
assertThat(album.tracks(), notNullValue());
401+
assertThat(album.tracks().size(), is(2)); // Track1 and Track2
402+
}
348403
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.poiji.deserialize.model;
2+
3+
import com.poiji.annotation.ExcelCellsJoinedByName;
4+
import org.apache.commons.collections4.MultiValuedMap;
5+
6+
/**
7+
* A record class to test @ExcelCellsJoinedByName support
8+
*/
9+
public record AlbumRecord(
10+
@ExcelCellsJoinedByName(expression = "Artist")
11+
MultiValuedMap<String, String> artists,
12+
13+
@ExcelCellsJoinedByName(expression = "Track[0-9]+")
14+
MultiValuedMap<String, String> tracks
15+
) {
16+
}

src/test/resources/employees.xlsx

0 Bytes
Binary file not shown.

src/test/resources/person.xlsx

0 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)