Skip to content

Commit

Permalink
Fix #438: prevent quoting of BigInteger/BigDecimal when not expected (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Oct 19, 2023
1 parent 56686c8 commit f8bd56b
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ public enum Feature
* actually need this.
* Note that this feature has precedence over {@link #STRICT_CHECK_FOR_QUOTING}, when
* both would be applicable.
* Note that this setting does NOT affect quoting of typed values like {@code Number}s
* or {@code Boolean}s.
*
* @since 2.5
*/
Expand Down Expand Up @@ -861,7 +863,7 @@ public void writeNumber(BigInteger v) throws IOException
if (!_arraySeparator.isEmpty()) {
_addToArray(String.valueOf(v));
} else {
_writer.write(_columnIndex(), v.toString());
_writer.write(_columnIndex(), v);

}
}
Expand Down Expand Up @@ -902,12 +904,11 @@ public void writeNumber(BigDecimal v) throws IOException
}
_verifyValueWrite("write number");
if (!_skipValue) {
String str = isEnabled(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN)
? v.toPlainString() : v.toString();
boolean plain = isEnabled(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
if (!_arraySeparator.isEmpty()) {
_addToArray(String.valueOf(v));
_addToArray(plain ? v.toPlainString() : v.toString());
} else {
_writer.write(_columnIndex(), str);
_writer.write(_columnIndex(), v, plain);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ protected BufferedValue() { }
public static BufferedValue bufferedRaw(String v) { return new RawValue(v); }
public static BufferedValue buffered(int v) { return new IntValue(v); }
public static BufferedValue buffered(long v) { return new LongValue(v); }
public static BufferedValue buffered(float v) { return new FloatValue(v); }
public static BufferedValue buffered(double v) { return new DoubleValue(v); }
public static BufferedValue bufferedNumber(String numStr) { return new BigNumberValue(numStr); }
public static BufferedValue buffered(boolean v) {
return v ? BooleanValue.TRUE : BooleanValue.FALSE;
}
Expand Down Expand Up @@ -76,6 +78,19 @@ public void write(CsvEncoder w) throws IOException {
}
}

// @since 2.16
protected final static class FloatValue extends BufferedValue
{
private final float _value;

public FloatValue(float v) { _value = v; }

@Override
public void write(CsvEncoder w) throws IOException {
w.appendValue(_value);
}
}

protected final static class DoubleValue extends BufferedValue
{
private final double _value;
Expand All @@ -88,6 +103,18 @@ public void write(CsvEncoder w) throws IOException {
}
}

protected final static class BigNumberValue extends BufferedValue
{
private final String _value;

public BigNumberValue(String v) { _value = v; }

@Override
public void write(CsvEncoder w) throws IOException {
w.appendNumberValue(_value);
}
}

protected final static class BooleanValue extends BufferedValue
{
public final static BooleanValue FALSE = new BooleanValue(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import java.io.IOException;
import java.io.Writer;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;

/**
Expand Down Expand Up @@ -438,6 +440,19 @@ public final void write(int columnIndex, long value) throws IOException
_buffer(columnIndex, BufferedValue.buffered(value));
}

// @since 2.16
public final void write(int columnIndex, BigInteger value) throws IOException
{
// easy case: all in order
final String numStr = value.toString();
if (columnIndex == _nextColumnToWrite) {
appendNumberValue(numStr);
++_nextColumnToWrite;
return;
}
_buffer(columnIndex, BufferedValue.bufferedNumber(numStr));
}

public final void write(int columnIndex, float value) throws IOException
{
// easy case: all in order
Expand All @@ -460,6 +475,20 @@ public final void write(int columnIndex, double value) throws IOException
_buffer(columnIndex, BufferedValue.buffered(value));
}

// @since 2.16
public final void write(int columnIndex, BigDecimal value, boolean plain) throws IOException
{
final String numStr = plain ? value.toPlainString() : value.toString();

// easy case: all in order
if (columnIndex == _nextColumnToWrite) {
appendNumberValue(numStr);
++_nextColumnToWrite;
return;
}
_buffer(columnIndex, BufferedValue.bufferedNumber(numStr));
}

public final void write(int columnIndex, boolean value) throws IOException
{
// easy case: all in order
Expand Down Expand Up @@ -599,7 +628,7 @@ protected void appendValue(long value) throws IOException
}
_outputTail = NumberOutput.outputLong(value, _outputBuffer, _outputTail);
}

protected void appendValue(float value) throws IOException
{
String str = NumberOutput.toString(value, _cfgUseFastDoubleWriter);
Expand All @@ -626,6 +655,19 @@ protected void appendValue(double value) throws IOException
writeRaw(str);
}

// @since 2.16: pre-encoded BigInteger/BigDecimal value
protected void appendNumberValue(String numValue) throws IOException
{
// Same as "appendRawValue()", except may want quoting
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
if (_nextColumnToWrite > 0) {
appendColumnSeparator();
}
writeRaw(numValue);
}

protected void appendValue(boolean value) throws IOException {
_append(value ? TRUE_CHARS : FALSE_CHARS);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.File;
import java.io.StringWriter;
import java.math.BigDecimal;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;

Expand Down Expand Up @@ -37,6 +38,19 @@ public Entry2(String id, float amount) {
}
}

@JsonPropertyOrder({"id", "amount", "enabled"})
static class Entry3 {
public String id;
public BigDecimal amount;
public boolean enabled;

public Entry3(String id, BigDecimal amount, boolean enabled) {
this.id = id;
this.amount = amount;
this.enabled = enabled;
}
}

/*
/**********************************************************************
/* Test methods
Expand Down Expand Up @@ -209,6 +223,26 @@ public void testForcedQuoting60() throws Exception
assertEquals("xyz,2.5\n", result);
}

// [dataformats-csv#438]: Should not quote BigInteger/BigDecimal (or booleans)
public void testForcedQuotingOfBigDecimal() throws Exception
{
CsvSchema schema = CsvSchema.builder()
.addColumn("id")
.addColumn("amount")
.addColumn("enabled")
.build();
String result = MAPPER.writer(schema)
.with(CsvGenerator.Feature.ALWAYS_QUOTE_STRINGS)
.writeValueAsString(new Entry3("abc", BigDecimal.valueOf(2.5), true));
assertEquals("\"abc\",2.5,true\n", result);

// Also, as per [dataformat-csv#81], should be possible to change dynamically
result = MAPPER.writer(schema)
.without(CsvGenerator.Feature.ALWAYS_QUOTE_STRINGS)
.writeValueAsString(new Entry3("xyz", BigDecimal.valueOf(1.5), false));
assertEquals("xyz,1.5,false\n", result);
}

public void testForcedQuotingWithQuoteEscapedWithBackslash() throws Exception
{
CsvSchema schema = CsvSchema.builder()
Expand Down
2 changes: 2 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Active Maintainers:
#435: (yaml) Minor parsing validation miss: tagged as `int`, exception
on underscore-only values
#437: (yaml) Update SnakeYAML dependency to 2.2
#438: (csv) `BigInteger` and `BigDecimal` are quoted if
`CsvGenerator.Feature.ALWAYS_QUOTE_STRINGS` enabled

2.15.3 (12-Oct-2023)

Expand Down

0 comments on commit f8bd56b

Please sign in to comment.