2012/11/17 <ggreg...@apache.org> > Author: ggregory > Date: Sat Nov 17 18:00:38 2012 > New Revision: 1410759 > > URL: http://svn.apache.org/viewvc?rev=1410759&view=rev > Log: > [CSV-68] Use the Builder pattern for CSVFormat. > > Modified: > > commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVFormat.java > > commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVFormatBuilderTest.java > > commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVFormatTest.java > > Modified: > commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVFormat.java > URL: > http://svn.apache.org/viewvc/commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVFormat.java?rev=1410759&r1=1410758&r2=1410759&view=diff > > ============================================================================== > --- > commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVFormat.java > (original) > +++ > commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVFormat.java > Sat Nov 17 18:00:38 2012 > @@ -29,12 +29,13 @@ import java.io.IOException; > import java.io.Reader; > import java.io.Serializable; > import java.io.StringWriter; > +import java.util.Arrays; > > /** > * The format specification of a CSV file. > * > * This class is immutable. > - * > + * > * @version $Id$ > */ > public class CSVFormat implements Serializable { > @@ -125,8 +126,8 @@ public class CSVFormat implements Serial > > /** > * Creates a new CSV format builds. > - * > - * @param delimiter > + * > + * @param delimiter > * the char used for value separation, must not be a line > break character > * @throws IllegalArgumentException if the delimiter is a line break > character > */ > @@ -137,7 +138,7 @@ public class CSVFormat implements Serial > public static CSVFormatBuilder newBuilder(final CSVFormat format) { > return new CSVFormatBuilder(format); > } > - > + > /** > * Standard comma separated format, as for {@link #RFC4180} but > allowing blank lines. > * <ul> > @@ -158,7 +159,7 @@ public class CSVFormat implements Serial > * the char used for value separation, must not be a line > break character > * @param quoteChar > * the char used as value encapsulation marker > - * @param quotePolicy > + * @param quotePolicy > * the quote policy > * @param commentStart > * the char used for comment identification > @@ -174,10 +175,12 @@ public class CSVFormat implements Serial > * the header > * @throws IllegalArgumentException if the delimiter is a line break > character > */ > - private CSVFormat(final char delimiter, final Character quoteChar, > final Quote quotePolicy, final Character commentStart, final Character > escape, final > - boolean ignoreSurroundingSpaces, final boolean > ignoreEmptyLines, final String lineSeparator, > - final String[] header) { > - if (isLineBreak(delimiter)) { > + private CSVFormat(final char delimiter, final Character quoteChar, > final Quote quotePolicy, final Character commentStart, final Character > escape, final > + boolean ignoreSurroundingSpaces, final boolean > ignoreEmptyLines, final String lineSeparator, > + final String[] header) > + { > + if (isLineBreak(delimiter)) > + { > throw new IllegalArgumentException("The delimiter cannot be a > line break"); > } > this.delimiter = delimiter; > @@ -188,7 +191,7 @@ public class CSVFormat implements Serial > this.ignoreSurroundingSpaces = ignoreSurroundingSpaces; > this.ignoreEmptyLines = ignoreEmptyLines; > this.recordSeparator = lineSeparator; > - this.header = header; > + this.header = header == null ? null : header.clone(); >
Well, that looks a lot simpler :) Thanks Gary! What else has to be done to finish CSV-68? Regards, Benedikt > } > > /** > @@ -373,7 +376,109 @@ public class CSVFormat implements Serial > public Quote getQuotePolicy() { > return quotePolicy; > } > - > + > + @Override > + public int hashCode() > + { > + final int prime = 31; > + int result = 1; > + > + result = prime * result + delimiter; > + result = prime * result + ((quotePolicy == null) ? 0 : > quotePolicy.hashCode()); > + result = prime * result + ((quoteChar == null) ? 0 : > quoteChar.hashCode()); > + result = prime * result + ((commentStart == null) ? 0 : > commentStart.hashCode()); > + result = prime * result + ((escape == null) ? 0 : > escape.hashCode()); > + result = prime * result + (ignoreSurroundingSpaces ? 1231 : 1237); > + result = prime * result + (ignoreEmptyLines ? 1231 : 1237); > + result = prime * result + ((recordSeparator == null) ? 0 : > recordSeparator.hashCode()); > + result = prime * result + Arrays.hashCode(header); > + return result; > + } > + > + @Override > + public boolean equals(Object obj) > + { > + if (this == obj) > + { > + return true; > + } > + if (obj == null) > + { > + return false; > + } > + if (getClass() != obj.getClass()) > + { > + return false; > + } > + > + CSVFormat other = (CSVFormat) obj; > + if (delimiter != other.delimiter) > + { > + return false; > + } > + if (quotePolicy != other.quotePolicy) > + { > + return false; > + } > + if (quoteChar == null) > + { > + if (other.quoteChar != null) > + { > + return false; > + } > + } > + else if (!quoteChar.equals(other.quoteChar)) > + { > + return false; > + } > + if (commentStart == null) > + { > + if (other.commentStart != null) > + { > + return false; > + } > + } > + else if (!commentStart.equals(other.commentStart)) > + { > + return false; > + } > + if (escape == null) > + { > + if (other.escape != null) > + { > + return false; > + } > + } > + else if (!escape.equals(other.escape)) > + { > + return false; > + } > + if (!Arrays.equals(header, other.header)) > + { > + return false; > + } > + if (ignoreSurroundingSpaces != other.ignoreSurroundingSpaces) > + { > + return false; > + } > + if (ignoreEmptyLines != other.ignoreEmptyLines) > + { > + return false; > + } > + if (recordSeparator == null) > + { > + if (other.recordSeparator != null) > + { > + return false; > + } > + } > + else if (!recordSeparator.equals(other.recordSeparator)) > + { > + return false; > + } > + return true; > + } > + > public static class CSVFormatBuilder { > > private char delimiter; > @@ -393,7 +498,7 @@ public class CSVFormat implements Serial > * the char used for value separation, must not be a > line break character > * @param quoteChar > * the char used as value encapsulation marker > - * @param quotePolicy > + * @param quotePolicy > * the quote policy > * @param commentStart > * the char used for comment identification > @@ -410,8 +515,8 @@ public class CSVFormat implements Serial > * @throws IllegalArgumentException if the delimiter is a line > break character > */ > // package protected for use by test code > - CSVFormatBuilder(final char delimiter, final Character quoteChar, > final Quote quotePolicy, final Character commentStart, final Character > escape, final > - boolean ignoreSurroundingSpaces, final boolean > ignoreEmptyLines, final String lineSeparator, > + CSVFormatBuilder(final char delimiter, final Character quoteChar, > final Quote quotePolicy, final Character commentStart, final Character > escape, final > + boolean ignoreSurroundingSpaces, final boolean > ignoreEmptyLines, final String lineSeparator, > final String[] header) { > if (isLineBreak(delimiter)) { > throw new IllegalArgumentException("The delimiter cannot > be a line break"); > @@ -426,11 +531,11 @@ public class CSVFormat implements Serial > this.recordSeparator = lineSeparator; > this.header = header; > } > - > + > /** > - * > + * > * Creates a CSVFormatBuilder, using the values of the given > CSVFormat. > - * > + * > * @param format > * The format to use values from > */ > @@ -443,8 +548,8 @@ public class CSVFormat implements Serial > > /** > * Creates a basic CSVFormatBuilder. > - * > - * @param delimiter > + * > + * @param delimiter > * the char used for value separation, must not be a > line break character > * @throws IllegalArgumentException if the delimiter is a line > break character > */ > @@ -457,35 +562,35 @@ public class CSVFormat implements Serial > return new CSVFormat(delimiter, quoteChar, quotePolicy, > commentStart, escape, > ignoreSurroundingSpaces, > ignoreEmptyLines, recordSeparator, header); > } > - > + > /** > * Verifies the consistency of the parameters and throws an > IllegalStateException if necessary. > - * > + * > * @throws IllegalStateException > */ > private void validate() throws IllegalStateException { > if (quoteChar != null && delimiter == quoteChar.charValue()) { > throw new IllegalStateException("The quoteChar character > and the delimiter cannot be the same ('" + quoteChar + "')"); > } > - > + > if (escape != null && delimiter == escape.charValue()) { > throw new IllegalStateException("The escape character and > the delimiter cannot be the same ('" + escape + "')"); > } > - > + > if (commentStart != null && delimiter == > commentStart.charValue()) { > - throw new IllegalStateException("The comment start > character and the delimiter cannot be the same ('" + commentStart + > + throw new IllegalStateException("The comment start > character and the delimiter cannot be the same ('" + commentStart + > "')"); > } > - > + > if (quoteChar != null && quoteChar.equals(commentStart)) { > - throw new IllegalStateException("The comment start > character and the quoteChar cannot be the same ('" + commentStart + > + throw new IllegalStateException("The comment start > character and the quoteChar cannot be the same ('" + commentStart + > "')"); > } > - > + > if (escape != null && escape.equals(commentStart)) { > throw new IllegalStateException("The comment start and > the escape character cannot be the same ('" + commentStart + "')"); > } > - > + > if (escape == null && quotePolicy == Quote.NONE) { > throw new IllegalStateException("No quotes mode set but > no escape character is set"); > } > @@ -504,7 +609,7 @@ public class CSVFormat implements Serial > if (isLineBreak(delimiter)) { > throw new IllegalArgumentException("The delimiter cannot > be a line break"); > } > - this.delimiter = delimiter; > + this.delimiter = delimiter; > return this; > } > > @@ -625,7 +730,7 @@ public class CSVFormat implements Serial > this.header = header; > return this; > } > - > + > /** > * Sets the trimming behavior of the format. > * > > Modified: > commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVFormatBuilderTest.java > URL: > http://svn.apache.org/viewvc/commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVFormatBuilderTest.java?rev=1410759&r1=1410758&r2=1410759&view=diff > > ============================================================================== > --- > commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVFormatBuilderTest.java > (original) > +++ > commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVFormatBuilderTest.java > Sat Nov 17 18:00:38 2012 > @@ -21,9 +21,9 @@ import static org.apache.commons.csv.CSV > import static org.apache.commons.csv.Constants.CR; > import static org.apache.commons.csv.Constants.CRLF; > import static org.apache.commons.csv.Constants.LF; > -import static org.junit.Assert.assertArrayEquals; > import static org.junit.Assert.assertEquals; > import static org.junit.Assert.assertFalse; > +import static org.junit.Assert.assertNotSame; > import static org.junit.Assert.assertTrue; > > import org.apache.commons.csv.CSVFormat.CSVFormatBuilder; > @@ -159,7 +159,7 @@ public class CSVFormatBuilderTest { > @Test > public void testCopiedFormatIsEqualToOriginal() { > CSVFormat copyOfRCF4180 = CSVFormat.newBuilder(RFC4180).build(); > - assertEqualFormats(RFC4180, copyOfRCF4180); > + assertEquals(RFC4180, copyOfRCF4180); > } > > @Test > @@ -168,16 +168,14 @@ public class CSVFormatBuilderTest { > assertTrue(newFormat.getDelimiter() != RFC4180.getDelimiter()); > } > > - // FIXME implement equals on CSVFormat to allow use of > Assert.assertEquals() > - private static void assertEqualFormats(CSVFormat expected, CSVFormat > acutal) { > - assertEquals(expected.getCommentStart(), > acutal.getCommentStart()); > - assertEquals(expected.getDelimiter(), acutal.getDelimiter()); > - assertEquals(expected.getEscape(), acutal.getEscape()); > - assertArrayEquals(expected.getHeader(), acutal.getHeader()); > - assertEquals(expected.getIgnoreEmptyLines(), > acutal.getIgnoreEmptyLines()); > - assertEquals(expected.getIgnoreSurroundingSpaces(), > acutal.getIgnoreSurroundingSpaces()); > - assertEquals(expected.getQuoteChar(), acutal.getQuoteChar()); > - assertEquals(expected.getQuotePolicy(), acutal.getQuotePolicy()); > - assertEquals(expected.getRecordSeparator(), > acutal.getRecordSeparator()); > + @Test > + public void testHeaderReferenceCannotEscape() { > + String[] header = new String[]{"one", "tow", "three"}; > + builder.withHeader(header); > + > + CSVFormat firstFormat = builder.build(); > + CSVFormat secondFormat = builder.build(); > + assertNotSame(header, firstFormat.getHeader()); > + assertNotSame(firstFormat, secondFormat.getHeader()); > } > } > > Modified: > commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVFormatTest.java > URL: > http://svn.apache.org/viewvc/commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVFormatTest.java?rev=1410759&r1=1410758&r2=1410759&view=diff > > ============================================================================== > --- > commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVFormatTest.java > (original) > +++ > commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVFormatTest.java > Sat Nov 17 18:00:38 2012 > @@ -18,6 +18,7 @@ > package org.apache.commons.csv; > > import static org.junit.Assert.assertEquals; > +import static org.junit.Assert.assertFalse; > import static org.junit.Assert.assertNotNull; > > import java.io.ByteArrayInputStream; > @@ -65,4 +66,153 @@ public class CSVFormatTest { > assertEquals("trim", > CSVFormat.DEFAULT.getIgnoreSurroundingSpaces(), > format.getIgnoreSurroundingSpaces()); > assertEquals("empty lines", > CSVFormat.DEFAULT.getIgnoreEmptyLines(), format.getIgnoreEmptyLines()); > } > + > + @Test > + public void testEquals() { > + CSVFormat right = CSVFormat.DEFAULT; > + CSVFormat left = CSVFormat.newBuilder().build(); > + > + assertFalse(right.equals(null)); > + assertFalse(right.equals("A String Instance")); > + > + assertEquals(right, right); > + assertEquals(right, left); > + assertEquals(left, right); > + > + assertEquals(right.hashCode(), right.hashCode()); > + assertEquals(right.hashCode(), left.hashCode()); > + } > + > + @Test > + public void testEqualsDelimiter() { > + CSVFormat right = CSVFormat.newBuilder('!').build(); > + CSVFormat left = CSVFormat.newBuilder('?').build(); > + > + assertNotEquals(right, left); > + } > + > + @Test > + public void testEqualsQuoteChar() { > + CSVFormat right = > CSVFormat.newBuilder('\'').withQuoteChar('"').build(); > + CSVFormat left = > CSVFormat.newBuilder(right).withQuoteChar('!').build(); > + > + assertNotEquals(right, left); > + } > + > + @Test > + public void testEqualsQuotePolicy() { > + CSVFormat right = CSVFormat.newBuilder('\'') > + .withQuoteChar('"') > + .withQuotePolicy(Quote.ALL) > + .build(); > + CSVFormat left = CSVFormat.newBuilder(right) > + .withQuotePolicy(Quote.MINIMAL) > + .build(); > + > + assertNotEquals(right, left); > + } > + > + @Test > + public void testEqualsCommentStart() { > + CSVFormat right = CSVFormat.newBuilder('\'') > + .withQuoteChar('"') > + .withQuotePolicy(Quote.ALL) > + .withCommentStart('#') > + .build(); > + CSVFormat left = CSVFormat.newBuilder(right) > + .withCommentStart('!') > + .build(); > + > + assertNotEquals(right, left); > + } > + > + @Test > + public void testEqualsEscape() { > + CSVFormat right = CSVFormat.newBuilder('\'') > + .withQuoteChar('"') > + .withQuotePolicy(Quote.ALL) > + .withCommentStart('#') > + .withEscape('+') > + .build(); > + CSVFormat left = CSVFormat.newBuilder(right) > + .withEscape('!') > + .build(); > + > + assertNotEquals(right, left); > + } > + > + @Test > + public void testEqualsIgnoreSurroundingSpaces() { > + CSVFormat right = CSVFormat.newBuilder('\'') > + .withQuoteChar('"') > + .withQuotePolicy(Quote.ALL) > + .withCommentStart('#') > + .withEscape('+') > + .withIgnoreSurroundingSpaces(true) > + .build(); > + CSVFormat left = CSVFormat.newBuilder(right) > + .withIgnoreSurroundingSpaces(false) > + .build(); > + > + assertNotEquals(right, left); > + } > + > + @Test > + public void testEqualsIgnoreEmptyLines() { > + CSVFormat right = CSVFormat.newBuilder('\'') > + .withQuoteChar('"') > + .withQuotePolicy(Quote.ALL) > + .withCommentStart('#') > + .withEscape('+') > + .withIgnoreSurroundingSpaces(true) > + .withIgnoreEmptyLines(true) > + .build(); > + CSVFormat left = CSVFormat.newBuilder(right) > + .withIgnoreEmptyLines(false) > + .build(); > + > + assertNotEquals(right, left); > + } > + > + @Test > + public void testEqualsRecordSeparator() { > + CSVFormat right = CSVFormat.newBuilder('\'') > + .withQuoteChar('"') > + .withQuotePolicy(Quote.ALL) > + .withCommentStart('#') > + .withEscape('+') > + .withIgnoreSurroundingSpaces(true) > + .withIgnoreEmptyLines(true) > + .withRecordSeparator('*') > + .build(); > + CSVFormat left = CSVFormat.newBuilder(right) > + .withRecordSeparator('!') > + .build(); > + > + assertNotEquals(right, left); > + } > + > + @Test > + public void testEqualsHeader() { > + CSVFormat right = CSVFormat.newBuilder('\'') > + .withQuoteChar('"') > + .withQuotePolicy(Quote.ALL) > + .withCommentStart('#') > + .withEscape('+') > + .withIgnoreSurroundingSpaces(true) > + .withIgnoreEmptyLines(true) > + .withRecordSeparator('*') > + .withHeader("One", "Two", "Three") > + .build(); > + CSVFormat left = CSVFormat.newBuilder(right) > + .withHeader("Three", "Two", "One") > + .build(); > + > + assertNotEquals(right, left); > + } > + > + private static void assertNotEquals(Object right, Object left) { > + assertFalse(right.equals(left)); > + assertFalse(left.equals(right)); > + } > } > > >