mirror of
https://github.com/apache/commons-csv.git
synced 2025-02-09 11:35:26 +00:00
Merge branch 'master' into release
This commit is contained in:
commit
660f7c9f85
@ -5,14 +5,16 @@
|
|||||||
|
|
||||||
INTRODUCTION:
|
INTRODUCTION:
|
||||||
|
|
||||||
This document contains the release notes for the 1.8 version of Apache Commons CSV.
|
This document contains the release notes for the 1.8-SNAPSHOT version of Apache Commons CSV.
|
||||||
Commons CSV reads and writes files in variations of the Comma Separated Value (CSV) format.
|
Commons CSV reads and writes files in variations of the Comma Separated Value (CSV) format.
|
||||||
|
|
||||||
Commons CSV requires at least Java 6.
|
Commons CSV requires at least Java 6.
|
||||||
|
|
||||||
The Apache Commons CSV library provides a simple interface for reading and writing CSV files of various types.
|
The Apache Commons CSV library provides a simple interface for reading and writing CSV files of various types.
|
||||||
|
|
||||||
Feature and bug fix release (Java 8)
|
Feature and bug fix release (Java 8).
|
||||||
|
This release fixes serialization compatibility of CSVRecord with versions 1.0 to 1.6. New fields added since
|
||||||
|
1.7 are not serialized. Support for Serializable is scheduled to be removed in version 2.0.
|
||||||
|
|
||||||
Changes in this version include:
|
Changes in this version include:
|
||||||
|
|
||||||
@ -32,6 +34,7 @@ o CSV-241: CSVFormat#validate() does not account for allowDuplicateHeaderNames
|
|||||||
o CSV-245: Post 1.7 release fixes. Thanks to Alex Herbert.
|
o CSV-245: Post 1.7 release fixes. Thanks to Alex Herbert.
|
||||||
o CSV-252: Upgrade test framework to JUnit 5 Jupiter #49, #50. Thanks to Alex Herbert.
|
o CSV-252: Upgrade test framework to JUnit 5 Jupiter #49, #50. Thanks to Alex Herbert.
|
||||||
o CSV-247: A single empty header is allowed when not allowing empty column headers. #47. Thanks to Alex Herbert, Gary Gregory.
|
o CSV-247: A single empty header is allowed when not allowing empty column headers. #47. Thanks to Alex Herbert, Gary Gregory.
|
||||||
|
o CSV-248: CSVRecord is not Serializable. Thanks to Alex Herbert.
|
||||||
o Use test scope for supercsv #48. Thanks to Alex Herbert.
|
o Use test scope for supercsv #48. Thanks to Alex Herbert.
|
||||||
|
|
||||||
CHANGES
|
CHANGES
|
||||||
@ -41,6 +44,7 @@ o Update tests from H2 1.4.199 to 1.4.200. Thanks to Gary Gregory.
|
|||||||
o Update tests from Hamcrest 2.1 to 2.2. Thanks to Gary Gregory.
|
o Update tests from Hamcrest 2.1 to 2.2. Thanks to Gary Gregory.
|
||||||
o Update tests from Mockito 3.1.0 to 3.2.4. Thanks to Gary Gregory.
|
o Update tests from Mockito 3.1.0 to 3.2.4. Thanks to Gary Gregory.
|
||||||
o Fix typos in site and test #53. Thanks to Chen.
|
o Fix typos in site and test #53. Thanks to Chen.
|
||||||
|
o Fix typo performance test #55. Thanks to Chen.
|
||||||
|
|
||||||
|
|
||||||
Historical list of changes: https://commons.apache.org/proper/commons-csv/changes-report.html
|
Historical list of changes: https://commons.apache.org/proper/commons-csv/changes-report.html
|
||||||
|
6
pom.xml
6
pom.xml
@ -32,7 +32,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit.jupiter</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit-jupiter</artifactId>
|
<artifactId>junit-jupiter</artifactId>
|
||||||
<version>5.5.2</version>
|
<version>5.6.0</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -140,7 +140,7 @@
|
|||||||
<commons.release.version>1.8</commons.release.version>
|
<commons.release.version>1.8</commons.release.version>
|
||||||
<commons.release.desc>(Java 8)</commons.release.desc>
|
<commons.release.desc>(Java 8)</commons.release.desc>
|
||||||
<!-- The RC version used in the staging repository URL. -->
|
<!-- The RC version used in the staging repository URL. -->
|
||||||
<commons.rc.version>RC1</commons.rc.version>
|
<commons.rc.version>RC2</commons.rc.version>
|
||||||
<commons.bc.version>1.7</commons.bc.version>
|
<commons.bc.version>1.7</commons.bc.version>
|
||||||
<commons.componentid>csv</commons.componentid>
|
<commons.componentid>csv</commons.componentid>
|
||||||
<commons.module.name>org.apache.commons.csv</commons.module.name>
|
<commons.module.name>org.apache.commons.csv</commons.module.name>
|
||||||
@ -258,6 +258,7 @@
|
|||||||
<!-- The ferc.gov files are included discussion in https://issues.apache.org/jira/browse/LEGAL-175. -->
|
<!-- The ferc.gov files are included discussion in https://issues.apache.org/jira/browse/LEGAL-175. -->
|
||||||
<exclude>src/test/resources/ferc.gov/contract.txt</exclude>
|
<exclude>src/test/resources/ferc.gov/contract.txt</exclude>
|
||||||
<exclude>src/test/resources/ferc.gov/transaction.txt</exclude>
|
<exclude>src/test/resources/ferc.gov/transaction.txt</exclude>
|
||||||
|
<exclude>src/test/resources/**/*.bin</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
@ -376,6 +377,7 @@
|
|||||||
<exclude>src/test/resources/CSVFileParser/testCSV85_ignoreEmpty.txt</exclude>
|
<exclude>src/test/resources/CSVFileParser/testCSV85_ignoreEmpty.txt</exclude>
|
||||||
<exclude>src/test/resources/ferc.gov/contract.txt</exclude>
|
<exclude>src/test/resources/ferc.gov/contract.txt</exclude>
|
||||||
<exclude>src/test/resources/ferc.gov/transaction.txt</exclude>
|
<exclude>src/test/resources/ferc.gov/transaction.txt</exclude>
|
||||||
|
<exclude>src/test/resources/**/*.bin</exclude>
|
||||||
</excludes>
|
</excludes>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
@ -38,7 +38,12 @@
|
|||||||
<title>Apache Commons CSV Release Notes</title>
|
<title>Apache Commons CSV Release Notes</title>
|
||||||
</properties>
|
</properties>
|
||||||
<body>
|
<body>
|
||||||
<release version="1.8" date="2019-01-18" description="Feature and bug fix release (Java 8)">
|
<release version="1.8" date="2019-02-01" description="Feature and bug fix release (Java 8).
|
||||||
|
|
||||||
|
This release fixes serialization compatibility of CSVRecord with versions 1.0 to 1.6.
|
||||||
|
New fields added since 1.7 are not serialized. Support for Serializable is scheduled to be
|
||||||
|
removed in version 2.0.
|
||||||
|
">
|
||||||
<action issue="CSV-255" type="add" dev="ggregory" due-to="0x100">Add CSVRecord.isSet(int) method #52.</action>
|
<action issue="CSV-255" type="add" dev="ggregory" due-to="0x100">Add CSVRecord.isSet(int) method #52.</action>
|
||||||
<action issue="CSV-135" type="fix" dev="sebb" due-to="Mateusz Zakarczemny">Char escape doesn't work properly with quoting.</action>
|
<action issue="CSV-135" type="fix" dev="sebb" due-to="Mateusz Zakarczemny">Char escape doesn't work properly with quoting.</action>
|
||||||
<action issue="CSV-244" type="fix" dev="sebb">Test case failures following CSVFormat#equals() update.</action>
|
<action issue="CSV-244" type="fix" dev="sebb">Test case failures following CSVFormat#equals() update.</action>
|
||||||
@ -48,11 +53,13 @@
|
|||||||
<action issue="CSV-245" type="fix" dev="ggregory" due-to="Alex Herbert">Post 1.7 release fixes.</action>
|
<action issue="CSV-245" type="fix" dev="ggregory" due-to="Alex Herbert">Post 1.7 release fixes.</action>
|
||||||
<action issue="CSV-252" type="fix" dev="ggregory" due-to= "Alex Herbert">Upgrade test framework to JUnit 5 Jupiter #49, #50.</action>
|
<action issue="CSV-252" type="fix" dev="ggregory" due-to= "Alex Herbert">Upgrade test framework to JUnit 5 Jupiter #49, #50.</action>
|
||||||
<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>
|
<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>
|
||||||
|
<action issue="CSV-248" type="fix" dev="ggregory" due-to="Alex Herbert">CSVRecord is not Serializable.</action>
|
||||||
<action type="fix" dev="ggregory" due-to="Alex Herbert">Use test scope for supercsv #48.</action>
|
<action type="fix" dev="ggregory" due-to="Alex Herbert">Use test scope for supercsv #48.</action>
|
||||||
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from H2 1.4.199 to 1.4.200.</action>
|
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from H2 1.4.199 to 1.4.200.</action>
|
||||||
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from Hamcrest 2.1 to 2.2.</action>
|
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from Hamcrest 2.1 to 2.2.</action>
|
||||||
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from Mockito 3.1.0 to 3.2.4.</action>
|
<action type="update" dev="ggregory" due-to="Gary Gregory">Update tests from Mockito 3.1.0 to 3.2.4.</action>
|
||||||
<action type="update" dev="ggregory" due-to="Chen">Fix typos in site and test #53.</action>
|
<action type="update" dev="ggregory" due-to="Chen">Fix typos in site and test #53.</action>
|
||||||
|
<action type="update" dev="ggregory" due-to="Chen">Fix typo performance test #55.</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="1.7" date="2019-06-01" description="Feature and bug fix release (Java 8)">
|
<release version="1.7" date="2019-06-01" description="Feature and bug fix release (Java 8)">
|
||||||
<action issue="CSV-233" type="add" dev="ggregory" due-to="Gary Gregory">Add predefined CSVFormats for printing MongoDB CSV and TSV.</action>
|
<action issue="CSV-233" type="add" dev="ggregory" due-to="Gary Gregory">Add predefined CSVFormats for printing MongoDB CSV and TSV.</action>
|
||||||
|
@ -555,6 +555,11 @@ public final class CSVParser implements Iterable<CSVRecord>, Closeable {
|
|||||||
* <p>
|
* <p>
|
||||||
* The map keys are column names. The map values are 0-based indices.
|
* The map keys are column names. The map values are 0-based indices.
|
||||||
* </p>
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Note: The map can only provide a one-to-one mapping when the format did not
|
||||||
|
* contain null or duplicate column names.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
* @return a copy of the header map.
|
* @return a copy of the header map.
|
||||||
*/
|
*/
|
||||||
public Map<String, Integer> getHeaderMap() {
|
public Map<String, Integer> getHeaderMap() {
|
||||||
@ -577,8 +582,14 @@ public final class CSVParser implements Iterable<CSVRecord>, Closeable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a read-only list of header names that iterates in column order.
|
* Returns a read-only list of header names that iterates in column order.
|
||||||
|
* <p>
|
||||||
|
* Note: The list provides strings that can be used as keys in the header map.
|
||||||
|
* The list will not contain null column names if they were present in the input
|
||||||
|
* format.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @return read-only list of header names that iterates in column order.
|
* @return read-only list of header names that iterates in column order.
|
||||||
|
* @see #getHeaderMap()
|
||||||
* @since 1.7
|
* @since 1.7
|
||||||
*/
|
*/
|
||||||
public List<String> getHeaderNames() {
|
public List<String> getHeaderNames() {
|
||||||
|
@ -24,9 +24,19 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A CSV record parsed from a CSV file.
|
* A CSV record parsed from a CSV file.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Note: Support for {@link Serializable} is scheduled to be removed in version 2.0.
|
||||||
|
* In version 1.8 the mapping between the column header and the column index was
|
||||||
|
* removed from the serialised state. The class maintains serialization compatibility
|
||||||
|
* with versions pre-1.8 for the record values; these must be accessed by index
|
||||||
|
* following deserialization. There will be loss of any functionally linked to the header
|
||||||
|
* mapping when transferring serialised forms pre-1.8 to 1.8 and vice versa.
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
public final class CSVRecord implements Serializable, Iterable<String> {
|
public final class CSVRecord implements Serializable, Iterable<String> {
|
||||||
|
|
||||||
@ -45,8 +55,8 @@ public final class CSVRecord implements Serializable, Iterable<String> {
|
|||||||
/** The values of the record */
|
/** The values of the record */
|
||||||
private final String[] values;
|
private final String[] values;
|
||||||
|
|
||||||
/** The parser that originates this record. */
|
/** The parser that originates this record. This is not serialized. */
|
||||||
private final CSVParser parser;
|
private final transient CSVParser parser;
|
||||||
|
|
||||||
CSVRecord(final CSVParser parser, final String[] values, final String comment, final long recordNumber,
|
CSVRecord(final CSVParser parser, final String[] values, final String comment, final long recordNumber,
|
||||||
final long characterPosition) {
|
final long characterPosition) {
|
||||||
@ -65,7 +75,7 @@ public final class CSVRecord implements Serializable, Iterable<String> {
|
|||||||
* @return the String at the given enum String
|
* @return the String at the given enum String
|
||||||
*/
|
*/
|
||||||
public String get(final Enum<?> e) {
|
public String get(final Enum<?> e) {
|
||||||
return get(e.toString());
|
return get(Objects.toString(e, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,6 +92,14 @@ public final class CSVRecord implements Serializable, Iterable<String> {
|
|||||||
/**
|
/**
|
||||||
* Returns a value by name.
|
* Returns a value by name.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
|
* Note: This requires a field mapping obtained from the original parser.
|
||||||
|
* A check using {@link #isMapped(String)} should be used to determine if a
|
||||||
|
* mapping exists from the provided {@code name} to a field index. In this case an
|
||||||
|
* exception will only be thrown if the record does not contain a field corresponding
|
||||||
|
* to the mapping, that is the record length is not consistent with the mapping size.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
* @param name
|
* @param name
|
||||||
* the name of the column to be retrieved.
|
* the name of the column to be retrieved.
|
||||||
* @return the column value, maybe null depending on {@link CSVFormat#getNullString()}.
|
* @return the column value, maybe null depending on {@link CSVFormat#getNullString()}.
|
||||||
@ -89,7 +107,9 @@ public final class CSVRecord implements Serializable, Iterable<String> {
|
|||||||
* if no header mapping was provided
|
* if no header mapping was provided
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* if {@code name} is not mapped or if the record is inconsistent
|
* if {@code name} is not mapped or if the record is inconsistent
|
||||||
|
* @see #isMapped(String)
|
||||||
* @see #isConsistent()
|
* @see #isConsistent()
|
||||||
|
* @see #getParser()
|
||||||
* @see CSVFormat#withNullString(String)
|
* @see CSVFormat#withNullString(String)
|
||||||
*/
|
*/
|
||||||
public String get(final String name) {
|
public String get(final String name) {
|
||||||
@ -135,12 +155,17 @@ public final class CSVRecord implements Serializable, Iterable<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Integer> getHeaderMapRaw() {
|
private Map<String, Integer> getHeaderMapRaw() {
|
||||||
return parser.getHeaderMapRaw();
|
return parser == null ? null : parser.getHeaderMapRaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the parser.
|
* Returns the parser.
|
||||||
*
|
*
|
||||||
|
* <p>
|
||||||
|
* Note: The parser is not part of the serialized state of the record. A null check
|
||||||
|
* should be used when the record may have originated from a serialized form.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
* @return the parser.
|
* @return the parser.
|
||||||
* @since 1.7
|
* @since 1.7
|
||||||
*/
|
*/
|
||||||
|
@ -42,7 +42,7 @@ public class CSVFileParserTest {
|
|||||||
|
|
||||||
private static final File BASE = new File("src/test/resources/CSVFileParser");
|
private static final File BASE = new File("src/test/resources/CSVFileParser");
|
||||||
|
|
||||||
private String readTestData(BufferedReader reader) throws IOException {
|
private String readTestData(final BufferedReader reader) throws IOException {
|
||||||
String line;
|
String line;
|
||||||
do {
|
do {
|
||||||
line = reader.readLine();
|
line = reader.readLine();
|
||||||
@ -61,7 +61,7 @@ public class CSVFileParserTest {
|
|||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("generateData")
|
@MethodSource("generateData")
|
||||||
public void testCSVFile(File testFile) throws Exception {
|
public void testCSVFile(final File testFile) throws Exception {
|
||||||
try (FileReader fr = new FileReader(testFile); BufferedReader testData = new BufferedReader(fr)) {
|
try (FileReader fr = new FileReader(testFile); BufferedReader testData = new BufferedReader(fr)) {
|
||||||
String line = readTestData(testData);
|
String line = readTestData(testData);
|
||||||
assertNotNull("file must contain config line", line);
|
assertNotNull("file must contain config line", line);
|
||||||
@ -108,7 +108,7 @@ public class CSVFileParserTest {
|
|||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("generateData")
|
@MethodSource("generateData")
|
||||||
public void testCSVUrl(File testFile) throws Exception {
|
public void testCSVUrl(final File testFile) throws Exception {
|
||||||
try (FileReader fr = new FileReader(testFile); BufferedReader testData = new BufferedReader(fr)) {
|
try (FileReader fr = new FileReader(testFile); BufferedReader testData = new BufferedReader(fr)) {
|
||||||
String line = readTestData(testData);
|
String line = readTestData(testData);
|
||||||
assertNotNull("file must contain config line", line);
|
assertNotNull("file must contain config line", line);
|
||||||
|
@ -64,7 +64,7 @@ public class CSVFormatTest {
|
|||||||
return format.withDelimiter(format.getDelimiter());
|
return format.withDelimiter(format.getDelimiter());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertNotEquals(String name, String type, Object left, Object right) {
|
private void assertNotEquals(final String name, final String type, final Object left, final Object right) {
|
||||||
if (left.equals(right) || right.equals(left)) {
|
if (left.equals(right) || right.equals(left)) {
|
||||||
fail("Objects must not compare equal for " + name + "(" + type + ")");
|
fail("Objects must not compare equal for " + name + "(" + type + ")");
|
||||||
}
|
}
|
||||||
@ -153,12 +153,12 @@ public class CSVFormatTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEqualsHash() throws Exception {
|
public void testEqualsHash() throws Exception {
|
||||||
Method[] methods = CSVFormat.class.getDeclaredMethods();
|
final Method[] methods = CSVFormat.class.getDeclaredMethods();
|
||||||
for (Method method : methods) {
|
for (final Method method : methods) {
|
||||||
if (Modifier.isPublic(method.getModifiers())) {
|
if (Modifier.isPublic(method.getModifiers())) {
|
||||||
final String name = method.getName();
|
final String name = method.getName();
|
||||||
if (name.startsWith("with")) {
|
if (name.startsWith("with")) {
|
||||||
for (Class<?> cls : method.getParameterTypes()) {
|
for (final Class<?> cls : method.getParameterTypes()) {
|
||||||
final String type = cls.getCanonicalName();
|
final String type = cls.getCanonicalName();
|
||||||
if ("boolean".equals(type)) {
|
if ("boolean".equals(type)) {
|
||||||
final Object defTrue = method.invoke(CSVFormat.DEFAULT, new Object[] {Boolean.TRUE});
|
final Object defTrue = method.invoke(CSVFormat.DEFAULT, new Object[] {Boolean.TRUE});
|
||||||
@ -550,7 +550,7 @@ public class CSVFormatTest {
|
|||||||
|
|
||||||
final CSVFormat csvFormat = CSVFormat.MYSQL;
|
final CSVFormat csvFormat = CSVFormat.MYSQL;
|
||||||
|
|
||||||
NullPointerException e = assertThrows(NullPointerException.class, () -> csvFormat.format((Object[]) null));
|
final NullPointerException e = assertThrows(NullPointerException.class, () -> csvFormat.format((Object[]) null));
|
||||||
assertEquals(CSVFormat.class.getName(), e.getStackTrace()[0].getClassName());
|
assertEquals(CSVFormat.class.getName(), e.getStackTrace()[0].getClassName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,6 +724,20 @@ public class CSVParserTest {
|
|||||||
assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withHeader().parse(in).iterator());
|
assertThrows(IllegalArgumentException.class, () -> CSVFormat.DEFAULT.withHeader().parse(in).iterator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHeadersWithNullColumnName() throws IOException {
|
||||||
|
final Reader in = new StringReader("header1,null,header3\n1,2,3\n4,5,6");
|
||||||
|
final Iterator<CSVRecord> records = CSVFormat.DEFAULT
|
||||||
|
.withHeader()
|
||||||
|
.withNullString("null")
|
||||||
|
.withAllowMissingColumnNames()
|
||||||
|
.parse(in).iterator();
|
||||||
|
final CSVRecord record = records.next();
|
||||||
|
// Expect the null header to be missing
|
||||||
|
assertEquals(Arrays.asList("header1", "header3"), record.getParser().getHeaderNames());
|
||||||
|
assertEquals(2, record.getParser().getHeaderMap().size());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIgnoreCaseHeaderMapping() throws Exception {
|
public void testIgnoreCaseHeaderMapping() throws Exception {
|
||||||
final Reader reader = new StringReader("1,2,3");
|
final Reader reader = new StringReader("1,2,3");
|
||||||
|
@ -289,15 +289,25 @@ public class CSVPrinterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCSV135() throws IOException {
|
public void testCSV135() throws IOException {
|
||||||
List<String> l = new LinkedList<String>();
|
final List<String> list = new LinkedList<>();
|
||||||
l.add("\"\""); // ""
|
list.add("\"\""); // ""
|
||||||
l.add("\\\\"); // \\
|
list.add("\\\\"); // \\
|
||||||
l.add("\\\"\\"); // \"\
|
list.add("\\\"\\"); // \"\
|
||||||
tryFormat(l, null, null, "\"\",\\\\,\\\"\\"); // "",\\,\"\ (unchanged)
|
//
|
||||||
tryFormat(l, '"', null, "\"\"\"\"\"\",\\\\,\"\\\"\"\\\""); // """""",\\,"\""\" (quoted, and embedded DQ doubled)
|
// "",\\,\"\ (unchanged)
|
||||||
tryFormat(l, null, '\\', "\"\",\\\\\\\\,\\\\\"\\\\"); // "",\\\\,\\"\\ (escapes escaped, not quoted)
|
tryFormat(list, null, null, "\"\",\\\\,\\\"\\");
|
||||||
tryFormat(l, '"', '\\', "\"\\\"\\\"\",\"\\\\\\\\\",\"\\\\\\\"\\\\\""); // "\"\"","\\\\","\\\"\\" (quoted, and embedded DQ & escape escaped)
|
//
|
||||||
tryFormat(l, '"', '"', "\"\"\"\"\"\",\\\\,\"\\\"\"\\\""); // """""",\\,"\""\" (quoted, embedded DQ escaped)
|
// """""",\\,"\""\" (quoted, and embedded DQ doubled)
|
||||||
|
tryFormat(list, '"', null, "\"\"\"\"\"\",\\\\,\"\\\"\"\\\"");
|
||||||
|
//
|
||||||
|
// "",\\\\,\\"\\ (escapes escaped, not quoted)
|
||||||
|
tryFormat(list, null, '\\', "\"\",\\\\\\\\,\\\\\"\\\\");
|
||||||
|
//
|
||||||
|
// "\"\"","\\\\","\\\"\\" (quoted, and embedded DQ & escape escaped)
|
||||||
|
tryFormat(list, '"', '\\', "\"\\\"\\\"\",\"\\\\\\\\\",\"\\\\\\\"\\\\\"");
|
||||||
|
//
|
||||||
|
// """""",\\,"\""\" (quoted, embedded DQ escaped)
|
||||||
|
tryFormat(list, '"', '"', "\"\"\"\"\"\",\\\\,\"\\\"\"\\\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -772,7 +782,8 @@ public class CSVPrinterTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testMySqlNullOutput() throws IOException {
|
public void testMySqlNullOutput() throws IOException {
|
||||||
Object[] s = new String[] { "NULL", null };
|
Object[] s = new String[] { "NULL", null };
|
||||||
CSVFormat format = CSVFormat.MYSQL.withQuote(DQUOTE_CHAR).withNullString("NULL").withQuoteMode(QuoteMode.NON_NUMERIC);
|
CSVFormat format = CSVFormat.MYSQL.withQuote(DQUOTE_CHAR).withNullString("NULL")
|
||||||
|
.withQuoteMode(QuoteMode.NON_NUMERIC);
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
try (final CSVPrinter printer = new CSVPrinter(writer, format)) {
|
try (final CSVPrinter printer = new CSVPrinter(writer, format)) {
|
||||||
printer.printRecord(s);
|
printer.printRecord(s);
|
||||||
@ -1519,10 +1530,10 @@ public class CSVPrinterTest {
|
|||||||
return CSVParser.parse(expected, format).getRecords().get(0).values();
|
return CSVParser.parse(expected, format).getRecords().get(0).values();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void tryFormat(List<String> l, Character quote, Character escape, String expected) throws IOException {
|
private void tryFormat(final List<String> l, final Character quote, final Character escape, final String expected) throws IOException {
|
||||||
CSVFormat format = CSVFormat.DEFAULT.withQuote(quote).withEscape(escape).withRecordSeparator(null);
|
final CSVFormat format = CSVFormat.DEFAULT.withQuote(quote).withEscape(escape).withRecordSeparator(null);
|
||||||
Appendable out = new StringBuilder();
|
final Appendable out = new StringBuilder();
|
||||||
CSVPrinter printer = new CSVPrinter(out, format);
|
final CSVPrinter printer = new CSVPrinter(out, format);
|
||||||
printer.printRecord(l);
|
printer.printRecord(l);
|
||||||
printer.close();
|
printer.close();
|
||||||
assertEquals(expected, out.toString());
|
assertEquals(expected, out.toString());
|
||||||
|
@ -23,10 +23,15 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@ -41,9 +46,9 @@ public class CSVRecordTest {
|
|||||||
UNKNOWN_COLUMN
|
UNKNOWN_COLUMN
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] values;
|
|
||||||
private CSVRecord record, recordWithHeader;
|
|
||||||
private Map<String, Integer> headerMap;
|
private Map<String, Integer> headerMap;
|
||||||
|
private CSVRecord record, recordWithHeader;
|
||||||
|
private String[] values;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@ -89,6 +94,11 @@ public class CSVRecordTest {
|
|||||||
assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get(EnumFixture.UNKNOWN_COLUMN));
|
assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get(EnumFixture.UNKNOWN_COLUMN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetNullEnum() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> recordWithHeader.get((Enum<?>) null));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetUnmappedName() {
|
public void testGetUnmappedName() {
|
||||||
assertThrows(IllegalArgumentException.class, () -> assertNull(recordWithHeader.get("fourth")));
|
assertThrows(IllegalArgumentException.class, () -> assertNull(recordWithHeader.get("fourth")));
|
||||||
@ -133,13 +143,6 @@ public class CSVRecordTest {
|
|||||||
assertFalse(recordWithHeader.isMapped("fourth"));
|
assertFalse(recordWithHeader.isMapped("fourth"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testIsSetString() {
|
|
||||||
assertFalse(record.isSet("first"));
|
|
||||||
assertTrue(recordWithHeader.isSet("first"));
|
|
||||||
assertFalse(recordWithHeader.isSet("fourth"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsSetInt() {
|
public void testIsSetInt() {
|
||||||
assertFalse(record.isSet(-1));
|
assertFalse(record.isSet(-1));
|
||||||
@ -150,6 +153,13 @@ public class CSVRecordTest {
|
|||||||
assertFalse(recordWithHeader.isSet(1000));
|
assertFalse(recordWithHeader.isSet(1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsSetString() {
|
||||||
|
assertFalse(record.isSet("first"));
|
||||||
|
assertTrue(recordWithHeader.isSet("first"));
|
||||||
|
assertFalse(recordWithHeader.isSet("fourth"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIterator() {
|
public void testIterator() {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -185,17 +195,47 @@ public class CSVRecordTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testToMap() {
|
public void testSerialization() throws IOException, ClassNotFoundException {
|
||||||
final Map<String, String> map = this.recordWithHeader.toMap();
|
CSVRecord shortRec;
|
||||||
this.validateMap(map, true);
|
try (final CSVParser parser = CSVParser.parse("A,B\n#my comment\nOne,Two", CSVFormat.DEFAULT.withHeader().withCommentMarker('#'))) {
|
||||||
|
shortRec = parser.iterator().next();
|
||||||
|
}
|
||||||
|
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
try (ObjectOutputStream oos = new ObjectOutputStream(out)) {
|
||||||
|
oos.writeObject(shortRec);
|
||||||
|
}
|
||||||
|
final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
try (ObjectInputStream ois = new ObjectInputStream(in)) {
|
||||||
|
final Object object = ois.readObject();
|
||||||
|
assertTrue(object instanceof CSVRecord);
|
||||||
|
final CSVRecord rec = (CSVRecord) object;
|
||||||
|
assertEquals(1L, rec.getRecordNumber());
|
||||||
|
assertEquals("One", rec.get(0));
|
||||||
|
assertEquals("Two", rec.get(1));
|
||||||
|
assertEquals(2, rec.size());
|
||||||
|
assertEquals(shortRec.getCharacterPosition(), rec.getCharacterPosition());
|
||||||
|
assertEquals("my comment", rec.getComment());
|
||||||
|
// The parser is not serialized
|
||||||
|
assertNull(rec.getParser());
|
||||||
|
// Check all header map functionality is absent
|
||||||
|
assertTrue(rec.isConsistent());
|
||||||
|
assertFalse(rec.isMapped("A"));
|
||||||
|
assertFalse(rec.isSet("A"));
|
||||||
|
assertEquals(0, rec.toMap().size());
|
||||||
|
// This will throw
|
||||||
|
try {
|
||||||
|
rec.get("A");
|
||||||
|
org.junit.jupiter.api.Assertions.fail("Access by name is not expected after deserialisation");
|
||||||
|
} catch (final IllegalStateException expected) {
|
||||||
|
// OK
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testToMapWithShortRecord() throws Exception {
|
public void testToMap() {
|
||||||
try (final CSVParser parser = CSVParser.parse("a,b", CSVFormat.DEFAULT.withHeader("A", "B", "C"))) {
|
final Map<String, String> map = this.recordWithHeader.toMap();
|
||||||
final CSVRecord shortRec = parser.iterator().next();
|
this.validateMap(map, true);
|
||||||
shortRec.toMap();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -208,6 +248,14 @@ public class CSVRecordTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToMapWithShortRecord() throws Exception {
|
||||||
|
try (final CSVParser parser = CSVParser.parse("a,b", CSVFormat.DEFAULT.withHeader("A", "B", "C"))) {
|
||||||
|
final CSVRecord shortRec = parser.iterator().next();
|
||||||
|
shortRec.toMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void validateMap(final Map<String, String> map, final boolean allowsNulls) {
|
private void validateMap(final Map<String, String> map, final boolean allowsNulls) {
|
||||||
assertTrue(map.containsKey("first"));
|
assertTrue(map.containsKey("first"));
|
||||||
assertTrue(map.containsKey("second"));
|
assertTrue(map.containsKey("second"));
|
||||||
|
@ -24,7 +24,6 @@ import java.nio.charset.StandardCharsets;
|
|||||||
|
|
||||||
import org.apache.commons.csv.CSVFormat;
|
import org.apache.commons.csv.CSVFormat;
|
||||||
import org.apache.commons.csv.CSVParser;
|
import org.apache.commons.csv.CSVParser;
|
||||||
import org.apache.commons.csv.CSVRecord;
|
|
||||||
import org.apache.commons.csv.QuoteMode;
|
import org.apache.commons.csv.QuoteMode;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.commons.csv.issues;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import org.apache.commons.csv.CSVRecord;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
|
||||||
|
public class JiraCsv248Test {
|
||||||
|
/**
|
||||||
|
* Test deserialisation of a CSVRecord created using version 1.6.
|
||||||
|
*
|
||||||
|
* <p>This test asserts that serialization from 1.8 onwards is consistent with
|
||||||
|
* previous versions. Serialization was broken in version 1.7.
|
||||||
|
*
|
||||||
|
* @throws IOException Signals that an I/O exception has occurred.
|
||||||
|
* @throws ClassNotFoundException If the CSVRecord cannot be deserialized
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testJiraCsv248() throws IOException, ClassNotFoundException {
|
||||||
|
// Record was originally created using CSV version 1.6 with the following code:
|
||||||
|
//try (final CSVParser parser = CSVParser.parse("A,B\n#my comment\nOne,Two", CSVFormat.DEFAULT.withHeader().withCommentMarker('#'))) {
|
||||||
|
// CSVRecord rec = parser.iterator().next();
|
||||||
|
//}
|
||||||
|
try (InputStream in = getTestInput();
|
||||||
|
ObjectInputStream ois = new ObjectInputStream(in)) {
|
||||||
|
final Object object = ois.readObject();
|
||||||
|
assertTrue(object instanceof CSVRecord);
|
||||||
|
final CSVRecord rec = (CSVRecord) object;
|
||||||
|
assertEquals(1L, rec.getRecordNumber());
|
||||||
|
assertEquals("One", rec.get(0));
|
||||||
|
assertEquals("Two", rec.get(1));
|
||||||
|
assertEquals(2, rec.size());
|
||||||
|
// The comment and whitespace are ignored so this is not 17 but 4
|
||||||
|
assertEquals(4, rec.getCharacterPosition());
|
||||||
|
assertEquals("my comment", rec.getComment());
|
||||||
|
// The parser is not serialized
|
||||||
|
assertNull(rec.getParser());
|
||||||
|
// Check all header map functionality is absent
|
||||||
|
assertTrue(rec.isConsistent());
|
||||||
|
assertFalse(rec.isMapped("A"));
|
||||||
|
assertFalse(rec.isSet("A"));
|
||||||
|
assertEquals(0, rec.toMap().size());
|
||||||
|
// This will throw
|
||||||
|
try {
|
||||||
|
rec.get("A");
|
||||||
|
org.junit.jupiter.api.Assertions.fail("Access by name is not expected after deserialisation");
|
||||||
|
} catch (final IllegalStateException expected) {
|
||||||
|
// OK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InputStream getTestInput() {
|
||||||
|
return ClassLoader.getSystemClassLoader().getResourceAsStream("CSV-248/csvRecord.bin");
|
||||||
|
}
|
||||||
|
}
|
@ -38,7 +38,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
/**
|
/**
|
||||||
* Tests performance.
|
* Tests performance.
|
||||||
*
|
*
|
||||||
* To run this test, use: mvn test -Dtest=PeformanceTest
|
* To run this test, use: mvn test -Dtest=PerformanceTest
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("boxing") // test code
|
@SuppressWarnings("boxing") // test code
|
||||||
public class PerformanceTest {
|
public class PerformanceTest {
|
||||||
@ -112,12 +112,11 @@ public class PerformanceTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadBigFile() throws Exception {
|
public void testReadBigFile() throws Exception {
|
||||||
long bestTime = Long.MAX_VALUE;
|
long bestTime = Long.MAX_VALUE;
|
||||||
|
long count;
|
||||||
for (int i = 0; i < this.max; i++) {
|
for (int i = 0; i < this.max; i++) {
|
||||||
final long startMillis;
|
final long startMillis;
|
||||||
long count;
|
|
||||||
try (final BufferedReader in = this.createBufferedReader()) {
|
try (final BufferedReader in = this.createBufferedReader()) {
|
||||||
startMillis = System.currentTimeMillis();
|
startMillis = System.currentTimeMillis();
|
||||||
count = 0;
|
|
||||||
count = this.readAll(in);
|
count = this.readAll(in);
|
||||||
}
|
}
|
||||||
final long totalMillis = System.currentTimeMillis() - startMillis;
|
final long totalMillis = System.currentTimeMillis() - startMillis;
|
||||||
|
BIN
src/test/resources/CSV-248/csvRecord.bin
Normal file
BIN
src/test/resources/CSV-248/csvRecord.bin
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user