Skip to content

Commit 3ac0ec2

Browse files
committed
JDBC Blob columns are now output as Base64 instead of Object#toString(),
which usually is InputStream#toString()
1 parent df3732b commit 3ac0ec2

5 files changed

Lines changed: 135 additions & 85 deletions

File tree

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
<artifactId>commons-io</artifactId>
5353
<version>2.15.1</version>
5454
</dependency>
55+
<dependency>
56+
<groupId>commons-codec</groupId>
57+
<artifactId>commons-codec</artifactId>
58+
<version>1.16.1</version>
59+
</dependency>
5560
<dependency>
5661
<groupId>org.apache.commons</groupId>
5762
<artifactId>commons-lang3</artifactId>

src/changes/changes.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
<action type="fix" issue="CSV-310" dev="ggregory" due-to="Buddhi De Silva">Misleading error message when QuoteMode set to None #352.</action>
5353
<action type="fix" issue="CSV-311" dev="ggregory" due-to="Christian Feuersaenger, Gary Gregory">OutOfMemory for very long rows despite using column value of type Reader.</action>
5454
<action type="fix" dev="ggregory" due-to="Gary Gregory">Use try-with-resources to manage JDBC Clob in CSVPrinter.printRecords(ResultSet).</action>
55+
<action type="fix" dev="ggregory" due-to="Gary Gregory">JDBC Blob columns are now output as Base64 instead of Object#toString(), which usually is InputStream#toString().</action>
5556
<!-- UPDATE -->
5657
<action type="update" dev="ggregory" due-to="Gary Gregory">Bump commons-io:commons-io: from 2.11.0 to 2.15.1.</action>
5758
<action type="update" dev="ggregory" due-to="Gary Gregory, Dependabot">Bump commons-parent from 57 to 67.</action>

src/main/java/org/apache/commons/csv/CSVFormat.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import java.io.File;
3434
import java.io.FileOutputStream;
3535
import java.io.IOException;
36+
import java.io.InputStream;
37+
import java.io.OutputStream;
3638
import java.io.OutputStreamWriter;
3739
import java.io.Reader;
3840
import java.io.Serializable;
@@ -49,8 +51,11 @@
4951
import java.util.Objects;
5052
import java.util.Set;
5153

54+
import org.apache.commons.codec.binary.Base64OutputStream;
5255
import org.apache.commons.io.IOUtils;
5356
import org.apache.commons.io.function.Uncheck;
57+
import org.apache.commons.io.output.AppendableOutputStream;
58+
import org.apache.commons.io.output.CloseShieldOutputStream;
5459

5560
/**
5661
* Specifies the format of a CSV file for parsing and writing.
@@ -2030,6 +2035,9 @@ public synchronized void print(final Object value, final Appendable out, final b
20302035
} else if (value instanceof Reader) {
20312036
print((Reader) value, out, newRecord);
20322037
return;
2038+
} else if (value instanceof InputStream) {
2039+
print((InputStream) value, out, newRecord);
2040+
return;
20332041
} else {
20342042
charSequence = value.toString();
20352043
}
@@ -2074,8 +2082,28 @@ public CSVPrinter print(final Path out, final Charset charset) throws IOExceptio
20742082
return print(Files.newBufferedWriter(out, charset));
20752083
}
20762084

2085+
private void print(final InputStream inputStream, final Appendable out, final boolean newRecord) throws IOException {
2086+
// InputStream is never null here
2087+
// There is nothing to escape when quoting is used which is the default.
2088+
if (!newRecord) {
2089+
append(getDelimiterString(), out);
2090+
}
2091+
final boolean quoteCharacterSet = isQuoteCharacterSet();
2092+
if (quoteCharacterSet) {
2093+
append(getQuoteCharacter().charValue(), out);
2094+
}
2095+
// Stream the input to the output without reading or holding the whole value in memory.
2096+
// AppendableOutputStream cannot "close" an Appendable.
2097+
try (OutputStream outputStream = new Base64OutputStream(new AppendableOutputStream<>(out))) {
2098+
IOUtils.copy(inputStream, outputStream);
2099+
}
2100+
if (quoteCharacterSet) {
2101+
append(getQuoteCharacter().charValue(), out);
2102+
}
2103+
}
2104+
20772105
private void print(final Reader reader, final Appendable out, final boolean newRecord) throws IOException {
2078-
// Reader is never null
2106+
// Reader is never null here
20792107
if (!newRecord) {
20802108
append(getDelimiterString(), out);
20812109
}
@@ -2088,7 +2116,6 @@ private void print(final Reader reader, final Appendable out, final boolean newR
20882116
} else {
20892117
IOUtils.copy(reader, out);
20902118
}
2091-
20922119
}
20932120

20942121
/**

src/main/java/org/apache/commons/csv/CSVPrinter.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
import java.io.Closeable;
2525
import java.io.Flushable;
2626
import java.io.IOException;
27+
import java.io.InputStream;
2728
import java.io.Reader;
29+
import java.sql.Blob;
2830
import java.sql.Clob;
2931
import java.sql.ResultSet;
3032
import java.sql.SQLException;
@@ -419,6 +421,10 @@ public void printRecords(final ResultSet resultSet) throws SQLException, IOExcep
419421
try (Reader reader = ((Clob) object).getCharacterStream()) {
420422
print(reader);
421423
}
424+
} else if (object instanceof Blob) {
425+
try (InputStream inputStream = ((Blob) object).getBinaryStream()) {
426+
print(inputStream);
427+
}
422428
} else {
423429
print(object);
424430
}

0 commit comments

Comments
 (0)