diff --git a/src/main/java/org/apache/commons/csv/CSVFormat.java b/src/main/java/org/apache/commons/csv/CSVFormat.java index 40e4b701..aa2eabfa 100644 --- a/src/main/java/org/apache/commons/csv/CSVFormat.java +++ b/src/main/java/org/apache/commons/csv/CSVFormat.java @@ -126,6 +126,42 @@ public class CSVFormat implements Cloneable, Serializable { this.emptyLinesIgnored = emptyLinesIgnored; } + /** + * Returns true if the given character is a line break character. + * + * @param c the character to check + * + * @return true if c is a line break character + */ + private static boolean isLineBreak(char c) { + return c == '\n' || c == '\r'; + } + + /** + * Verifies the consistency of the parameters and throws an IllegalArgumentException if necessary. + */ + void validate() throws IllegalArgumentException { + if (delimiter == encapsulator) { + throw new IllegalArgumentException("The encapsulator character and the delimiter cannot be the same (\"" + encapsulator + "\")"); + } + + if (delimiter == escape) { + throw new IllegalArgumentException("The escape character and the delimiter cannot be the same (\"" + escape + "\")"); + } + + if (delimiter == commentStart) { + throw new IllegalArgumentException("The comment start character and the delimiter cannot be the same (\"" + commentStart + "\")"); + } + + if (encapsulator != DISABLED && encapsulator == commentStart) { + throw new IllegalArgumentException("The comment start character and the encapsulator cannot be the same (\"" + commentStart + "\")"); + } + + if (escape != DISABLED && escape == commentStart) { + throw new IllegalArgumentException("The comment start and the escape character cannot be the same (\"" + commentStart + "\")"); + } + } + /** * Returns the character delimiting the values (typically ';', ',' or '\t'). * @@ -140,8 +176,13 @@ public class CSVFormat implements Cloneable, Serializable { * * @param delimiter the delimiter character * @return A copy of this format using the specified delimiter character + * @throws IllegalArgumentException thrown if the specified character is a line break */ public CSVFormat withDelimiter(char delimiter) { + if (isLineBreak(delimiter)) { + throw new IllegalArgumentException("The delimiter cannot be a line break"); + } + CSVFormat format = clone(); format.delimiter = delimiter; return format; @@ -161,8 +202,13 @@ public class CSVFormat implements Cloneable, Serializable { * * @param encapsulator the encapsulator character * @return A copy of this format using the specified encapsulator character + * @throws IllegalArgumentException thrown if the specified character is a line break */ public CSVFormat withEncapsulator(char encapsulator) { + if (isLineBreak(encapsulator)) { + throw new IllegalArgumentException("The encapsulator cannot be a line break"); + } + CSVFormat format = clone(); format.encapsulator = encapsulator; return format; @@ -186,8 +232,13 @@ public class CSVFormat implements Cloneable, Serializable { * * @param commentStart the comment start marker * @return A copy of this format using the specified character as the comment start marker + * @throws IllegalArgumentException thrown if the specified character is a line break */ public CSVFormat withCommentStart(char commentStart) { + if (isLineBreak(commentStart)) { + throw new IllegalArgumentException("The comment start character cannot be a line break"); + } + CSVFormat format = clone(); format.commentStart = commentStart; return format; @@ -216,8 +267,13 @@ public class CSVFormat implements Cloneable, Serializable { * * @param escape the escape character * @return A copy of this format using the specified escape character + * @throws IllegalArgumentException thrown if the specified character is a line break */ public CSVFormat withEscape(char escape) { + if (isLineBreak(escape)) { + throw new IllegalArgumentException("The escape character cannot be a line break"); + } + CSVFormat format = clone(); format.escape = escape; return format; diff --git a/src/main/java/org/apache/commons/csv/CSVParser.java b/src/main/java/org/apache/commons/csv/CSVParser.java index 8c641ef0..e980dbe7 100644 --- a/src/main/java/org/apache/commons/csv/CSVParser.java +++ b/src/main/java/org/apache/commons/csv/CSVParser.java @@ -76,6 +76,7 @@ public class CSVParser implements Iterable { * CSV parser using the default {@link CSVFormat}. * * @param input a Reader containing "csv-formatted" input + * @throws IllegalArgumentException thrown if the parameters of the format are inconsistent */ public CSVParser(Reader input) { this(input, CSVFormat.DEFAULT); @@ -86,8 +87,11 @@ public class CSVParser implements Iterable { * * @param input a Reader containing "csv-formatted" input * @param format the CSVFormat used for CSV parsing + * @throws IllegalArgumentException thrown if the parameters of the format are inconsistent */ public CSVParser(Reader input, CSVFormat format) { + format.validate(); + if (format.isUnicodeEscapesInterpreted()) { input = new UnicodeUnescapeReader(input); } @@ -100,6 +104,7 @@ public class CSVParser implements Iterable { * * @param input a String containing "csv-formatted" input * @param format the CSVFormat used for CSV parsing + * @throws IllegalArgumentException thrown if the parameters of the format are inconsistent */ public CSVParser(String input, CSVFormat format) { this(new StringReader(input), format); diff --git a/src/main/java/org/apache/commons/csv/CSVPrinter.java b/src/main/java/org/apache/commons/csv/CSVPrinter.java index 1e427033..c32b4f1c 100644 --- a/src/main/java/org/apache/commons/csv/CSVPrinter.java +++ b/src/main/java/org/apache/commons/csv/CSVPrinter.java @@ -39,11 +39,14 @@ public class CSVPrinter { * is supported. Hybrid formats (encapsulation and escaping with a different character) are not supported. * * @param out stream to which to print. - * @param format describes the CSV variation. + * @param format the CSV format. If null the default format is used ({@link CSVFormat#DEFAULT}) + * @throws IllegalArgumentException thrown if the parameters of the format are inconsistent */ public CSVPrinter(Appendable out, CSVFormat format) { this.out = out; this.format = format == null ? CSVFormat.DEFAULT : format; + + this.format.validate(); } // ====================================================== diff --git a/src/test/java/org/apache/commons/csv/CSVFormatTest.java b/src/test/java/org/apache/commons/csv/CSVFormatTest.java index 86486346..20ce3628 100644 --- a/src/test/java/org/apache/commons/csv/CSVFormatTest.java +++ b/src/test/java/org/apache/commons/csv/CSVFormatTest.java @@ -70,4 +70,78 @@ public class CSVFormatTest extends TestCase { assertEquals("a,b,c", format.format("a", "b", "c")); assertEquals("\"x,y\",z", format.format("x,y", "z")); } + + public void testValidation() { + CSVFormat format = CSVFormat.DEFAULT; + + try { + format.withDelimiter('\n'); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + try { + format.withEscape('\r'); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + try { + format.withEncapsulator('\n'); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + try { + format.withCommentStart('\r'); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + try { + format.withDelimiter('!').withEscape('!').validate(); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + try { + format.withDelimiter('!').withCommentStart('!').validate(); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + try { + format.withEncapsulator('!').withCommentStart('!').validate(); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + format.withEncapsulator(CSVFormat.DISABLED).withCommentStart(CSVFormat.DISABLED).validate(); + + try { + format.withEscape('!').withCommentStart('!').validate(); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + format.withEscape(CSVFormat.DISABLED).withCommentStart(CSVFormat.DISABLED).validate(); + + + try { + format.withEncapsulator('!').withDelimiter('!').validate(); + fail(); + } catch (IllegalArgumentException e) { + // expected + } + + + } }