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,30 @@ 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 )) {
133
+ throw new IllegalArgumentException ("Unsupported type " + type );
134
+ }
135
+ ParameterizedType parameterizedType = (ParameterizedType ) type ;
136
+ if (!NumberedObject .class .equals (parameterizedType .getRawType ())) {
137
+ throw new IllegalArgumentException ("Unsupported type " + parameterizedType );
138
+ }
139
+ return convertToNumberedObject (entry , parameterizedType .getActualTypeArguments ()[0 ]);
140
+ };
123
141
private static final TableCellByTypeTransformer JACKSON_TABLE_CELL_BY_TYPE_CONVERTER = (value ,
124
142
cellType ) -> objectMapper .convertValue (value , objectMapper .constructType (cellType ));
125
143
private static final DataTableType DATE_TABLE_CELL_TRANSFORMER = new DataTableType (Date .class ,
126
144
(TableCellTransformer <Date >) SIMPLE_DATE_FORMAT ::parse );
127
145
146
+ private static Object convertToNumberedObject (Map <String , String > numberedEntry , Type type ) {
147
+ int number = Integer .parseInt (numberedEntry .get ("#" ));
148
+ Map <String , String > entry = numberedEntry .entrySet ().stream ()
149
+ .filter (e -> !"#" .equals (e .getKey ()))
150
+ .collect (toMap (Map .Entry ::getKey , Map .Entry ::getValue ));
151
+ return new NumberedObject <>(number , objectMapper .convertValue (entry , objectMapper .constructType (type )));
152
+ }
153
+
128
154
static {
129
155
SIMPLE_DATE_FORMAT .setTimeZone (TimeZone .getTimeZone ("UTC" ));
130
156
}
@@ -427,6 +453,26 @@ void convert_to_empty_list_of_object__using_default_converter__throws_exception(
427
453
"Note: Usually solving one is enough" ));
428
454
}
429
455
456
+ @ Test
457
+ void convert_to_list_of_parameterized_object__using_default_converter () {
458
+ DataTable table = parse ("" ,
459
+ "| # | firstName | lastName | birthDate |" ,
460
+ "| 1 | Annie M. G. | Schmidt | 1911-03-20 |" ,
461
+ "| 2 | Roald | Dahl | 1916-09-13 |" ,
462
+ "| 3 | Astrid | Lindgren | 1907-11-14 |" );
463
+
464
+ registry .setDefaultDataTableEntryTransformer (JACKSON_NUMBERED_OBJECT_TABLE_ENTRY_CONVERTER );
465
+ registry .setDefaultDataTableCellTransformer (TABLE_CELL_BY_TYPE_CONVERTER_SHOULD_NOT_BE_USED );
466
+
467
+ List <NumberedObject <Author >> expected = asList (
468
+ new NumberedObject <>(1 , new Author ("Annie M. G." , "Schmidt" , "1911-03-20" )),
469
+ new NumberedObject <>(2 , new Author ("Roald" , "Dahl" , "1916-09-13" )),
470
+ new NumberedObject <>(3 , new Author ("Astrid" , "Lindgren" , "1907-11-14" )));
471
+
472
+ assertEquals (expected , converter .toList (table , NUMBERED_AUTHOR ));
473
+ assertEquals (expected , converter .convert (table , LIST_OF_NUMBERED_AUTHOR ));
474
+ }
475
+
430
476
@ Test
431
477
void convert_to_list_of_primitive () {
432
478
DataTable table = parse ("" ,
@@ -1222,6 +1268,20 @@ void convert_to_single_object__single_cell__using_default_transformer() {
1222
1268
assertEquals (Piece .BLACK_BISHOP , converter .convert (table , Piece .class ));
1223
1269
}
1224
1270
1271
+ @ Test
1272
+ void convert_to_parameterized_object__using_default_converter () {
1273
+ DataTable table = parse ("" ,
1274
+ "| # | firstName | lastName | birthDate |" ,
1275
+ "| 1 | Annie M. G. | Schmidt | 1911-03-20 |" );
1276
+
1277
+ registry .setDefaultDataTableEntryTransformer (JACKSON_NUMBERED_OBJECT_TABLE_ENTRY_CONVERTER );
1278
+ registry .setDefaultDataTableCellTransformer (TABLE_CELL_BY_TYPE_CONVERTER_SHOULD_NOT_BE_USED );
1279
+
1280
+ NumberedObject <Author > expected = new NumberedObject <>(1 , new Author ("Annie M. G." , "Schmidt" , "1911-03-20" ));
1281
+
1282
+ assertEquals (expected , converter .convert (table , NUMBERED_AUTHOR ));
1283
+ }
1284
+
1225
1285
@ Test
1226
1286
void convert_to_table__table_transformer_takes_precedence_over_identity_transform () {
1227
1287
DataTable table = parse ("" ,
@@ -1713,6 +1773,28 @@ void to_maps_of_unknown_value_type__throws_exception__register_table_cell_transf
1713
1773
"Note: Usually solving one is enough" ));
1714
1774
}
1715
1775
1776
+ private static class NumberedObject <T > {
1777
+ private final int number ;
1778
+ private final T value ;
1779
+
1780
+ private NumberedObject (int number , T value ) {
1781
+ this .number = number ;
1782
+ this .value = value ;
1783
+ }
1784
+
1785
+ @ Override
1786
+ public boolean equals (Object obj ) {
1787
+ return obj instanceof NumberedObject
1788
+ && ((NumberedObject <?>) obj ).number == number
1789
+ && Objects .equals (((NumberedObject <?>) obj ).value , value );
1790
+ }
1791
+
1792
+ @ Override
1793
+ public String toString () {
1794
+ return String .format ("%d: %s" , number , value );
1795
+ }
1796
+ }
1797
+
1716
1798
private enum Piece {
1717
1799
BLACK_PAWN ("♟" ),
1718
1800
BLACK_BISHOP ("♝" ),
0 commit comments