Skip to content

Commit 69aa686

Browse files
committed
CSV-264: CSVParser identifies null, empty or blank headers as 'missing'
Duplicate missing header names are handled consistently between CSVFormat and CSVParser. Document that the ignore header case flag is for parser behaviour. Update CSVDuplicateHeaderTest to add the ignore header case flag to tests. Add test cases with case insensitive duplicates.
1 parent 8ad07df commit 69aa686

3 files changed

Lines changed: 175 additions & 119 deletions

File tree

src/main/java/org/apache/commons/csv/CSVFormat.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ public Builder setAllowDuplicateHeaderNames(final boolean allowDuplicateHeaderNa
289289
}
290290

291291
/**
292-
* Sets the missing column names parser behavior, {@code true} to allow missing column names in the header line, {@code false} to cause an
292+
* Sets the parser missing column names behavior, {@code true} to allow missing column names in the header line, {@code false} to cause an
293293
* {@link IllegalArgumentException} to be thrown.
294294
*
295295
* @param allowMissingColumnNames the missing column names behavior, {@code true} to allow missing column names in the header line, {@code false} to
@@ -564,7 +564,7 @@ public Builder setIgnoreEmptyLines(final boolean ignoreEmptyLines) {
564564
}
565565

566566
/**
567-
* Sets the case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
567+
* Sets the parser case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
568568
*
569569
* @param ignoreHeaderCase the case mapping behavior, {@code true} to access name/values, {@code false} to leave the mapping as is.
570570
* @return This instance.
@@ -1599,7 +1599,7 @@ public boolean getIgnoreEmptyLines() {
15991599
}
16001600

16011601
/**
1602-
* Gets whether header names will be accessed ignoring case.
1602+
* Gets whether header names will be accessed ignoring case when parsing input.
16031603
*
16041604
* @return {@code true} if header names cases are ignored, {@code false} if they are case sensitive.
16051605
* @since 1.3

src/main/java/org/apache/commons/csv/CSVParser.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,8 @@ private Headers createHeaders() throws IOException {
499499

500500
// build the name to index mappings
501501
if (headerRecord != null) {
502+
// Track an occurrence of a null, empty or blank header.
503+
boolean observedMissing = false;
502504
for (int i = 0; i < headerRecord.length; i++) {
503505
final String header = headerRecord[i];
504506
final boolean blankHeader = CSVFormat.isBlank(header);
@@ -507,7 +509,7 @@ private Headers createHeaders() throws IOException {
507509
"A header name is missing in " + Arrays.toString(headerRecord));
508510
}
509511

510-
final boolean containsHeader = header != null && hdrMap.containsKey(header);
512+
final boolean containsHeader = blankHeader ? observedMissing : hdrMap.containsKey(header);
511513
final DuplicateHeaderMode headerMode = this.format.getDuplicateHeaderMode();
512514
final boolean duplicatesAllowed = headerMode == DuplicateHeaderMode.ALLOW_ALL;
513515
final boolean emptyDuplicatesAllowed = headerMode == DuplicateHeaderMode.ALLOW_EMPTY;
@@ -518,6 +520,7 @@ private Headers createHeaders() throws IOException {
518520
"The header contains a duplicate name: \"%s\" in %s. If this is valid then use CSVFormat.Builder.setDuplicateHeaderMode().",
519521
header, Arrays.toString(headerRecord)));
520522
}
523+
observedMissing |= blankHeader;
521524
if (header != null) {
522525
hdrMap.put(header, Integer.valueOf(i));
523526
if (headerNames == null) {

0 commit comments

Comments
 (0)