8
8
import org .junit .jupiter .api .Test ;
9
9
10
10
import java .beans .ConstructorProperties ;
11
+ import java .lang .reflect .ParameterizedType ;
11
12
import java .lang .reflect .Type ;
12
13
import java .math .BigDecimal ;
13
14
import java .math .BigInteger ;
17
18
import java .util .HashMap ;
18
19
import java .util .List ;
19
20
import java .util .Map ;
21
+ import java .util .Objects ;
20
22
import java .util .Optional ;
21
23
import java .util .TimeZone ;
22
24
30
32
import static java .util .Collections .emptyMap ;
31
33
import static java .util .Collections .singletonList ;
32
34
import static java .util .Locale .ENGLISH ;
35
+ import static java .util .stream .Collectors .toMap ;
33
36
import static org .hamcrest .CoreMatchers .is ;
34
37
import static org .hamcrest .CoreMatchers .startsWith ;
35
38
import static org .hamcrest .MatcherAssert .assertThat ;
@@ -93,7 +96,11 @@ class DataTableTypeRegistryTableConverterTest {
93
96
}.getType ();
94
97
private static final Type MAP_OF_STRING_TO_MAP_OF_INTEGER_TO_PIECE = new TypeReference <Map <String , Map <Integer , Piece >>>() {
95
98
}.getType ();
96
- public static final Type OPTIONAL_CHESS_BOARD_TYPE = new TypeReference <Optional <ChessBoard >>() {
99
+ private static final Type OPTIONAL_CHESS_BOARD_TYPE = new TypeReference <Optional <ChessBoard >>() {
100
+ }.getType ();
101
+ private static final Type NUMBERED_AUTHOR = new TypeReference <NumberedObject <Author >>() {
102
+ }.getType ();
103
+ private static final Type LIST_OF_NUMBERED_AUTHOR = new TypeReference <List <NumberedObject <Author >>>() {
97
104
}.getType ();
98
105
private static final TableTransformer <ChessBoard > CHESS_BOARD_TABLE_TRANSFORMER = table -> new ChessBoard (
99
106
table .subTable (1 , 1 ).values ());
@@ -120,11 +127,26 @@ class DataTableTypeRegistryTableConverterTest {
120
127
};
121
128
private static final TableEntryByTypeTransformer JACKSON_TABLE_ENTRY_BY_TYPE_CONVERTER = (entry , type ,
122
129
cellTransformer ) -> objectMapper .convertValue (entry , objectMapper .constructType (type ));
130
+ private static final TableEntryByTypeTransformer JACKSON_NUMBERED_OBJECT_TABLE_ENTRY_CONVERTER = (entry , type ,
131
+ cellTransformer ) -> {
132
+ if (type instanceof ParameterizedType && NumberedObject .class .equals (((ParameterizedType ) type ).getRawType ())) {
133
+ return convertToNumberedObject (entry , ((ParameterizedType ) type ).getActualTypeArguments ()[0 ]);
134
+ }
135
+ return objectMapper .convertValue (entry , objectMapper .constructType (type ));
136
+ };
123
137
private static final TableCellByTypeTransformer JACKSON_TABLE_CELL_BY_TYPE_CONVERTER = (value ,
124
138
cellType ) -> objectMapper .convertValue (value , objectMapper .constructType (cellType ));
125
139
private static final DataTableType DATE_TABLE_CELL_TRANSFORMER = new DataTableType (Date .class ,
126
140
(TableCellTransformer <Date >) SIMPLE_DATE_FORMAT ::parse );
127
141
142
+ private static Object convertToNumberedObject (Map <String , String > numberedEntry , Type type ) {
143
+ int number = Integer .parseInt (numberedEntry .get ("#" ));
144
+ Map <String , String > entry = numberedEntry .entrySet ().stream ()
145
+ .filter (e -> !"#" .equals (e .getKey ()))
146
+ .collect (toMap (Map .Entry ::getKey , Map .Entry ::getValue ));
147
+ return new NumberedObject <>(number , objectMapper .convertValue (entry , objectMapper .constructType (type )));
148
+ }
149
+
128
150
static {
129
151
SIMPLE_DATE_FORMAT .setTimeZone (TimeZone .getTimeZone ("UTC" ));
130
152
}
@@ -427,6 +449,26 @@ void convert_to_empty_list_of_object__using_default_converter__throws_exception(
427
449
"Note: Usually solving one is enough" ));
428
450
}
429
451
452
+ @ Test
453
+ void convert_to_list_of_parameterized_object__using_default_converter () {
454
+ DataTable table = parse ("" ,
455
+ "| # | firstName | lastName | birthDate |" ,
456
+ "| 1 | Annie M. G. | Schmidt | 1911-03-20 |" ,
457
+ "| 2 | Roald | Dahl | 1916-09-13 |" ,
458
+ "| 3 | Astrid | Lindgren | 1907-11-14 |" );
459
+
460
+ registry .setDefaultDataTableEntryTransformer (JACKSON_NUMBERED_OBJECT_TABLE_ENTRY_CONVERTER );
461
+ registry .setDefaultDataTableCellTransformer (TABLE_CELL_BY_TYPE_CONVERTER_SHOULD_NOT_BE_USED );
462
+
463
+ List <NumberedObject <Author >> expected = asList (
464
+ new NumberedObject <>(1 , new Author ("Annie M. G." , "Schmidt" , "1911-03-20" )),
465
+ new NumberedObject <>(2 , new Author ("Roald" , "Dahl" , "1916-09-13" )),
466
+ new NumberedObject <>(3 , new Author ("Astrid" , "Lindgren" , "1907-11-14" )));
467
+
468
+ assertEquals (expected , converter .toList (table , NUMBERED_AUTHOR ));
469
+ assertEquals (expected , converter .convert (table , LIST_OF_NUMBERED_AUTHOR ));
470
+ }
471
+
430
472
@ Test
431
473
void convert_to_list_of_primitive () {
432
474
DataTable table = parse ("" ,
@@ -1222,6 +1264,20 @@ void convert_to_single_object__single_cell__using_default_transformer() {
1222
1264
assertEquals (Piece .BLACK_BISHOP , converter .convert (table , Piece .class ));
1223
1265
}
1224
1266
1267
+ @ Test
1268
+ void convert_to_parameterized_object__using_default_converter () {
1269
+ DataTable table = parse ("" ,
1270
+ "| # | firstName | lastName | birthDate |" ,
1271
+ "| 1 | Annie M. G. | Schmidt | 1911-03-20 |" );
1272
+
1273
+ registry .setDefaultDataTableEntryTransformer (JACKSON_NUMBERED_OBJECT_TABLE_ENTRY_CONVERTER );
1274
+ registry .setDefaultDataTableCellTransformer (TABLE_CELL_BY_TYPE_CONVERTER_SHOULD_NOT_BE_USED );
1275
+
1276
+ NumberedObject <Author > expected = new NumberedObject <>(1 , new Author ("Annie M. G." , "Schmidt" , "1911-03-20" ));
1277
+
1278
+ assertEquals (expected , converter .convert (table , NUMBERED_AUTHOR ));
1279
+ }
1280
+
1225
1281
@ Test
1226
1282
void convert_to_table__table_transformer_takes_precedence_over_identity_transform () {
1227
1283
DataTable table = parse ("" ,
@@ -1713,6 +1769,28 @@ void to_maps_of_unknown_value_type__throws_exception__register_table_cell_transf
1713
1769
"Note: Usually solving one is enough" ));
1714
1770
}
1715
1771
1772
+ private static class NumberedObject <T > {
1773
+ private final int number ;
1774
+ private final T value ;
1775
+
1776
+ private NumberedObject (int number , T value ) {
1777
+ this .number = number ;
1778
+ this .value = value ;
1779
+ }
1780
+
1781
+ @ Override
1782
+ public boolean equals (Object obj ) {
1783
+ return obj instanceof NumberedObject
1784
+ && ((NumberedObject <?>) obj ).number == number
1785
+ && Objects .equals (((NumberedObject <?>) obj ).value , value );
1786
+ }
1787
+
1788
+ @ Override
1789
+ public String toString () {
1790
+ return String .format ("%d: %s" , number , value );
1791
+ }
1792
+ }
1793
+
1716
1794
private enum Piece {
1717
1795
BLACK_PAWN ("♟" ),
1718
1796
BLACK_BISHOP ("♝" ),
0 commit comments