Skip to content

Commit 07a0724

Browse files
committed
Merge branch 'master' of github.com:apache/commons-csv into fixtypoPerformanceTest
2 parents 18b7fb9 + a35797b commit 07a0724

15 files changed

Lines changed: 260 additions & 59 deletions

File tree

RELEASE-NOTES.txt

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55

66
INTRODUCTION:
77

8-
This document contains the release notes for the 1.8 version of Apache Commons CSV.
8+
This document contains the release notes for the 1.8-SNAPSHOT version of Apache Commons CSV.
99
Commons CSV reads and writes files in variations of the Comma Separated Value (CSV) format.
1010

1111
Commons CSV requires at least Java 6.
1212

1313
The Apache Commons CSV library provides a simple interface for reading and writing CSV files of various types.
1414

15-
Feature and bug fix release (Java 8)
15+
Feature and bug fix release (Java 8).
16+
This release fixes serialization compatibility of CSVRecord with versions 1.0 to 1.6. New fields added since
17+
1.7 are not serialized. Support for Serializable is scheduled to be removed in version 2.0.
1618

1719
Changes in this version include:
1820

@@ -32,6 +34,7 @@ o CSV-241: CSVFormat#validate() does not account for allowDuplicateHeaderNames
3234
o CSV-245: Post 1.7 release fixes. Thanks to Alex Herbert.
3335
o CSV-252: Upgrade test framework to JUnit 5 Jupiter #49, #50. Thanks to Alex Herbert.
3436
o CSV-247: A single empty header is allowed when not allowing empty column headers. #47. Thanks to Alex Herbert, Gary Gregory.
37+
o CSV-248: CSVRecord is not Serializable. Thanks to Alex Herbert.
3538
o Use test scope for supercsv #48. Thanks to Alex Herbert.
3639

3740
CHANGES
@@ -41,6 +44,7 @@ o Update tests from H2 1.4.199 to 1.4.200. Thanks to Gary Gregory.
4144
o Update tests from Hamcrest 2.1 to 2.2. Thanks to Gary Gregory.
4245
o Update tests from Mockito 3.1.0 to 3.2.4. Thanks to Gary Gregory.
4346
o Fix typos in site and test #53. Thanks to Chen.
47+
o Fix typo performance test #55. Thanks to Chen.
4448

4549

4650
Historical list of changes: https://commons.apache.org/proper/commons-csv/changes-report.html

pom.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
<dependency>
3333
<groupId>org.junit.jupiter</groupId>
3434
<artifactId>junit-jupiter</artifactId>
35-
<version>5.5.2</version>
35+
<version>5.6.0</version>
3636
<scope>test</scope>
3737
</dependency>
3838
<dependency>
@@ -140,7 +140,7 @@
140140
<commons.release.version>1.8</commons.release.version>
141141
<commons.release.desc>(Java 8)</commons.release.desc>
142142
<!-- The RC version used in the staging repository URL. -->
143-
<commons.rc.version>RC1</commons.rc.version>
143+
<commons.rc.version>RC2</commons.rc.version>
144144
<commons.bc.version>1.7</commons.bc.version>
145145
<commons.componentid>csv</commons.componentid>
146146
<commons.module.name>org.apache.commons.csv</commons.module.name>
@@ -258,6 +258,7 @@
258258
<!-- The ferc.gov files are included discussion in https://issues.apache.org/jira/browse/LEGAL-175. -->
259259
<exclude>src/test/resources/ferc.gov/contract.txt</exclude>
260260
<exclude>src/test/resources/ferc.gov/transaction.txt</exclude>
261+
<exclude>src/test/resources/**/*.bin</exclude>
261262
</excludes>
262263
</configuration>
263264
</plugin>
@@ -376,6 +377,7 @@
376377
<exclude>src/test/resources/CSVFileParser/testCSV85_ignoreEmpty.txt</exclude>
377378
<exclude>src/test/resources/ferc.gov/contract.txt</exclude>
378379
<exclude>src/test/resources/ferc.gov/transaction.txt</exclude>
380+
<exclude>src/test/resources/**/*.bin</exclude>
379381
</excludes>
380382
</configuration>
381383
</plugin>

src/changes/changes.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@
3838
<title>Apache Commons CSV Release Notes</title>
3939
</properties>
4040
<body>
41-
<release version="1.8" date="2019-01-18" description="Feature and bug fix release (Java 8)">
41+
<release version="1.8" date="2019-02-01" description="Feature and bug fix release (Java 8).
42+
43+
This release fixes serialization compatibility of CSVRecord with versions 1.0 to 1.6.
44+
New fields added since 1.7 are not serialized. Support for Serializable is scheduled to be
45+
removed in version 2.0.
46+
">
4247
<action issue="CSV-255" type="add" dev="ggregory" due-to="0x100">Add CSVRecord.isSet(int) method #52.</action>
4348
<action issue="CSV-135" type="fix" dev="sebb" due-to="Mateusz Zakarczemny">Char escape doesn't work properly with quoting.</action>
4449
<action issue="CSV-244" type="fix" dev="sebb">Test case failures following CSVFormat#equals() update.</action>
@@ -48,11 +53,13 @@
4853
<action issue="CSV-245" type="fix" dev="ggregory" due-to="Alex Herbert">Post 1.7 release fixes.</action>
4954
<action issue="CSV-252" type="fix" dev="ggregory" due-to= "Alex Herbert">Upgrade test framework to JUnit 5 Jupiter #49, #50.</action>
5055
<action issue="CSV-247" type="fix" dev="ggregory" due-to="Alex Herbert, Gary Gregory">A single empty header is allowed when not allowing empty column headers. #47.</action>
56+
<action issue="CSV-248" type="fix" dev="ggregory" due-to="Alex Herbert">CSVRecord is not Serializable.</action>
5157
<action type="fix" dev="ggregory" due-to="Alex Herbert">Use test scope for supercsv #48.</action>
5258
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from H2 1.4.199 to 1.4.200.</action>
5359
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from Hamcrest 2.1 to 2.2.</action>
5460
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from Mockito 3.1.0 to 3.2.4.</action>
5561
<action type="update" dev="ggregory" due-to="Chen">Fix typos in site and test #53.</action>
62+
<action type="update" dev="ggregory" due-to="Chen">Fix typo performance test #55.</action>
5663
</release>
5764
<release version="1.7" date="2019-06-01" description="Feature and bug fix release (Java 8)">
5865
<action issue="CSV-233" type="add" dev="ggregory" due-to="Gary Gregory">Add predefined CSVFormats for printing MongoDB CSV and TSV.</action>

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,11 @@ public String getFirstEndOfLine() {
555555
* <p>
556556
* The map keys are column names. The map values are 0-based indices.
557557
* </p>
558+
* <p>
559+
* Note: The map can only provide a one-to-one mapping when the format did not
560+
* contain null or duplicate column names.
561+
* </p>
562+
*
558563
* @return a copy of the header map.
559564
*/
560565
public Map<String, Integer> getHeaderMap() {
@@ -577,8 +582,14 @@ Map<String, Integer> getHeaderMapRaw() {
577582

578583
/**
579584
* Returns a read-only list of header names that iterates in column order.
585+
* <p>
586+
* Note: The list provides strings that can be used as keys in the header map.
587+
* The list will not contain null column names if they were present in the input
588+
* format.
589+
* </p>
580590
*
581591
* @return read-only list of header names that iterates in column order.
592+
* @see #getHeaderMap()
582593
* @since 1.7
583594
*/
584595
public List<String> getHeaderNames() {

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,19 @@
2424
import java.util.List;
2525
import java.util.Map;
2626
import java.util.Map.Entry;
27+
import java.util.Objects;
2728

2829
/**
2930
* A CSV record parsed from a CSV file.
31+
*
32+
* <p>
33+
* Note: Support for {@link Serializable} is scheduled to be removed in version 2.0.
34+
* In version 1.8 the mapping between the column header and the column index was
35+
* removed from the serialised state. The class maintains serialization compatibility
36+
* with versions pre-1.8 for the record values; these must be accessed by index
37+
* following deserialization. There will be loss of any functionally linked to the header
38+
* mapping when transferring serialised forms pre-1.8 to 1.8 and vice versa.
39+
* </p>
3040
*/
3141
public final class CSVRecord implements Serializable, Iterable<String> {
3242

@@ -45,8 +55,8 @@ public final class CSVRecord implements Serializable, Iterable<String> {
4555
/** The values of the record */
4656
private final String[] values;
4757

48-
/** The parser that originates this record. */
49-
private final CSVParser parser;
58+
/** The parser that originates this record. This is not serialized. */
59+
private final transient CSVParser parser;
5060

5161
CSVRecord(final CSVParser parser, final String[] values, final String comment, final long recordNumber,
5262
final long characterPosition) {
@@ -65,7 +75,7 @@ public final class CSVRecord implements Serializable, Iterable<String> {
6575
* @return the String at the given enum String
6676
*/
6777
public String get(final Enum<?> e) {
68-
return get(e.toString());
78+
return get(Objects.toString(e, null));
6979
}
7080

7181
/**
@@ -82,14 +92,24 @@ public String get(final int i) {
8292
/**
8393
* Returns a value by name.
8494
*
95+
* <p>
96+
* Note: This requires a field mapping obtained from the original parser.
97+
* A check using {@link #isMapped(String)} should be used to determine if a
98+
* mapping exists from the provided {@code name} to a field index. In this case an
99+
* exception will only be thrown if the record does not contain a field corresponding
100+
* to the mapping, that is the record length is not consistent with the mapping size.
101+
* </p>
102+
*
85103
* @param name
86104
* the name of the column to be retrieved.
87105
* @return the column value, maybe null depending on {@link CSVFormat#getNullString()}.
88106
* @throws IllegalStateException
89107
* if no header mapping was provided
90108
* @throws IllegalArgumentException
91109
* if {@code name} is not mapped or if the record is inconsistent
110+
* @see #isMapped(String)
92111
* @see #isConsistent()
112+
* @see #getParser()
93113
* @see CSVFormat#withNullString(String)
94114
*/
95115
public String get(final String name) {
@@ -135,12 +155,17 @@ public String getComment() {
135155
}
136156

137157
private Map<String, Integer> getHeaderMapRaw() {
138-
return parser.getHeaderMapRaw();
158+
return parser == null ? null : parser.getHeaderMapRaw();
139159
}
140160

141161
/**
142162
* Returns the parser.
143163
*
164+
* <p>
165+
* Note: The parser is not part of the serialized state of the record. A null check
166+
* should be used when the record may have originated from a serialized form.
167+
* </p>
168+
*
144169
* @return the parser.
145170
* @since 1.7
146171
*/

src/site/xdoc/user-guide.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ limitations under the License.
3232

3333
Parsing files with Apache Commons CSV is relatively straight forward.
3434
The CSVFormat class provides some commonly used CSV variants:
35-
35+
3636
<dl>
3737
<dt><a href="https://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVFormat.html#DEFAULT">DEFAULT</a></dt><dd>Standard Comma Separated Value format, as for RFC4180 but allowing empty lines.</dd>
3838
<dt><a href="https://commons.apache.org/proper/commons-csv/apidocs/org/apache/commons/csv/CSVFormat.html#EXCEL">EXCEL</a></dt><dd>The Microsoft Excel CSV format.</dd>

src/test/java/org/apache/commons/csv/CSVBenchmark.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public int read(final Blackhole bh) throws Exception {
7979
while ((line = in.readLine()) != null) {
8080
count++;
8181
}
82-
82+
8383
bh.consume(count);
8484
in.close();
8585
return count;
@@ -94,7 +94,7 @@ public int split(final Blackhole bh) throws Exception {
9494
final String[] values = StringUtils.split(line, ',');
9595
count += values.length;
9696
}
97-
97+
9898
bh.consume(count);
9999
in.close();
100100
return count;
@@ -103,7 +103,7 @@ public int split(final Blackhole bh) throws Exception {
103103
@Benchmark
104104
public int parseCommonsCSV(final Blackhole bh) throws Exception {
105105
final BufferedReader in = getReader();
106-
106+
107107
final CSVFormat format = CSVFormat.DEFAULT.withHeader();
108108

109109
int count = 0;
@@ -119,7 +119,7 @@ public int parseCommonsCSV(final Blackhole bh) throws Exception {
119119
@Benchmark
120120
public int parseGenJavaCSV(final Blackhole bh) throws Exception {
121121
final BufferedReader in = getReader();
122-
122+
123123
final CsvReader reader = new CsvReader(in);
124124
reader.setFieldDelimiter(',');
125125

@@ -137,7 +137,7 @@ public int parseGenJavaCSV(final Blackhole bh) throws Exception {
137137
@Benchmark
138138
public int parseJavaCSV(final Blackhole bh) throws Exception {
139139
final BufferedReader in = getReader();
140-
140+
141141
final com.csvreader.CsvReader reader = new com.csvreader.CsvReader(in, ',');
142142
reader.setRecordDelimiter('\n');
143143

@@ -154,7 +154,7 @@ public int parseJavaCSV(final Blackhole bh) throws Exception {
154154
@Benchmark
155155
public int parseOpenCSV(final Blackhole bh) throws Exception {
156156
final BufferedReader in = getReader();
157-
157+
158158
final com.opencsv.CSVReader reader = new com.opencsv.CSVReader(in, ',');
159159

160160
int count = 0;
@@ -170,10 +170,10 @@ public int parseOpenCSV(final Blackhole bh) throws Exception {
170170
@Benchmark
171171
public int parseSkifeCSV(final Blackhole bh) throws Exception {
172172
final BufferedReader in = getReader();
173-
173+
174174
final org.skife.csv.CSVReader reader = new org.skife.csv.SimpleReader();
175175
reader.setSeperator(',');
176-
176+
177177
final CountingReaderCallback callback = new CountingReaderCallback();
178178
reader.parse(in, callback);
179179

@@ -194,7 +194,7 @@ public void onRow(final String[] fields) {
194194
@Benchmark
195195
public int parseSuperCSV(final Blackhole bh) throws Exception {
196196
final BufferedReader in = getReader();
197-
197+
198198
final CsvListReader reader = new CsvListReader(in, CsvPreference.STANDARD_PREFERENCE);
199199

200200
int count = 0;

src/test/java/org/apache/commons/csv/CSVFileParserTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class CSVFileParserTest {
4242

4343
private static final File BASE = new File("src/test/resources/CSVFileParser");
4444

45-
private String readTestData(BufferedReader reader) throws IOException {
45+
private String readTestData(final BufferedReader reader) throws IOException {
4646
String line;
4747
do {
4848
line = reader.readLine();
@@ -61,7 +61,7 @@ public static Stream<File> generateData() {
6161

6262
@ParameterizedTest
6363
@MethodSource("generateData")
64-
public void testCSVFile(File testFile) throws Exception {
64+
public void testCSVFile(final File testFile) throws Exception {
6565
try (FileReader fr = new FileReader(testFile); BufferedReader testData = new BufferedReader(fr)) {
6666
String line = readTestData(testData);
6767
assertNotNull("file must contain config line", line);
@@ -108,7 +108,7 @@ public void testCSVFile(File testFile) throws Exception {
108108

109109
@ParameterizedTest
110110
@MethodSource("generateData")
111-
public void testCSVUrl(File testFile) throws Exception {
111+
public void testCSVUrl(final File testFile) throws Exception {
112112
try (FileReader fr = new FileReader(testFile); BufferedReader testData = new BufferedReader(fr)) {
113113
String line = readTestData(testData);
114114
assertNotNull("file must contain config line", line);

src/test/java/org/apache/commons/csv/CSVFormatTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ private static CSVFormat copy(final CSVFormat format) {
6464
return format.withDelimiter(format.getDelimiter());
6565
}
6666

67-
private void assertNotEquals(String name, String type, Object left, Object right) {
67+
private void assertNotEquals(final String name, final String type, final Object left, final Object right) {
6868
if (left.equals(right) || right.equals(left)) {
6969
fail("Objects must not compare equal for " + name + "(" + type + ")");
7070
}
@@ -153,12 +153,12 @@ public void testEqualsEscape() {
153153

154154
@Test
155155
public void testEqualsHash() throws Exception {
156-
Method[] methods = CSVFormat.class.getDeclaredMethods();
157-
for (Method method : methods) {
156+
final Method[] methods = CSVFormat.class.getDeclaredMethods();
157+
for (final Method method : methods) {
158158
if (Modifier.isPublic(method.getModifiers())) {
159159
final String name = method.getName();
160160
if (name.startsWith("with")) {
161-
for (Class<?> cls : method.getParameterTypes()) {
161+
for (final Class<?> cls : method.getParameterTypes()) {
162162
final String type = cls.getCanonicalName();
163163
if ("boolean".equals(type)) {
164164
final Object defTrue = method.invoke(CSVFormat.DEFAULT, new Object[] {Boolean.TRUE});
@@ -550,7 +550,7 @@ public void testFormatThrowsNullPointerException() {
550550

551551
final CSVFormat csvFormat = CSVFormat.MYSQL;
552552

553-
NullPointerException e = assertThrows(NullPointerException.class, () -> csvFormat.format((Object[]) null));
553+
final NullPointerException e = assertThrows(NullPointerException.class, () -> csvFormat.format((Object[]) null));
554554
assertEquals(CSVFormat.class.getName(), e.getStackTrace()[0].getClassName());
555555
}
556556

src/test/java/org/apache/commons/csv/CSVParserTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,20 @@ public void testHeadersMissingOneColumnException() throws Exception {
724724
assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withHeader().parse(in).iterator());
725725
}
726726

727+
@Test
728+
public void testHeadersWithNullColumnName() throws IOException {
729+
final Reader in = new StringReader("header1,null,header3\n1,2,3\n4,5,6");
730+
final Iterator<CSVRecord> records = CSVFormat.DEFAULT
731+
.withHeader()
732+
.withNullString("null")
733+
.withAllowMissingColumnNames()
734+
.parse(in).iterator();
735+
final CSVRecord record = records.next();
736+
// Expect the null header to be missing
737+
assertEquals(Arrays.asList("header1", "header3"), record.getParser().getHeaderNames());
738+
assertEquals(2, record.getParser().getHeaderMap().size());
739+
}
740+
727741
@Test
728742
public void testIgnoreCaseHeaderMapping() throws Exception {
729743
final Reader reader = new StringReader("1,2,3");

0 commit comments

Comments
 (0)