1717import org .kohsuke .stapler .DataBoundConstructor ;
1818
1919import java .io .File ;
20+ import java .io .BufferedReader ;
2021import java .io .IOException ;
2122import java .util .*;
23+ import java .io .FileInputStream ;
24+ import java .io .InputStreamReader ;
25+ import java .nio .charset .StandardCharsets ;
2226
2327public class Csv extends Provider {
24-
28+
2529 private static final long serialVersionUID = 9141170397250309265L ;
2630
2731 private static final String ID = "csv" ;
28-
32+
2933 @ DataBoundConstructor
3034 public Csv () {
3135 super ();
3236 // empty constructor required for stapler
3337 }
34-
38+
3539 @ Override
3640 public ReportParser createParser () {
3741 if (getActualId ().equals (getDescriptor ().getId ())) {
3842 throw new IllegalArgumentException (Messages .Provider_Error ());
3943 }
40-
44+
4145 return new CsvCustomParser (getActualId ());
4246 }
4347
@@ -54,9 +58,9 @@ public Descriptor() {
5458 public static class CsvCustomParser extends ReportParser {
5559
5660 private static final long serialVersionUID = -8689695008930386640L ;
57-
61+
5862 private final String id ;
59-
63+
6064 private List <String > parserMessages ;
6165
6266 public CsvCustomParser (String id ) {
@@ -69,17 +73,54 @@ public String getId() {
6973 return id ;
7074 }
7175
76+
77+ private char detectDelimiter (File file ) throws IOException {
78+ // List of possible delimiters
79+ char [] delimiters = { ',' , ';' , '\t' , '|' };
80+ int [] delimiterCounts = new int [delimiters .length ];
81+
82+ // Read the lines of the file to detect the delimiter
83+ try (BufferedReader reader = new BufferedReader (new InputStreamReader (new FileInputStream (file ), StandardCharsets .UTF_8 ))) {
84+ int linesToCheck = 5 ; // Number of lines to check
85+ int linesChecked = 0 ;
86+
87+ String line ;
88+ while ((line = reader .readLine ()) != null && linesChecked < linesToCheck ) {
89+ for (int i = 0 ; i < delimiters .length ; i ++) {
90+ delimiterCounts [i ] += StringUtils .countMatches (line , delimiters [i ]);
91+ }
92+ linesChecked ++;
93+ }
94+ }
95+
96+ // Return the most frequent delimiter
97+ int maxCount = 0 ;
98+ char detectedDelimiter = 0 ;
99+ for (int i = 0 ; i < delimiters .length ; i ++) {
100+ if (delimiterCounts [i ] > maxCount ) {
101+ maxCount = delimiterCounts [i ];
102+ detectedDelimiter = delimiters [i ];
103+ }
104+ }
105+
106+ return detectedDelimiter ;
107+ }
108+
109+
72110 @ Override
73111 public ReportDto parse (File file ) throws IOException {
112+ // Get delimiter
113+ char delimiter = detectDelimiter (file );
74114
75115 final CsvMapper mapper = new CsvMapper ();
76- final CsvSchema schema = mapper .schemaFor (String [].class ).withColumnSeparator (',' );
116+ final CsvSchema schema = mapper .schemaFor (String [].class ).withColumnSeparator (delimiter );
77117
78118 mapper .enable (CsvParser .Feature .WRAP_AS_ARRAY );
79119 mapper .enable (CsvParser .Feature .SKIP_EMPTY_LINES );
80120 mapper .enable (CsvParser .Feature .ALLOW_TRAILING_COMMA );
81121 mapper .enable (CsvParser .Feature .INSERT_NULLS_FOR_MISSING_COLUMNS );
82122 mapper .enable (CsvParser .Feature .TRIM_SPACES );
123+
83124 final MappingIterator <List <String >> it = mapper .readerForListOf (String .class )
84125 .with (schema )
85126 .readValues (file );
@@ -100,6 +141,7 @@ public ReportDto parse(File file) throws IOException {
100141 } else {
101142 parserMessages .add (String .format ("skipped file - First line has %d elements" , headerColumnCount + 1 ));
102143 }
144+
103145 /** Parse all data rows */
104146 for (int rowIdx = 0 ; rowIdx < rowCount ; rowIdx ++) {
105147 String parentId = "report" ;
@@ -116,20 +158,22 @@ public ReportDto parse(File file) throws IOException {
116158 for (int colIdx = rowSize - 1 ; colIdx > 1 ; colIdx --) {
117159 String value = row .get (colIdx );
118160
119- if (NumberUtils .isCreatable (value ) == true ) {
161+ if (NumberUtils .isCreatable (value )) {
120162 colIdxValueStart = colIdx ;
121163 } else {
122164 if (colIdxValueStart > 0 ) {
123- parserMessages .add (String .format ("Found data - fields number = %d - numeric fields = %d" , colIdxValueStart , rowSize - colIdxValueStart ));
165+ parserMessages
166+ .add (String .format ("Found data - fields number = %d - numeric fields = %d" ,
167+ colIdxValueStart , rowSize - colIdxValueStart ));
124168 }
125169 break ;
126170 }
127171 }
128172 }
129173
130- String valueId = "" ;
174+ String valueId = "" ;
131175 /** Parse line if first data line is OK and line has more element than header */
132- if ((colIdxValueStart > 0 ) && (rowSize >= headerColumnCount )){
176+ if ((colIdxValueStart > 0 ) && (rowSize >= headerColumnCount )) {
133177 /** Check line and header size matching */
134178 for (int colIdx = 0 ; colIdx < headerColumnCount ; colIdx ++) {
135179 String id = header .get (colIdx );
@@ -141,19 +185,22 @@ public ReportDto parse(File file) throws IOException {
141185 if ((NumberUtils .isCreatable (value )) || (StringUtils .isBlank (value ))) {
142186 /** Empty field found - message */
143187 if (colIdx == 0 ) {
144- parserMessages .add (String .format ("skipped line %d - First column item empty - col = %d " , rowIdx + 2 , colIdx + 1 ));
145- break ;
188+ parserMessages
189+ .add (String .format ("skipped line %d - First column item empty - col = %d " ,
190+ rowIdx + 2 , colIdx + 1 ));
191+ break ;
146192 } else {
147193 emptyFieldFound = true ;
148194 /** Continue next column parsing */
149195 continue ;
150196 }
151197 } else {
152198 /** Check if field values are present after empty cells */
153- if (emptyFieldFound == true ) {
154- parserMessages .add (String .format ("skipped line %d Empty field in col = %d " , rowIdx + 2 , colIdx + 1 ));
155- break ;
156- }
199+ if (emptyFieldFound ) {
200+ parserMessages .add (String .format ("skipped line %d Empty field in col = %d " ,
201+ rowIdx + 2 , colIdx + 1 ));
202+ break ;
203+ }
157204 }
158205 valueId += value ;
159206 Optional <Item > parent = report .findItem (parentId , report .getItems ());
@@ -193,19 +240,20 @@ public ReportDto parse(File file) throws IOException {
193240 parserMessages .add (String .format ("skipped line %d - First data row not found" , rowIdx + 2 ));
194241 continue ;
195242 } else {
196- parserMessages .add (String .format ("skipped line %d - line has fewer element than title" , rowIdx + 2 ));
243+ parserMessages
244+ .add (String .format ("skipped line %d - line has fewer element than title" , rowIdx + 2 ));
197245 continue ;
198246 }
199247 }
200248 /** If last item was created, it will be added to report */
201- if (lastItemAdded == true ) {
249+ if (lastItemAdded ) {
202250 last .setResult (result );
203251 } else {
204252 parserMessages .add (String .format ("ignored line %d - Same fields already exists" , rowIdx + 2 ));
205253 }
206254 }
207- //report.setParserLog(parserMessages);
255+ // report.setParserLog(parserMessages);
208256 return report ;
209257 }
210258 }
211- }
259+ }
0 commit comments