2525import java .util .List ;
2626import java .util .Map ;
2727import java .util .Set ;
28+ import java .util .function .Consumer ;
2829
2930import org .apache .commons .logging .Log ;
3031import org .apache .commons .logging .LogFactory ;
6364 * @author Patrick Baumgartner
6465 * @author François Martin
6566 * @author Stefano Cordio
67+ * @author Daeho Kwon
6668 * @since 4.0
6769 * @see FlatFileItemReader
6870 */
@@ -319,6 +321,35 @@ public DelimitedBuilder<T> delimited() {
319321 return this .delimitedBuilder ;
320322 }
321323
324+ /**
325+ * Configure a {@link DelimitedSpec} using a lambda.
326+ * @return the current builder instance
327+ * @since 6.0
328+ */
329+ public FlatFileItemReaderBuilder <T > delimited (Consumer <DelimitedSpec <T >> config ) {
330+ DelimitedSpecImpl <T > spec = new DelimitedSpecImpl <>();
331+ config .accept (spec );
332+
333+ DelimitedBuilder <T > builder = this .delimited ();
334+ if (spec .delimiter != null ) {
335+ builder .delimiter (spec .delimiter );
336+ }
337+ if (spec .quoteCharacter != null ) {
338+ builder .quoteCharacter (spec .quoteCharacter );
339+ }
340+ if (!spec .names .isEmpty ()) {
341+ builder .names (spec .names .toArray (new String [0 ]));
342+ }
343+ if (!spec .included .isEmpty ()) {
344+ builder .includedFields (spec .included .toArray (new Integer [0 ]));
345+ }
346+
347+ builder .fieldSetFactory (spec .fieldSetFactory );
348+ builder .strict (spec .strict );
349+
350+ return this ;
351+ }
352+
322353 /**
323354 * Returns an instance of a {@link FixedLengthBuilder} for building a
324355 * {@link FixedLengthTokenizer}. The {@link FixedLengthTokenizer} configured by this
@@ -332,6 +363,30 @@ public FixedLengthBuilder<T> fixedLength() {
332363 return this .fixedLengthBuilder ;
333364 }
334365
366+ /**
367+ * Configure a {@link FixedLengthSpec} using a lambda.
368+ * @return the current builder instance
369+ * @since 6.0
370+ */
371+ public FlatFileItemReaderBuilder <T > fixedLength (Consumer <FixedLengthSpec <T >> config ) {
372+ FixedLengthSpecImpl <T > spec = new FixedLengthSpecImpl <>();
373+ config .accept (spec );
374+
375+ FixedLengthBuilder <T > builder = this .fixedLength ();
376+
377+ if (!spec .ranges .isEmpty ()) {
378+ builder .columns (spec .ranges .toArray (new Range [0 ]));
379+ }
380+ if (!spec .names .isEmpty ()) {
381+ builder .names (spec .names .toArray (new String [0 ]));
382+ }
383+
384+ builder .fieldSetFactory (spec .fieldSetFactory );
385+ builder .strict (spec .strict );
386+
387+ return this ;
388+ }
389+
335390 /**
336391 * The class that will represent the "item" to be returned from the reader. This class
337392 * is used via the {@link BeanWrapperFieldSetMapper}. If more complex logic is
@@ -775,4 +830,240 @@ public FixedLengthTokenizer build() {
775830
776831 }
777832
833+ /**
834+ * A specification for configuring a delimited file tokenizer.
835+ *
836+ * @param <T> the type of the parent {@link FlatFileItemReaderBuilder}
837+ * @since 6.0
838+ */
839+ public interface DelimitedSpec <T > {
840+
841+ /**
842+ * Define the delimiter for the file.
843+ * @param delimiter String used as a delimiter between fields.
844+ * @return The instance of the specification for chaining.
845+ * @see DelimitedLineTokenizer#setDelimiter(String)
846+ */
847+ DelimitedSpec <T > delimiter (String delimiter );
848+
849+ /**
850+ * Define the character used to quote fields.
851+ * @param quoteCharacter char used to define quoted fields
852+ * @return The instance of the specification for chaining.
853+ * @see DelimitedLineTokenizer#setQuoteCharacter(char)
854+ */
855+ DelimitedSpec <T > quoteCharacter (char quoteCharacter );
856+
857+ /**
858+ * A list of indices of the fields within a delimited file to be included
859+ * @param fields indices of the fields
860+ * @return The instance of the specification for chaining.
861+ * @see DelimitedLineTokenizer#setIncludedFields(int[])
862+ */
863+ DelimitedSpec <T > includedFields (Integer ... fields );
864+
865+ /**
866+ * Add an index to the list of fields to be included from the file
867+ * @param field the index to be included
868+ * @return The instance of the specification for chaining.
869+ * @see DelimitedLineTokenizer#setIncludedFields(int[])
870+ */
871+ DelimitedSpec <T > addIncludedField (int field );
872+
873+ /**
874+ * Names of each of the fields within the fields that are returned in the order
875+ * they occur within the delimited file. Required.
876+ * @param names names of each field
877+ * @return The instance of the specification for chaining.
878+ * @see DelimitedLineTokenizer#setNames(String[])
879+ */
880+ DelimitedSpec <T > names (String ... names );
881+
882+ /**
883+ * A factory for creating the resulting {@link FieldSet}. Defaults to
884+ * {@link DefaultFieldSetFactory}.
885+ * @param fieldSetFactory Factory for creating {@link FieldSet}
886+ * @return The instance of the specification for chaining.
887+ * @see DelimitedLineTokenizer#setFieldSetFactory(FieldSetFactory)
888+ */
889+ DelimitedSpec <T > fieldSetFactory (FieldSetFactory fieldSetFactory );
890+
891+ /**
892+ * If true (the default) then the number of tokens in line must match the number
893+ * of tokens defined (by {@link Range}, columns, etc.) in {@link LineTokenizer}.
894+ * If false then lines with less tokens will be tolerated and padded with empty
895+ * columns, and lines with more tokens will simply be truncated.
896+ * @param strict the strict flag to set
897+ */
898+ DelimitedSpec <T > strict (boolean strict );
899+
900+ }
901+
902+ /**
903+ * A specification for configuring a fixed length file tokenizer.
904+ *
905+ * @param <T> the type of the parent {@link FlatFileItemReaderBuilder}
906+ * @since 6.0
907+ */
908+ public interface FixedLengthSpec <T > {
909+
910+ /**
911+ * The column ranges for each field
912+ * @param ranges column ranges
913+ * @return This instance for chaining
914+ * @see FixedLengthTokenizer#setColumns(Range[])
915+ */
916+ FixedLengthSpec <T > columns (Range ... ranges );
917+
918+ /**
919+ * Add a column range to the existing list
920+ * @param range a new column range
921+ * @return This instance for chaining
922+ * @see FixedLengthTokenizer#setColumns(Range[])
923+ */
924+ FixedLengthSpec <T > addColumns (Range range );
925+
926+ /**
927+ * Insert a column range to the existing list
928+ * @param range a new column range
929+ * @param index index to add it at
930+ * @return This instance for chaining
931+ * @see FixedLengthTokenizer#setColumns(Range[])
932+ */
933+ FixedLengthSpec <T > addColumns (Range range , int index );
934+
935+ /**
936+ * The names of the fields to be parsed from the file. Required.
937+ * @param names names of fields
938+ * @return The parent builder
939+ * @see FixedLengthTokenizer#setNames(String[])
940+ */
941+ FixedLengthSpec <T > names (String ... names );
942+
943+ /**
944+ * A factory for creating the resulting {@link FieldSet}. Defaults to
945+ * {@link DefaultFieldSetFactory}.
946+ * @param fieldSetFactory Factory for creating {@link FieldSet}
947+ * @return The instance of the specification for chaining.
948+ * @see FixedLengthTokenizer#setFieldSetFactory(FieldSetFactory)
949+ */
950+ FixedLengthSpec <T > fieldSetFactory (FieldSetFactory fieldSetFactory );
951+
952+ /**
953+ * Boolean indicating if the number of tokens in a line must match the number of
954+ * fields (ranges) configured. Defaults to true.
955+ * @param strict defaults to true
956+ * @return This instance for chaining
957+ * @see FixedLengthTokenizer#setStrict(boolean)
958+ */
959+ FixedLengthSpec <T > strict (boolean strict );
960+
961+ }
962+
963+ private static class DelimitedSpecImpl <T > implements DelimitedSpec <T > {
964+
965+ private final List <String > names = new ArrayList <>();
966+
967+ private @ Nullable String delimiter ;
968+
969+ private @ Nullable Character quoteCharacter ;
970+
971+ private final List <Integer > included = new ArrayList <>();
972+
973+ private FieldSetFactory fieldSetFactory = new DefaultFieldSetFactory ();
974+
975+ private boolean strict = true ;
976+
977+ @ Override
978+ public DelimitedSpec <T > delimiter (String delimiter ) {
979+ this .delimiter = delimiter ;
980+ return this ;
981+ }
982+
983+ @ Override
984+ public DelimitedSpec <T > quoteCharacter (char quoteCharacter ) {
985+ this .quoteCharacter = quoteCharacter ;
986+ return this ;
987+ }
988+
989+ @ Override
990+ public DelimitedSpec <T > includedFields (Integer ... fields ) {
991+ this .included .addAll (Arrays .asList (fields ));
992+ return this ;
993+ }
994+
995+ @ Override
996+ public DelimitedSpec <T > addIncludedField (int field ) {
997+ this .included .add (field );
998+ return this ;
999+ }
1000+
1001+ @ Override
1002+ public DelimitedSpec <T > names (String ... names ) {
1003+ this .names .addAll (Arrays .asList (names ));
1004+ return this ;
1005+ }
1006+
1007+ @ Override
1008+ public DelimitedSpec <T > fieldSetFactory (FieldSetFactory f ) {
1009+ this .fieldSetFactory = f ;
1010+ return this ;
1011+ }
1012+
1013+ @ Override
1014+ public DelimitedSpec <T > strict (boolean strict ) {
1015+ this .strict = strict ;
1016+ return this ;
1017+ }
1018+
1019+ }
1020+
1021+ private static class FixedLengthSpecImpl <T > implements FixedLengthSpec <T > {
1022+
1023+ private final List <Range > ranges = new ArrayList <>();
1024+
1025+ private final List <String > names = new ArrayList <>();
1026+
1027+ private boolean strict = true ;
1028+
1029+ private FieldSetFactory fieldSetFactory = new DefaultFieldSetFactory ();
1030+
1031+ @ Override
1032+ public FixedLengthSpec <T > columns (Range ... ranges ) {
1033+ this .ranges .addAll (Arrays .asList (ranges ));
1034+ return this ;
1035+ }
1036+
1037+ @ Override
1038+ public FixedLengthSpec <T > addColumns (Range range ) {
1039+ this .ranges .add (range );
1040+ return this ;
1041+ }
1042+
1043+ @ Override
1044+ public FixedLengthSpec <T > addColumns (Range range , int index ) {
1045+ this .ranges .add (index , range );
1046+ return this ;
1047+ }
1048+
1049+ @ Override
1050+ public FixedLengthSpec <T > names (String ... names ) {
1051+ this .names .addAll (Arrays .asList (names ));
1052+ return this ;
1053+ }
1054+
1055+ @ Override
1056+ public FixedLengthSpec <T > fieldSetFactory (FieldSetFactory f ) {
1057+ this .fieldSetFactory = f ;
1058+ return this ;
1059+ }
1060+
1061+ @ Override
1062+ public FixedLengthSpec <T > strict (boolean strict ) {
1063+ this .strict = strict ;
1064+ return this ;
1065+ }
1066+
1067+ }
1068+
7781069}
0 commit comments