Skip to content

Commit 21efc07

Browse files
committed
Merge branch '2.11' into 2.12
2 parents 876d2f3 + afc2356 commit 21efc07

File tree

5 files changed

+121
-36
lines changed

5 files changed

+121
-36
lines changed

csv/src/main/java/com/fasterxml/jackson/dataformat/csv/impl/CsvEncoder.java

+41-32
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,19 @@
1717
*/
1818
public class CsvEncoder
1919
{
20-
21-
/*
22-
* default set of escaped characters.
23-
*/
20+
// Default set of escaped characters (none)
2421
private static final int [] sOutputEscapes = new int[0];
2522

2623
final protected static char[] HEX_CHARS = CharTypes.copyHexChars();
2724

28-
/* As an optimization we try coalescing short writes into
25+
/**
26+
* As an optimization we try coalescing short writes into
2927
* buffer; but pass longer directly.
3028
*/
3129
final protected static int SHORT_WRITE = 32;
3230

33-
/* Also: only do check for optional quotes for short
31+
/**
32+
* Also: only do check for optional quotes for short
3433
* values; longer ones will always be quoted.
3534
*/
3635
final protected static int MAX_QUOTE_CHECK = 24;
@@ -221,9 +220,9 @@ public CsvEncoder(IOContext ctxt, int csvFeatures, Writer out, CsvSchema schema)
221220
_cfgMaxQuoteCheckChars = MAX_QUOTE_CHECK;
222221

223222
_cfgQuoteCharEscapeChar = _getQuoteCharEscapeChar(
224-
_cfgEscapeQuoteCharWithEscapeChar,
225-
_cfgQuoteCharacter,
226-
_cfgEscapeCharacter
223+
_cfgEscapeQuoteCharWithEscapeChar,
224+
_cfgQuoteCharacter,
225+
_cfgEscapeCharacter
227226
);
228227

229228
_cfgControlCharEscapeChar = _cfgEscapeCharacter > 0 ? (char) _cfgEscapeCharacter : '\\';
@@ -256,31 +255,31 @@ public CsvEncoder(CsvEncoder base, CsvSchema newSchema)
256255
_cfgMinSafeChar = _calcSafeChar();
257256
_columnCount = newSchema.size();
258257
_cfgQuoteCharEscapeChar = _getQuoteCharEscapeChar(
259-
base._cfgEscapeQuoteCharWithEscapeChar,
260-
newSchema.getQuoteChar(),
261-
newSchema.getEscapeChar()
258+
base._cfgEscapeQuoteCharWithEscapeChar,
259+
newSchema.getQuoteChar(),
260+
newSchema.getEscapeChar()
262261
);
263262
_cfgControlCharEscapeChar = _cfgEscapeCharacter > 0 ? (char) _cfgEscapeCharacter : '\\';
264263
}
265264

266265
private final char _getQuoteCharEscapeChar(
267-
final boolean escapeQuoteCharWithEscapeChar,
268-
final int quoteCharacter,
269-
final int escapeCharacter) {
270-
271-
final char quoteEscapeChar;
272-
273-
if (_cfgEscapeQuoteCharWithEscapeChar && _cfgEscapeCharacter > 0) {
274-
quoteEscapeChar = (char) _cfgEscapeCharacter;
275-
}
276-
else if (_cfgQuoteCharacter > 0) {
277-
quoteEscapeChar = (char) _cfgQuoteCharacter;
278-
}
279-
else {
280-
quoteEscapeChar = '\\';
281-
}
282-
283-
return quoteEscapeChar;
266+
final boolean escapeQuoteCharWithEscapeChar,
267+
final int quoteCharacter,
268+
final int escapeCharacter)
269+
{
270+
final char quoteEscapeChar;
271+
272+
if (_cfgEscapeQuoteCharWithEscapeChar && _cfgEscapeCharacter > 0) {
273+
quoteEscapeChar = (char) _cfgEscapeCharacter;
274+
}
275+
else if (_cfgQuoteCharacter > 0) {
276+
quoteEscapeChar = (char) _cfgQuoteCharacter;
277+
}
278+
else {
279+
quoteEscapeChar = '\\';
280+
}
281+
282+
return quoteEscapeChar;
284283
}
285284

286285
private final int _calcSafeChar()
@@ -289,6 +288,8 @@ private final int _calcSafeChar()
289288
int min = Math.max(_cfgColumnSeparator, _cfgQuoteCharacter);
290289
// 06-Nov-2015, tatu: We will NOT apply escape character, because it usually
291290
// has higher ascii value (with backslash); better handle separately.
291+
// 23-Sep-2020, tatu: Should not actually need to consider anything but the
292+
// first character when checking... but leaving rest for now
292293
for (int i = 0; i < _cfgLineSeparatorLength; ++i) {
293294
min = Math.max(min, _cfgLineSeparator[i]);
294295
}
@@ -312,7 +313,7 @@ public CsvEncoder overrideFormatFeatures(int feat) {
312313
return this;
313314
}
314315

315-
public CsvEncoder setOutputEscapes(int [] esc) {
316+
public CsvEncoder setOutputEscapes(int[] esc) {
316317
_outputEscapes = (esc != null) ? esc : sOutputEscapes;
317318
return this;
318319
}
@@ -934,6 +935,7 @@ private final void _writeLongQuotedAndEscaped(String text, char esc) throws IOEx
934935
final int len = text.length();
935936
// NOTE: caller should guarantee quote char is valid (not -1) at this point:
936937
final char q = (char) _cfgQuoteCharacter;
938+
// 23-Sep-2020, tatu: Why was this defined but not used? Commented out in 2.11.3
937939
// final char quoteEscape = _cfgEscapeQuoteCharWithEscapeChar ? esc : q;
938940
for (int i = 0; i < len; ++i) {
939941
if (_outputTail >= _outputEnd) {
@@ -1063,7 +1065,7 @@ protected final boolean _needsQuotingLoose(String value, int esc)
10631065
}
10641066
return false;
10651067
}
1066-
1068+
10671069
/**
10681070
* @since 2.4
10691071
*/
@@ -1073,12 +1075,16 @@ protected boolean _needsQuotingStrict(String value)
10731075

10741076
final int[] escCodes = _outputEscapes;
10751077
final int escLen = escCodes.length;
1078+
// 23-Sep-2020, tatu: [dataformats-text#217] Must also ensure line separator
1079+
// leads to quoting
1080+
final int lfFirst = (_cfgLineSeparatorLength == 0) ? 0 : _cfgLineSeparator[0];
10761081

10771082
for (int i = 0, len = value.length(); i < len; ++i) {
10781083
int c = value.charAt(i);
10791084
if (c < minSafe) {
10801085
if (c == _cfgColumnSeparator || c == _cfgQuoteCharacter
10811086
|| (c < escLen && escCodes[c] != 0)
1087+
|| (c == lfFirst)
10821088
// 31-Dec-2014, tatu: Comment lines start with # so quote if starts with #
10831089
|| (c == '#' && i == 0)) {
10841090
return true;
@@ -1094,15 +1100,18 @@ protected boolean _needsQuotingStrict(String value)
10941100
protected boolean _needsQuotingStrict(String value, int esc)
10951101
{
10961102
final int minSafe = _cfgMinSafeChar;
1097-
10981103
final int[] escCodes = _outputEscapes;
10991104
final int escLen = escCodes.length;
1105+
// 23-Sep-2020, tatu: [dataformats-text#217] Must also ensure line separator
1106+
// leads to quoting
1107+
final int lfFirst = (_cfgLineSeparatorLength == 0) ? 0 : _cfgLineSeparator[0];
11001108

11011109
for (int i = 0, len = value.length(); i < len; ++i) {
11021110
int c = value.charAt(i);
11031111
if (c < minSafe) {
11041112
if (c == _cfgColumnSeparator || c == _cfgQuoteCharacter
11051113
|| (c < escLen && escCodes[c] != 0)
1114+
|| (c == lfFirst)
11061115
// 31-Dec-2014, tatu: Comment lines start with # so quote if starts with #
11071116
|| (c == '#' && i == 0)) {
11081117
return true;

csv/src/test/java/com/fasterxml/jackson/dataformat/csv/deser/TrailingCommaCSVTest.java

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.fasterxml.jackson.dataformat.csv.deser;
22

3-
import java.util.List;
4-
53
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
64
import com.fasterxml.jackson.databind.JsonMappingException;
75
import com.fasterxml.jackson.databind.MappingIterator;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.fasterxml.jackson.dataformat.csv.ser;
2+
3+
import com.fasterxml.jackson.dataformat.csv.*;
4+
5+
public class GeneratorQuotingTest extends ModuleTestBase
6+
{
7+
/*
8+
/**********************************************************************
9+
/* Test methods
10+
/**********************************************************************
11+
*/
12+
13+
private final CsvMapper MAPPER = mapperForCsv();
14+
15+
// [dataformats-text#220]
16+
public void testQuotingOfLinefeedsStd() throws Exception
17+
{
18+
final CsvSchema schema = MAPPER.schemaFor(IdDesc.class)
19+
.withLineSeparator("\n");
20+
String csv;
21+
22+
csv = MAPPER.writer(schema)
23+
.without(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)
24+
.writeValueAsString(new IdDesc("12\n3", "Foo"));
25+
assertEquals("\"12\n3\",Foo\n", csv);
26+
27+
csv = MAPPER.writer(schema.withEscapeChar('\\'))
28+
.without(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)
29+
.writeValueAsString(new IdDesc("12\n3", "Foo"));
30+
assertEquals("\"12\n3\",Foo\n", csv);
31+
32+
csv = MAPPER.writer(schema)
33+
.with(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)
34+
.writeValueAsString(new IdDesc("12\n3", "Foo"));
35+
assertEquals("\"12\n3\",Foo\n", csv);
36+
csv = MAPPER.writer(schema.withEscapeChar('\\'))
37+
.with(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)
38+
.writeValueAsString(new IdDesc("12\n3", "Foo"));
39+
assertEquals("\"12\n3\",Foo\n", csv);
40+
}
41+
42+
public void testQuotingOfLinefeedsCustom() throws Exception
43+
{
44+
// '-' is bigger than max('"', ','):
45+
final CsvSchema schema = MAPPER.schemaFor(IdDesc.class)
46+
.withLineSeparator("-");
47+
final IdDesc value = new IdDesc("12-3", "Foo");
48+
49+
// with loose(default) quoting
50+
String csv = MAPPER.writer(schema)
51+
.without(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)
52+
.writeValueAsString(value);
53+
assertEquals("\"12-3\",Foo-", csv);
54+
55+
// with loose(default) quoting and escape char
56+
csv = MAPPER.writer(schema.withEscapeChar('\\'))
57+
.without(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)
58+
.writeValueAsString(value);
59+
assertEquals("\"12-3\",Foo-", csv);
60+
61+
// with strict/optimal
62+
csv = MAPPER.writer(schema)
63+
.with(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)
64+
.writeValueAsString(value);
65+
assertEquals("\"12-3\",Foo-", csv);
66+
67+
// with strict/optimal and escape char
68+
csv = MAPPER.writer(schema.withEscapeChar('\\'))
69+
.with(CsvGenerator.Feature.STRICT_CHECK_FOR_QUOTING)
70+
.writeValueAsString(value);
71+
assertEquals("\"12-3\",Foo-", csv);
72+
}
73+
}

csv/src/test/java/com/fasterxml/jackson/dataformat/csv/ser/TestGenerator.java

-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import com.fasterxml.jackson.core.JsonGenerator;
99

1010
import com.fasterxml.jackson.databind.JsonMappingException;
11-
import com.fasterxml.jackson.databind.ObjectMapper;
1211
import com.fasterxml.jackson.databind.ObjectWriter;
1312
import com.fasterxml.jackson.databind.node.ObjectNode;
1413
import com.fasterxml.jackson.dataformat.csv.*;

release-notes/VERSION-2.x

+7-1
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,15 @@ Modules:
1919
(requested by pnepywoda@github)
2020
- Add Gradle Module Metadata (https://blog.gradle.org/alignment-with-gradle-module-metadata)
2121

22+
2.11.3 (not yet released)
23+
24+
#217: (csv) Should quote strings with line separator under STRICT_CHECK_FOR_QUOTING
25+
mode
26+
(reported, fix contributed by wkwkhautbois@github)
27+
2228
2.11.2 (02-Aug-2020)
2329

24-
#204: `CsvParser.Feature.ALLOW_TRAILING_COMMA` doesn't work with header columns
30+
#204: (csv) `CsvParser.Feature.ALLOW_TRAILING_COMMA` doesn't work with header columns
2531
(reported by Björn M)
2632
2733
2.11.1 (25-Jun-2020)

0 commit comments

Comments
 (0)