Author: ggregory
Date: Wed Sep 10 12:48:02 2014
New Revision: 1623984

URL: http://svn.apache.org/r1623984
Log:
[CSV-130] CSVFormat#withHeader doesn't work well with #printComment, add 
withHeaderComments(String...)

Modified:
    commons/proper/csv/trunk/src/changes/changes.xml
    commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVFormat.java
    
commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVPrinter.java
    
commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVPrinterTest.java

Modified: commons/proper/csv/trunk/src/changes/changes.xml
URL: 
http://svn.apache.org/viewvc/commons/proper/csv/trunk/src/changes/changes.xml?rev=1623984&r1=1623983&r2=1623984&view=diff
==============================================================================
--- commons/proper/csv/trunk/src/changes/changes.xml (original)
+++ commons/proper/csv/trunk/src/changes/changes.xml Wed Sep 10 12:48:02 2014
@@ -39,6 +39,7 @@
   </properties>
   <body>
     <release version="1.1" date="2014-mm-dd" description="Feature and bug fix 
release">
+      <action issue="CSV-130" type="fix" dev="ggregory" due-to="Sergei 
Lebedev">CSVFormat#withHeader doesn't work well with #printComment, add 
withHeaderComments(String...)</action>
       <action issue="CSV-128" type="fix" dev="ggregory">CSVFormat.EXCEL should 
ignore empty header names</action>
       <action issue="CSV-129" type="add" dev="ggregory">Add CSVFormat#with 
0-arg methods matching boolean arg methods</action>
       <action issue="CSV-132" type="fix" dev="ggregory" due-to="Sascha 
Szott">Incorrect Javadoc referencing org.apache.commons.csv.CSVFormat 
withQuote()</action>

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=1623984&r1=1623983&r2=1623984&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 
Wed Sep 10 12:48:02 2014
@@ -157,6 +157,7 @@ public final class CSVFormat implements 
     private final String recordSeparator; // for outputs
     private final String nullString; // the string to be used for null values
     private final String[] header; // array of header column names
+    private final String[] headerComments; // array of header comment lines
     private final boolean skipHeaderRecord;
 
     /**
@@ -173,7 +174,7 @@ public final class CSVFormat implements 
      * </ul>
      */
     public static final CSVFormat DEFAULT = new CSVFormat(COMMA, 
DOUBLE_QUOTE_CHAR, null, null, null,
-                                                            false, true, CRLF, 
null, null, false, false);
+                                                            false, true, CRLF, 
null, null, null, false, false);
 
     /**
      * Comma separated format as defined by <a 
href="http://tools.ietf.org/html/rfc4180";>RFC 4180</a>.
@@ -307,7 +308,7 @@ public final class CSVFormat implements 
      * @see #TDF
      */
     public static CSVFormat newFormat(final char delimiter) {
-        return new CSVFormat(delimiter, null, null, null, null, false, false, 
null, null, null, false, false);
+        return new CSVFormat(delimiter, null, null, null, null, false, false, 
null, null, null, null, false, false);
     }
 
     /**
@@ -331,6 +332,7 @@ public final class CSVFormat implements 
      *            the line separator to use for output
      * @param nullString
      *            the line separator to use for output
+     * @param toHeaderComments TODO
      * @param header
      *            the header
      * @param skipHeaderRecord TODO
@@ -341,8 +343,8 @@ public final class CSVFormat implements 
             final QuoteMode quoteMode, final Character commentStart,
             final Character escape, final boolean ignoreSurroundingSpaces,
             final boolean ignoreEmptyLines, final String recordSeparator,
-            final String nullString, final String[] header, final boolean 
skipHeaderRecord,
-            final boolean allowMissingColumnNames) {
+            final String nullString, final Object[] headerComments, final 
String[] header,
+            final boolean skipHeaderRecord, final boolean 
allowMissingColumnNames) {
         if (isLineBreak(delimiter)) {
             throw new IllegalArgumentException("The delimiter cannot be a line 
break");
         }
@@ -356,6 +358,7 @@ public final class CSVFormat implements 
         this.ignoreEmptyLines = ignoreEmptyLines;
         this.recordSeparator = recordSeparator;
         this.nullString = nullString;
+        this.headerComments = toStringArray(headerComments);
         if (header == null) {
             this.header = null;
         } else {
@@ -372,6 +375,18 @@ public final class CSVFormat implements 
         validate();
     }
 
+    private String[] toStringArray(Object[] values) {
+        if (values == null) {
+            return null;
+        }
+        String[] strings = new String[values.length];
+        for (int i = 0; i < values.length; i++) {
+            Object value = values[i];
+            strings[i] = value == null ? null : value.toString();
+        }
+        return strings;
+    }
+
     @Override
     public boolean equals(final Object obj) {
         if (this == obj) {
@@ -496,6 +511,15 @@ public final class CSVFormat implements 
     }
 
     /**
+     * Returns a copy of the header comment array.
+     *
+     * @return a copy of the header comment array; {@code null} if disabled.
+     */
+    public String[] getHeaderComments() {
+        return headerComments != null ? headerComments.clone() : null;
+    }
+
+    /**
      * Specifies whether missing column names are allowed when parsing the 
header line.
      *
      * @return {@code true} if missing column names are allowed when parsing 
the header line, {@code false} to throw an
@@ -701,6 +725,10 @@ public final class CSVFormat implements 
             sb.append(" SurroundingSpaces:ignored");
         }
         sb.append(" SkipHeaderRecord:").append(skipHeaderRecord);
+        if (headerComments != null) {
+            sb.append(' ');
+            
sb.append("HeaderComments:").append(Arrays.toString(headerComments));
+        }
         if (header != null) {
             sb.append(' ');
             sb.append("Header:").append(Arrays.toString(header));
@@ -775,8 +803,8 @@ public final class CSVFormat implements 
             throw new IllegalArgumentException("The comment start marker 
character cannot be a line break");
         }
         return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -793,8 +821,8 @@ public final class CSVFormat implements 
             throw new IllegalArgumentException("The delimiter cannot be a line 
break");
         }
         return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -824,8 +852,8 @@ public final class CSVFormat implements 
             throw new IllegalArgumentException("The escape character cannot be 
a line break");
         }
         return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escape,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -847,8 +875,27 @@ public final class CSVFormat implements 
      */
     public CSVFormat withHeader(final String... header) {
         return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
+    }
+
+    /**
+     * Sets the header comments of the format. The comments will be printed 
first, before the headers.
+     *
+     * <pre>
+     * CSVFormat format = aformat.withHeaderComments("Generated by Apache 
Commons CSV 1.1.", new Date());</pre>
+     *
+     * @param header
+     *            the header, {@code null} if disabled, empty if parsed 
automatically, user specified otherwise.
+     *
+     * @return A new CSVFormat that is equal to this but with the specified 
header
+     * @see #withSkipHeaderRecord(boolean)
+     * @since 1.1
+     */
+    public CSVFormat withHeaderComments(final Object... headerComments) {
+        return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escapeCharacter,
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, headerComments, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -872,8 +919,8 @@ public final class CSVFormat implements 
      */
     public CSVFormat withAllowMissingColumnNames(final boolean 
allowMissingColumnNames) {
         return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -897,8 +944,8 @@ public final class CSVFormat implements 
      */
     public CSVFormat withIgnoreEmptyLines(final boolean ignoreEmptyLines) {
         return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -922,8 +969,8 @@ public final class CSVFormat implements 
      */
     public CSVFormat withIgnoreSurroundingSpaces(final boolean 
ignoreSurroundingSpaces) {
         return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -943,8 +990,8 @@ public final class CSVFormat implements 
      */
     public CSVFormat withNullString(final String nullString) {
         return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -974,8 +1021,8 @@ public final class CSVFormat implements 
             throw new IllegalArgumentException("The quoteChar cannot be a line 
break");
         }
         return new CSVFormat(delimiter, quoteChar, quoteMode, commentMarker, 
escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -988,8 +1035,8 @@ public final class CSVFormat implements 
      */
     public CSVFormat withQuoteMode(final QuoteMode quoteModePolicy) {
         return new CSVFormat(delimiter, quoteCharacter, quoteModePolicy, 
commentMarker, escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -1022,8 +1069,8 @@ public final class CSVFormat implements 
      */
     public CSVFormat withRecordSeparator(final String recordSeparator) {
         return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 
     /**
@@ -1052,7 +1099,7 @@ public final class CSVFormat implements 
      */
     public CSVFormat withSkipHeaderRecord(final boolean skipHeaderRecord) {
         return new CSVFormat(delimiter, quoteCharacter, quoteMode, 
commentMarker, escapeCharacter,
-                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, header, skipHeaderRecord,
-                allowMissingColumnNames);
+                ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, 
nullString, null, header,
+                skipHeaderRecord, allowMissingColumnNames);
     }
 }

Modified: 
commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVPrinter.java
URL: 
http://svn.apache.org/viewvc/commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVPrinter.java?rev=1623984&r1=1623983&r2=1623984&view=diff
==============================================================================
--- 
commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVPrinter.java 
(original)
+++ 
commons/proper/csv/trunk/src/main/java/org/apache/commons/csv/CSVPrinter.java 
Wed Sep 10 12:48:02 2014
@@ -50,13 +50,13 @@ public final class CSVPrinter implements
      * </p>
      *
      * @param out
-     *        stream to which to print. Must not be null.
+     *            stream to which to print. Must not be null.
      * @param format
-     *        the CSV format. Must not be null.
+     *            the CSV format. Must not be null.
      * @throws IOException
-     *         thrown if the optional header cannot be printed.
+     *             thrown if the optional header cannot be printed.
      * @throws IllegalArgumentException
-     *         thrown if the parameters of the format are inconsistent or if 
either out or format are null.
+     *             thrown if the parameters of the format are inconsistent or 
if either out or format are null.
      */
     public CSVPrinter(final Appendable out, final CSVFormat format) throws 
IOException {
         Assertions.notNull(out, "out");
@@ -66,6 +66,13 @@ public final class CSVPrinter implements
         this.format = format;
         // TODO: Is it a good idea to do this here instead of on the first 
call to a print method?
         // It seems a pain to have to track whether the header has already 
been printed or not.
+        if (format.getHeaderComments() != null) {
+            for (String line : format.getHeaderComments()) {
+                if (line != null) {
+                    this.printComment(line);
+                }
+            }
+        }
         if (format.getHeader() != null) {
             this.printRecord((Object[]) format.getHeader());
         }
@@ -113,8 +120,8 @@ public final class CSVPrinter implements
         this.print(value, strValue, 0, strValue.length());
     }
 
-    private void print(final Object object, final CharSequence value,
-            final int offset, final int len) throws IOException {
+    private void print(final Object object, final CharSequence value, final 
int offset, final int len)
+            throws IOException {
         if (!newRecord) {
             out.append(format.getDelimiter());
         }
@@ -172,8 +179,8 @@ public final class CSVPrinter implements
      * Note: must only be called if quoting is enabled, otherwise will 
generate NPE
      */
     // the original object is needed so can check for Number
-    private void printAndQuote(final Object object, final CharSequence value,
-            final int offset, final int len) throws IOException {
+    private void printAndQuote(final Object object, final CharSequence value, 
final int offset, final int len)
+            throws IOException {
         boolean quote = false;
         int start = offset;
         int pos = offset;
@@ -381,11 +388,16 @@ public final class CSVPrinter implements
     /**
      * Prints all the objects in the given collection handling nested 
collections/arrays as records.
      *
-     * <p>If the given collection only contains simple objects, this method 
will print a single record like
+     * <p>
+     * If the given collection only contains simple objects, this method will 
print a single record like
      * {@link #printRecord(Iterable)}. If the given collections contains 
nested collections/arrays those nested elements
-     * will each be printed as records using {@link 
#printRecord(Object...)}.</p>
+     * will each be printed as records using {@link #printRecord(Object...)}.
+     * </p>
      *
-     * <p>Given the following data structure:</p>
+     * <p>
+     * Given the following data structure:
+     * </p>
+     * 
      * <pre>
      * <code>
      * List&lt;String[]&gt; data = ...
@@ -395,7 +407,10 @@ public final class CSVPrinter implements
      * </code>
      * </pre>
      *
-     * <p>Calling this method will print:</p>
+     * <p>
+     * Calling this method will print:
+     * </p>
+     * 
      * <pre>
      * <code>
      * A, B, C
@@ -424,11 +439,16 @@ public final class CSVPrinter implements
     /**
      * Prints all the objects in the given array handling nested 
collections/arrays as records.
      *
-     * <p>If the given array only contains simple objects, this method will 
print a single record like
+     * <p>
+     * If the given array only contains simple objects, this method will print 
a single record like
      * {@link #printRecord(Object...)}. If the given collections contains 
nested collections/arrays those nested
-     * elements will each be printed as records using {@link 
#printRecord(Object...)}.</p>
+     * elements will each be printed as records using {@link 
#printRecord(Object...)}.
+     * </p>
      *
-     * <p>Given the following data structure:</p>
+     * <p>
+     * Given the following data structure:
+     * </p>
+     * 
      * <pre>
      * <code>
      * String[][] data = new String[3][]
@@ -438,7 +458,10 @@ public final class CSVPrinter implements
      * </code>
      * </pre>
      *
-     * <p>Calling this method will print:</p>
+     * <p>
+     * Calling this method will print:
+     * </p>
+     * 
      * <pre>
      * <code>
      * A, B, C
@@ -467,11 +490,12 @@ public final class CSVPrinter implements
     /**
      * Prints all the objects in the given JDBC result set.
      *
-     * @param resultSet result set
-     *            the values to print.
+     * @param resultSet
+     *            result set the values to print.
      * @throws IOException
      *             If an I/O error occurs
-     * @throws SQLException if a database access error occurs
+     * @throws SQLException
+     *             if a database access error occurs
      */
     public void printRecords(final ResultSet resultSet) throws SQLException, 
IOException {
         final int columnCount = resultSet.getMetaData().getColumnCount();

Modified: 
commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVPrinterTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVPrinterTest.java?rev=1623984&r1=1623983&r2=1623984&view=diff
==============================================================================
--- 
commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVPrinterTest.java
 (original)
+++ 
commons/proper/csv/trunk/src/test/java/org/apache/commons/csv/CSVPrinterTest.java
 Wed Sep 10 12:48:02 2014
@@ -29,6 +29,7 @@ import java.sql.DriverManager;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
@@ -497,6 +498,37 @@ public class CSVPrinterTest {
     }
 
     @Test
+    public void testHeaderCommentExcel() throws IOException {
+        final StringWriter sw = new StringWriter();
+        Date now = new Date();
+        CSVFormat format = CSVFormat.EXCEL;
+        final CSVPrinter csvPrinter = printWithHeaderComments(sw, now, format);
+        assertEquals("# Generated by Apache Commons CSV 1.1\r\n# " + now + 
"\r\nCol1,Col2\r\nA,B\r\nC,D\r\n", sw.toString());
+        csvPrinter.close();
+    }
+
+    @Test
+    public void testHeaderCommentTdf() throws IOException {
+        final StringWriter sw = new StringWriter();
+        Date now = new Date();
+        CSVFormat format = CSVFormat.TDF;
+        final CSVPrinter csvPrinter = printWithHeaderComments(sw, now, format);
+        assertEquals("# Generated by Apache Commons CSV 1.1\r\n# " + now + 
"\r\nCol1\tCol2\r\nA\tB\r\nC\tD\r\n", sw.toString());
+        csvPrinter.close();
+    }
+
+    private CSVPrinter printWithHeaderComments(final StringWriter sw, Date 
now, CSVFormat format)
+            throws IOException {
+        format = format.withCommentMarker('#').withHeader("Col1", "Col2");
+        format = format.withHeaderComments("Generated by Apache Commons CSV 
1.1", now);
+        final CSVPrinter csvPrinter = format.print(sw);
+        csvPrinter.printRecord("A", "B");
+        csvPrinter.printRecord("C", "D");
+        csvPrinter.close();
+        return csvPrinter;
+    }
+
+    @Test
     public void testEOLPlain() throws IOException {
         final StringWriter sw = new StringWriter();
         final CSVPrinter printer = new CSVPrinter(sw, 
CSVFormat.DEFAULT.withQuote(null));


Reply via email to