Skip to content

Commit db11c04

Browse files
committed
[CSV-68] Use the Builder pattern for CSVFormat.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/csv/trunk@1410759 13f79535-47bb-0310-9956-ffa450edef68
1 parent e488916 commit db11c04

3 files changed

Lines changed: 296 additions & 43 deletions

File tree

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

Lines changed: 135 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@
2929
import java.io.Reader;
3030
import java.io.Serializable;
3131
import java.io.StringWriter;
32+
import java.util.Arrays;
3233

3334
/**
3435
* The format specification of a CSV file.
3536
*
3637
* This class is immutable.
37-
*
38+
*
3839
* @version $Id$
3940
*/
4041
public class CSVFormat implements Serializable {
@@ -125,8 +126,8 @@ public class CSVFormat implements Serializable {
125126

126127
/**
127128
* Creates a new CSV format builds.
128-
*
129-
* @param delimiter
129+
*
130+
* @param delimiter
130131
* the char used for value separation, must not be a line break character
131132
* @throws IllegalArgumentException if the delimiter is a line break character
132133
*/
@@ -137,7 +138,7 @@ public static CSVFormatBuilder newBuilder(final char delimiter) {
137138
public static CSVFormatBuilder newBuilder(final CSVFormat format) {
138139
return new CSVFormatBuilder(format);
139140
}
140-
141+
141142
/**
142143
* Standard comma separated format, as for {@link #RFC4180} but allowing blank lines.
143144
* <ul>
@@ -158,7 +159,7 @@ public static CSVFormatBuilder newBuilder() {
158159
* the char used for value separation, must not be a line break character
159160
* @param quoteChar
160161
* the char used as value encapsulation marker
161-
* @param quotePolicy
162+
* @param quotePolicy
162163
* the quote policy
163164
* @param commentStart
164165
* the char used for comment identification
@@ -174,10 +175,12 @@ public static CSVFormatBuilder newBuilder() {
174175
* the header
175176
* @throws IllegalArgumentException if the delimiter is a line break character
176177
*/
177-
private CSVFormat(final char delimiter, final Character quoteChar, final Quote quotePolicy, final Character commentStart, final Character escape, final
178-
boolean ignoreSurroundingSpaces, final boolean ignoreEmptyLines, final String lineSeparator,
179-
final String[] header) {
180-
if (isLineBreak(delimiter)) {
178+
private CSVFormat(final char delimiter, final Character quoteChar, final Quote quotePolicy, final Character commentStart, final Character escape, final
179+
boolean ignoreSurroundingSpaces, final boolean ignoreEmptyLines, final String lineSeparator,
180+
final String[] header)
181+
{
182+
if (isLineBreak(delimiter))
183+
{
181184
throw new IllegalArgumentException("The delimiter cannot be a line break");
182185
}
183186
this.delimiter = delimiter;
@@ -188,7 +191,7 @@ private CSVFormat(final char delimiter, final Character quoteChar, final Quote q
188191
this.ignoreSurroundingSpaces = ignoreSurroundingSpaces;
189192
this.ignoreEmptyLines = ignoreEmptyLines;
190193
this.recordSeparator = lineSeparator;
191-
this.header = header;
194+
this.header = header == null ? null : header.clone();
192195
}
193196

194197
/**
@@ -373,7 +376,109 @@ public String toString() {
373376
public Quote getQuotePolicy() {
374377
return quotePolicy;
375378
}
376-
379+
380+
@Override
381+
public int hashCode()
382+
{
383+
final int prime = 31;
384+
int result = 1;
385+
386+
result = prime * result + delimiter;
387+
result = prime * result + ((quotePolicy == null) ? 0 : quotePolicy.hashCode());
388+
result = prime * result + ((quoteChar == null) ? 0 : quoteChar.hashCode());
389+
result = prime * result + ((commentStart == null) ? 0 : commentStart.hashCode());
390+
result = prime * result + ((escape == null) ? 0 : escape.hashCode());
391+
result = prime * result + (ignoreSurroundingSpaces ? 1231 : 1237);
392+
result = prime * result + (ignoreEmptyLines ? 1231 : 1237);
393+
result = prime * result + ((recordSeparator == null) ? 0 : recordSeparator.hashCode());
394+
result = prime * result + Arrays.hashCode(header);
395+
return result;
396+
}
397+
398+
@Override
399+
public boolean equals(Object obj)
400+
{
401+
if (this == obj)
402+
{
403+
return true;
404+
}
405+
if (obj == null)
406+
{
407+
return false;
408+
}
409+
if (getClass() != obj.getClass())
410+
{
411+
return false;
412+
}
413+
414+
CSVFormat other = (CSVFormat) obj;
415+
if (delimiter != other.delimiter)
416+
{
417+
return false;
418+
}
419+
if (quotePolicy != other.quotePolicy)
420+
{
421+
return false;
422+
}
423+
if (quoteChar == null)
424+
{
425+
if (other.quoteChar != null)
426+
{
427+
return false;
428+
}
429+
}
430+
else if (!quoteChar.equals(other.quoteChar))
431+
{
432+
return false;
433+
}
434+
if (commentStart == null)
435+
{
436+
if (other.commentStart != null)
437+
{
438+
return false;
439+
}
440+
}
441+
else if (!commentStart.equals(other.commentStart))
442+
{
443+
return false;
444+
}
445+
if (escape == null)
446+
{
447+
if (other.escape != null)
448+
{
449+
return false;
450+
}
451+
}
452+
else if (!escape.equals(other.escape))
453+
{
454+
return false;
455+
}
456+
if (!Arrays.equals(header, other.header))
457+
{
458+
return false;
459+
}
460+
if (ignoreSurroundingSpaces != other.ignoreSurroundingSpaces)
461+
{
462+
return false;
463+
}
464+
if (ignoreEmptyLines != other.ignoreEmptyLines)
465+
{
466+
return false;
467+
}
468+
if (recordSeparator == null)
469+
{
470+
if (other.recordSeparator != null)
471+
{
472+
return false;
473+
}
474+
}
475+
else if (!recordSeparator.equals(other.recordSeparator))
476+
{
477+
return false;
478+
}
479+
return true;
480+
}
481+
377482
public static class CSVFormatBuilder {
378483

379484
private char delimiter;
@@ -393,7 +498,7 @@ public static class CSVFormatBuilder {
393498
* the char used for value separation, must not be a line break character
394499
* @param quoteChar
395500
* the char used as value encapsulation marker
396-
* @param quotePolicy
501+
* @param quotePolicy
397502
* the quote policy
398503
* @param commentStart
399504
* the char used for comment identification
@@ -410,8 +515,8 @@ public static class CSVFormatBuilder {
410515
* @throws IllegalArgumentException if the delimiter is a line break character
411516
*/
412517
// package protected for use by test code
413-
CSVFormatBuilder(final char delimiter, final Character quoteChar, final Quote quotePolicy, final Character commentStart, final Character escape, final
414-
boolean ignoreSurroundingSpaces, final boolean ignoreEmptyLines, final String lineSeparator,
518+
CSVFormatBuilder(final char delimiter, final Character quoteChar, final Quote quotePolicy, final Character commentStart, final Character escape, final
519+
boolean ignoreSurroundingSpaces, final boolean ignoreEmptyLines, final String lineSeparator,
415520
final String[] header) {
416521
if (isLineBreak(delimiter)) {
417522
throw new IllegalArgumentException("The delimiter cannot be a line break");
@@ -426,11 +531,11 @@ public static class CSVFormatBuilder {
426531
this.recordSeparator = lineSeparator;
427532
this.header = header;
428533
}
429-
534+
430535
/**
431-
*
536+
*
432537
* Creates a CSVFormatBuilder, using the values of the given CSVFormat.
433-
*
538+
*
434539
* @param format
435540
* The format to use values from
436541
*/
@@ -443,8 +548,8 @@ private CSVFormatBuilder(CSVFormat format) {
443548

444549
/**
445550
* Creates a basic CSVFormatBuilder.
446-
*
447-
* @param delimiter
551+
*
552+
* @param delimiter
448553
* the char used for value separation, must not be a line break character
449554
* @throws IllegalArgumentException if the delimiter is a line break character
450555
*/
@@ -457,35 +562,35 @@ public CSVFormat build() {
457562
return new CSVFormat(delimiter, quoteChar, quotePolicy, commentStart, escape,
458563
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, header);
459564
}
460-
565+
461566
/**
462567
* Verifies the consistency of the parameters and throws an IllegalStateException if necessary.
463-
*
568+
*
464569
* @throws IllegalStateException
465570
*/
466571
private void validate() throws IllegalStateException {
467572
if (quoteChar != null && delimiter == quoteChar.charValue()) {
468573
throw new IllegalStateException("The quoteChar character and the delimiter cannot be the same ('" + quoteChar + "')");
469574
}
470-
575+
471576
if (escape != null && delimiter == escape.charValue()) {
472577
throw new IllegalStateException("The escape character and the delimiter cannot be the same ('" + escape + "')");
473578
}
474-
579+
475580
if (commentStart != null && delimiter == commentStart.charValue()) {
476-
throw new IllegalStateException("The comment start character and the delimiter cannot be the same ('" + commentStart +
581+
throw new IllegalStateException("The comment start character and the delimiter cannot be the same ('" + commentStart +
477582
"')");
478583
}
479-
584+
480585
if (quoteChar != null && quoteChar.equals(commentStart)) {
481-
throw new IllegalStateException("The comment start character and the quoteChar cannot be the same ('" + commentStart +
586+
throw new IllegalStateException("The comment start character and the quoteChar cannot be the same ('" + commentStart +
482587
"')");
483588
}
484-
589+
485590
if (escape != null && escape.equals(commentStart)) {
486591
throw new IllegalStateException("The comment start and the escape character cannot be the same ('" + commentStart + "')");
487592
}
488-
593+
489594
if (escape == null && quotePolicy == Quote.NONE) {
490595
throw new IllegalStateException("No quotes mode set but no escape character is set");
491596
}
@@ -504,7 +609,7 @@ public CSVFormatBuilder withDelimiter(final char delimiter) {
504609
if (isLineBreak(delimiter)) {
505610
throw new IllegalArgumentException("The delimiter cannot be a line break");
506611
}
507-
this.delimiter = delimiter;
612+
this.delimiter = delimiter;
508613
return this;
509614
}
510615

@@ -625,7 +730,7 @@ public CSVFormatBuilder withHeader(final String... header) {
625730
this.header = header;
626731
return this;
627732
}
628-
733+
629734
/**
630735
* Sets the trimming behavior of the format.
631736
*

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

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
import static org.apache.commons.csv.Constants.CR;
2222
import static org.apache.commons.csv.Constants.CRLF;
2323
import static org.apache.commons.csv.Constants.LF;
24-
import static org.junit.Assert.assertArrayEquals;
2524
import static org.junit.Assert.assertEquals;
2625
import static org.junit.Assert.assertFalse;
26+
import static org.junit.Assert.assertNotSame;
2727
import static org.junit.Assert.assertTrue;
2828

2929
import org.apache.commons.csv.CSVFormat.CSVFormatBuilder;
@@ -159,7 +159,7 @@ public void testIgnoreEmptyLines() {
159159
@Test
160160
public void testCopiedFormatIsEqualToOriginal() {
161161
CSVFormat copyOfRCF4180 = CSVFormat.newBuilder(RFC4180).build();
162-
assertEqualFormats(RFC4180, copyOfRCF4180);
162+
assertEquals(RFC4180, copyOfRCF4180);
163163
}
164164

165165
@Test
@@ -168,16 +168,14 @@ public void testCopiedFormatWithChanges() {
168168
assertTrue(newFormat.getDelimiter() != RFC4180.getDelimiter());
169169
}
170170

171-
// FIXME implement equals on CSVFormat to allow use of Assert.assertEquals()
172-
private static void assertEqualFormats(CSVFormat expected, CSVFormat acutal) {
173-
assertEquals(expected.getCommentStart(), acutal.getCommentStart());
174-
assertEquals(expected.getDelimiter(), acutal.getDelimiter());
175-
assertEquals(expected.getEscape(), acutal.getEscape());
176-
assertArrayEquals(expected.getHeader(), acutal.getHeader());
177-
assertEquals(expected.getIgnoreEmptyLines(), acutal.getIgnoreEmptyLines());
178-
assertEquals(expected.getIgnoreSurroundingSpaces(), acutal.getIgnoreSurroundingSpaces());
179-
assertEquals(expected.getQuoteChar(), acutal.getQuoteChar());
180-
assertEquals(expected.getQuotePolicy(), acutal.getQuotePolicy());
181-
assertEquals(expected.getRecordSeparator(), acutal.getRecordSeparator());
171+
@Test
172+
public void testHeaderReferenceCannotEscape() {
173+
String[] header = new String[]{"one", "tow", "three"};
174+
builder.withHeader(header);
175+
176+
CSVFormat firstFormat = builder.build();
177+
CSVFormat secondFormat = builder.build();
178+
assertNotSame(header, firstFormat.getHeader());
179+
assertNotSame(firstFormat, secondFormat.getHeader());
182180
}
183181
}

0 commit comments

Comments
 (0)