2
2
package com .fasterxml .jackson .dataformat .csv ;
3
3
4
4
import java .util .*;
5
+ import java .util .function .UnaryOperator ;
5
6
6
7
import com .fasterxml .jackson .core .FormatSchema ;
7
8
@@ -263,6 +264,15 @@ public static class Column implements java.io.Serializable // since 2.4.3
263
264
*/
264
265
private final String _arrayElementSeparator ;
265
266
267
+ /**
268
+ * Value decorator used for this column, if any; {@code null} if none.
269
+ * Used to add decoration on serialization (writing) and remove decoration
270
+ * on deserialization (reading).
271
+ *
272
+ * @since 2.18
273
+ */
274
+ private final CsvValueDecorator _valueDecorator ;
275
+
266
276
/**
267
277
* Link to the next column within schema, if one exists;
268
278
* null for the last column.
@@ -285,22 +295,39 @@ public Column(int index, String name, ColumnType type, String arrayElementSep)
285
295
_name = name ;
286
296
_type = type ;
287
297
_arrayElementSeparator = _validArrayElementSeparator (arrayElementSep );
298
+ _valueDecorator = null ;
288
299
_next = null ;
289
300
}
290
301
291
302
public Column (Column src , Column next ) {
292
- this (src , src ._index , next );
303
+ this (src , src ._index , src ._valueDecorator , next );
304
+ }
305
+
306
+ protected Column (Column src , int index , Column next ) {
307
+ this (src , index , src ._valueDecorator , next );
308
+ }
309
+
310
+ /**
311
+ * @since 2.18
312
+ */
313
+ protected Column (Column src , CsvValueDecorator valueDecorator ) {
314
+ this (src , src ._index , valueDecorator , src ._next );
293
315
}
294
316
295
- protected Column (Column src , int index , Column next )
317
+ /**
318
+ * @since 2.18
319
+ */
320
+ protected Column (Column src , int index , CsvValueDecorator valueDecorator ,
321
+ Column next )
296
322
{
297
323
_index = index ;
298
324
_name = src ._name ;
299
325
_type = src ._type ;
300
326
_arrayElementSeparator = src ._arrayElementSeparator ;
327
+ _valueDecorator = valueDecorator ;
301
328
_next = next ;
302
329
}
303
-
330
+
304
331
public Column withName (String newName ) {
305
332
if (_name == newName ) {
306
333
return this ;
@@ -323,6 +350,16 @@ public Column withArrayElementSeparator(String separator) {
323
350
return new Column (_index , _name , _type , sep );
324
351
}
325
352
353
+ /**
354
+ * @since 2.18
355
+ */
356
+ public Column withValueDecorator (CsvValueDecorator valueDecorator ) {
357
+ if (valueDecorator == _valueDecorator ) {
358
+ return this ;
359
+ }
360
+ return new Column (this , valueDecorator );
361
+ }
362
+
326
363
public Column withNext (Column next ) {
327
364
if (_next == next ) {
328
365
return this ;
@@ -366,6 +403,11 @@ public boolean hasName(String n) {
366
403
*/
367
404
public String getArrayElementSeparator () { return _arrayElementSeparator ; }
368
405
406
+ /**
407
+ * @since 2.18
408
+ */
409
+ public CsvValueDecorator getValueDecorator () { return _valueDecorator ; }
410
+
369
411
public boolean isArray () {
370
412
return (_type == ColumnType .ARRAY );
371
413
}
@@ -445,6 +487,22 @@ public Builder addColumn(String name) {
445
487
return addColumn (new Column (index , name ));
446
488
}
447
489
490
+ /**
491
+ * Add column with given name, and with changes to apply (as specified
492
+ * by second argument, {@code transformer}).
493
+ * NOTE: does NOT check for duplicate column names so it is possibly to
494
+ * accidentally add duplicates.
495
+ *
496
+ * @param name Name of column to add
497
+ * @param transformer Changes to apply to column definition
498
+ *
499
+ * @since 2.18
500
+ */
501
+ public Builder addColumn (String name , UnaryOperator <Column > transformer ) {
502
+ Column col = transformer .apply (new Column (_columns .size (), name ));
503
+ return addColumn (col );
504
+ }
505
+
448
506
/**
449
507
* NOTE: does NOT check for duplicate column names so it is possibly to
450
508
* accidentally add duplicates.
@@ -454,6 +512,24 @@ public Builder addColumn(String name, ColumnType type) {
454
512
return addColumn (new Column (index , name , type ));
455
513
}
456
514
515
+ /**
516
+ * Add column with given name, and with changes to apply (as specified
517
+ * by second argument, {@code transformer}).
518
+ * NOTE: does NOT check for duplicate column names so it is possibly to
519
+ * accidentally add duplicates.
520
+ *
521
+ * @param name Name of column to add
522
+ * @param type Type of the column to add
523
+ * @param transformer Changes to apply to column definition
524
+ *
525
+ * @since 2.18
526
+ */
527
+ public Builder addColumn (String name , ColumnType type ,
528
+ UnaryOperator <Column > transformer ) {
529
+ Column col = transformer .apply (new Column (_columns .size (), name , type ));
530
+ return addColumn (col );
531
+ }
532
+
457
533
/**
458
534
* NOTE: does NOT check for duplicate column names so it is possibly to
459
535
* accidentally add duplicates.
@@ -1175,6 +1251,9 @@ public CsvSchema withoutColumns() {
1175
1251
* returns it unmodified (if no new columns found from `toAppend`), or constructs
1176
1252
* a new instance and returns that.
1177
1253
*
1254
+ * @return Either this schema (if nothing changed), or newly constructed {@link CsvSchema}
1255
+ * with appended columns.
1256
+ *
1178
1257
* @since 2.9
1179
1258
*/
1180
1259
public CsvSchema withColumnsFrom (CsvSchema toAppend ) {
@@ -1192,6 +1271,77 @@ public CsvSchema withColumnsFrom(CsvSchema toAppend) {
1192
1271
return b .build ();
1193
1272
}
1194
1273
1274
+ /**
1275
+ * Mutant factory method that will try to replace specified column with
1276
+ * changed definition (but same name), leaving other columns as-is.
1277
+ *<p>
1278
+ * As with all `withXxx()` methods this method never modifies `this` but either
1279
+ * returns it unmodified (if no change to column), or constructs
1280
+ * a new schema instance and returns that.
1281
+ *
1282
+ * @param columnName Name of column to replace
1283
+ * @param transformer Transformation to apply to the column
1284
+ *
1285
+ * @return Either this schema (if column did not change), or newly constructed {@link CsvSchema}
1286
+ * with changed column
1287
+ *
1288
+ * @since 2.18
1289
+ */
1290
+ public CsvSchema withColumn (String columnName , UnaryOperator <Column > transformer ) {
1291
+ Column old = column (columnName );
1292
+ if (old == null ) {
1293
+ throw new IllegalArgumentException ("No column '" +columnName +"' in CsvSchema (known columns: "
1294
+ +getColumnNames ()+")" );
1295
+ }
1296
+ Column newColumn = transformer .apply (old );
1297
+ if (newColumn == old ) {
1298
+ return this ;
1299
+ }
1300
+ return _withColumn (old .getIndex (), newColumn );
1301
+ }
1302
+
1303
+ /**
1304
+ * Mutant factory method that will try to replace specified column with
1305
+ * changed definition (but same name), leaving other columns as-is.
1306
+ *<p>
1307
+ * As with all `withXxx()` methods this method never modifies `this` but either
1308
+ * returns it unmodified (if no change to column), or constructs
1309
+ * a new schema instance and returns that.
1310
+ *
1311
+ * @param columnIndex Index of column to replace
1312
+ * @param transformer Transformation to apply to the column
1313
+ *
1314
+ * @return Either this schema (if column did not change), or newly constructed {@link CsvSchema}
1315
+ * with changed column
1316
+ *
1317
+ * @since 2.18
1318
+ */
1319
+ public CsvSchema withColumn (int columnIndex , UnaryOperator <Column > transformer ) {
1320
+ if (columnIndex < 0 || columnIndex >= size ()) {
1321
+ throw new IllegalArgumentException ("Illegal index " +columnIndex +"; `CsvSchema` has " +size ()+" columns" );
1322
+ }
1323
+ Column old = _columns [columnIndex ];
1324
+ Column newColumn = transformer .apply (old );
1325
+ if (newColumn == old ) {
1326
+ return this ;
1327
+ }
1328
+ return _withColumn (old .getIndex (), newColumn );
1329
+ }
1330
+
1331
+ /**
1332
+ * @since 2.18
1333
+ */
1334
+ protected CsvSchema _withColumn (int ix , Column toReplace ) {
1335
+ Objects .requireNonNull (toReplace );
1336
+ if (ix < 0 || ix >= size ()) {
1337
+ throw new IllegalArgumentException ("Illegal index for column '" +toReplace .getName ()+"': "
1338
+ +ix +" (column count: " +size ()+")" );
1339
+ }
1340
+ return rebuild ()
1341
+ .replaceColumn (ix , toReplace )
1342
+ .build ();
1343
+ }
1344
+
1195
1345
/**
1196
1346
* @since 2.7
1197
1347
*/
@@ -1352,6 +1502,19 @@ public Column column(int index) {
1352
1502
return _columns [index ];
1353
1503
}
1354
1504
1505
+ /**
1506
+ * Method for finding index of a named column within this schema.
1507
+ *
1508
+ * @param name Name of column to find
1509
+ * @return Index of the specified column, if one exists; {@code -1} if not
1510
+ *
1511
+ * @since 2.18
1512
+ */
1513
+ public int columnIndex (String name ) {
1514
+ Column col = column (name );
1515
+ return (col == null ) ? -1 : col .getIndex ();
1516
+ }
1517
+
1355
1518
/**
1356
1519
* @since 2.6
1357
1520
*/
0 commit comments