Skip to content

Commit 5a7b030

Browse files
authored
Merge pull request apache#279 from aherbert/csvparser-duplicate-missing-headers
CSVParser: Identify duplicates in null, empty and blank header names (WIP)
2 parents 8ad07df + 69aa686 commit 5a7b030

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)