Return-Path: X-Original-To: apmail-commons-commits-archive@minotaur.apache.org Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 8936211B0C for ; Thu, 14 Aug 2014 19:49:37 +0000 (UTC) Received: (qmail 67868 invoked by uid 500); 14 Aug 2014 19:49:37 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 67630 invoked by uid 500); 14 Aug 2014 19:49:37 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 67447 invoked by uid 99); 14 Aug 2014 19:49:37 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 14 Aug 2014 19:49:37 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 14 Aug 2014 19:48:57 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 55DAB2388C74 for ; Thu, 14 Aug 2014 19:48:17 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r919363 [10/44] - in /websites/production/commons/content/proper/commons-csv: ./ apidocs/ apidocs/org/apache/commons/csv/ apidocs/org/apache/commons/csv/class-use/ apidocs/resources/ apidocs/src-html/org/apache/commons/csv/ jacoco/ jacoco/.... Date: Thu, 14 Aug 2014 19:48:09 -0000 To: commits@commons.apache.org From: britter@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140814194817.55DAB2388C74@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: websites/production/commons/content/proper/commons-csv/apidocs/src-html/org/apache/commons/csv/CSVPrinter.html ============================================================================== --- websites/production/commons/content/proper/commons-csv/apidocs/src-html/org/apache/commons/csv/CSVPrinter.html (original) +++ websites/production/commons/content/proper/commons-csv/apidocs/src-html/org/apache/commons/csv/CSVPrinter.html Thu Aug 14 19:48:06 2014 @@ -39,7 +39,7 @@ 031/** 032 * Prints values in a CSV format. 033 * -034 * @version $Id: CSVPrinter.java 1592365 2014-05-04 16:08:56Z britter $ +034 * @version $Id: CSVPrinter.java 1617076 2014-08-10 09:23:01Z britter $ 035 */ 036public final class CSVPrinter implements Flushable, Closeable { 037 @@ -53,395 +53,453 @@ 045 /** 046 * Creates a printer that will print values to the given stream following the CSVFormat. 047 * <p> -048 * Currently, only a pure encapsulation format or a pure escaping format is supported. Hybrid formats -049 * (encapsulation and escaping with a different character) are not supported. +048 * Currently, only a pure encapsulation format or a pure escaping format is supported. Hybrid formats (encapsulation +049 * and escaping with a different character) are not supported. 050 * </p> 051 * 052 * @param out -053 * stream to which to print. Must not be null. +053 * stream to which to print. Must not be null. 054 * @param format -055 * the CSV format. Must not be null. -056 * @throws IllegalArgumentException -057 * thrown if the parameters of the format are inconsistent or if either out or format are null. -058 */ -059 public CSVPrinter(final Appendable out, final CSVFormat format) { -060 Assertions.notNull(out, "out"); -061 Assertions.notNull(format, "format"); -062 -063 this.out = out; -064 this.format = format; -065 this.format.validate(); -066 } -067 -068 // ====================================================== -069 // printing implementation -070 // ====================================================== -071 -072 public void close() throws IOException { -073 if (out instanceof Closeable) { -074 ((Closeable) out).close(); -075 } -076 } +055 * the CSV format. Must not be null. +056 * @throws IOException +057 * thrown if the optional header cannot be printed. +058 * @throws IllegalArgumentException +059 * thrown if the parameters of the format are inconsistent or if either out or format are null. +060 */ +061 public CSVPrinter(final Appendable out, final CSVFormat format) throws IOException { +062 Assertions.notNull(out, "out"); +063 Assertions.notNull(format, "format"); +064 +065 this.out = out; +066 this.format = format; +067 // TODO: Is it a good idea to do this here instead of on the first call to a print method? +068 // It seems a pain to have to track whether the header has already been printed or not. +069 if (format.getHeader() != null) { +070 this.printRecord((Object[]) format.getHeader()); +071 } +072 } +073 +074 // ====================================================== +075 // printing implementation +076 // ====================================================== 077 -078 /** -079 * Flushes the underlying stream. -080 * -081 * @throws IOException -082 * If an I/O error occurs -083 */ -084 public void flush() throws IOException { -085 if (out instanceof Flushable) { -086 ((Flushable) out).flush(); -087 } -088 } -089 -090 /** -091 * Prints the string as the next value on the line. The value will be escaped or encapsulated as needed. -092 * -093 * @param value -094 * value to be output. -095 * @throws IOException -096 * If an I/O error occurs -097 */ -098 public void print(final Object value) throws IOException { -099 // null values are considered empty -100 String strValue; -101 if (value == null) { -102 final String nullString = format.getNullString(); -103 strValue = nullString == null ? Constants.EMPTY : nullString; -104 } else { -105 strValue = value.toString(); -106 } -107 this.print(value, strValue, 0, strValue.length()); -108 } -109 -110 private void print(final Object object, final CharSequence value, -111 final int offset, final int len) throws IOException { -112 if (!newRecord) { -113 out.append(format.getDelimiter()); -114 } -115 if (format.isQuoting()) { -116 // the original object is needed so can check for Number -117 printAndQuote(object, value, offset, len); -118 } else if (format.isEscaping()) { -119 printAndEscape(value, offset, len); -120 } else { -121 out.append(value, offset, offset + len); -122 } -123 newRecord = false; -124 } -125 -126 /* -127 * Note: must only be called if escaping is enabled, otherwise will generate NPE -128 */ -129 private void printAndEscape(final CharSequence value, final int offset, final int len) throws IOException { -130 int start = offset; -131 int pos = offset; -132 final int end = offset + len; -133 -134 final char delim = format.getDelimiter(); -135 final char escape = format.getEscape().charValue(); -136 -137 while (pos < end) { -138 char c = value.charAt(pos); -139 if (c == CR || c == LF || c == delim || c == escape) { -140 // write out segment up until this char -141 if (pos > start) { -142 out.append(value, start, pos); -143 } -144 if (c == LF) { -145 c = 'n'; -146 } else if (c == CR) { -147 c = 'r'; -148 } -149 -150 out.append(escape); -151 out.append(c); -152 -153 start = pos + 1; // start on the current char after this one -154 } +078 public void close() throws IOException { +079 if (out instanceof Closeable) { +080 ((Closeable) out).close(); +081 } +082 } +083 +084 /** +085 * Flushes the underlying stream. +086 * +087 * @throws IOException +088 * If an I/O error occurs +089 */ +090 public void flush() throws IOException { +091 if (out instanceof Flushable) { +092 ((Flushable) out).flush(); +093 } +094 } +095 +096 /** +097 * Prints the string as the next value on the line. The value will be escaped or encapsulated as needed. +098 * +099 * @param value +100 * value to be output. +101 * @throws IOException +102 * If an I/O error occurs +103 */ +104 public void print(final Object value) throws IOException { +105 // null values are considered empty +106 String strValue; +107 if (value == null) { +108 final String nullString = format.getNullString(); +109 strValue = nullString == null ? Constants.EMPTY : nullString; +110 } else { +111 strValue = value.toString(); +112 } +113 this.print(value, strValue, 0, strValue.length()); +114 } +115 +116 private void print(final Object object, final CharSequence value, +117 final int offset, final int len) throws IOException { +118 if (!newRecord) { +119 out.append(format.getDelimiter()); +120 } +121 if (format.isQuoteCharacterSet()) { +122 // the original object is needed so can check for Number +123 printAndQuote(object, value, offset, len); +124 } else if (format.isEscapeCharacterSet()) { +125 printAndEscape(value, offset, len); +126 } else { +127 out.append(value, offset, offset + len); +128 } +129 newRecord = false; +130 } +131 +132 /* +133 * Note: must only be called if escaping is enabled, otherwise will generate NPE +134 */ +135 private void printAndEscape(final CharSequence value, final int offset, final int len) throws IOException { +136 int start = offset; +137 int pos = offset; +138 final int end = offset + len; +139 +140 final char delim = format.getDelimiter(); +141 final char escape = format.getEscapeCharacter().charValue(); +142 +143 while (pos < end) { +144 char c = value.charAt(pos); +145 if (c == CR || c == LF || c == delim || c == escape) { +146 // write out segment up until this char +147 if (pos > start) { +148 out.append(value, start, pos); +149 } +150 if (c == LF) { +151 c = 'n'; +152 } else if (c == CR) { +153 c = 'r'; +154 } 155 -156 pos++; -157 } +156 out.append(escape); +157 out.append(c); 158 -159 // write last segment -160 if (pos > start) { -161 out.append(value, start, pos); -162 } -163 } +159 start = pos + 1; // start on the current char after this one +160 } +161 +162 pos++; +163 } 164 -165 /* -166 * Note: must only be called if quoting is enabled, otherwise will generate NPE -167 */ -168 // the original object is needed so can check for Number -169 private void printAndQuote(final Object object, final CharSequence value, -170 final int offset, final int len) throws IOException { -171 boolean quote = false; -172 int start = offset; -173 int pos = offset; -174 final int end = offset + len; -175 -176 final char delimChar = format.getDelimiter(); -177 final char quoteChar = format.getQuoteChar().charValue(); -178 -179 Quote quotePolicy = format.getQuotePolicy(); -180 if (quotePolicy == null) { -181 quotePolicy = Quote.MINIMAL; -182 } -183 switch (quotePolicy) { -184 case ALL: -185 quote = true; -186 break; -187 case NON_NUMERIC: -188 quote = !(object instanceof Number); -189 break; -190 case NONE: -191 // Use the existing escaping code -192 printAndEscape(value, offset, len); -193 return; -194 case MINIMAL: -195 if (len <= 0) { -196 // always quote an empty token that is the first -197 // on the line, as it may be the only thing on the -198 // line. If it were not quoted in that case, -199 // an empty line has no tokens. -200 if (newRecord) { -201 quote = true; -202 } -203 } else { -204 char c = value.charAt(pos); -205 -206 // Hmmm, where did this rule come from? -207 if (newRecord && (c < '0' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || (c > 'z'))) { -208 quote = true; -209 // } else if (c == ' ' || c == '\f' || c == '\t') { -210 } else if (c <= COMMENT) { -211 // Some other chars at the start of a value caused the parser to fail, so for now -212 // encapsulate if we start in anything less than '#'. We are being conservative -213 // by including the default comment char too. +165 // write last segment +166 if (pos > start) { +167 out.append(value, start, pos); +168 } +169 } +170 +171 /* +172 * Note: must only be called if quoting is enabled, otherwise will generate NPE +173 */ +174 // the original object is needed so can check for Number +175 private void printAndQuote(final Object object, final CharSequence value, +176 final int offset, final int len) throws IOException { +177 boolean quote = false; +178 int start = offset; +179 int pos = offset; +180 final int end = offset + len; +181 +182 final char delimChar = format.getDelimiter(); +183 final char quoteChar = format.getQuoteCharacter().charValue(); +184 +185 QuoteMode quoteModePolicy = format.getQuoteMode(); +186 if (quoteModePolicy == null) { +187 quoteModePolicy = QuoteMode.MINIMAL; +188 } +189 switch (quoteModePolicy) { +190 case ALL: +191 quote = true; +192 break; +193 case NON_NUMERIC: +194 quote = !(object instanceof Number); +195 break; +196 case NONE: +197 // Use the existing escaping code +198 printAndEscape(value, offset, len); +199 return; +200 case MINIMAL: +201 if (len <= 0) { +202 // always quote an empty token that is the first +203 // on the line, as it may be the only thing on the +204 // line. If it were not quoted in that case, +205 // an empty line has no tokens. +206 if (newRecord) { +207 quote = true; +208 } +209 } else { +210 char c = value.charAt(pos); +211 +212 // TODO where did this rule come from? +213 if (newRecord && (c < '0' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || (c > 'z'))) { 214 quote = true; -215 } else { -216 while (pos < end) { -217 c = value.charAt(pos); -218 if (c == LF || c == CR || c == quoteChar || c == delimChar) { -219 quote = true; -220 break; -221 } -222 pos++; -223 } -224 -225 if (!quote) { -226 pos = end - 1; -227 c = value.charAt(pos); -228 // if (c == ' ' || c == '\f' || c == '\t') { -229 // Some other chars at the end caused the parser to fail, so for now -230 // encapsulate if we end in anything less than ' ' -231 if (c <= SP) { -232 quote = true; -233 } -234 } -235 } -236 } -237 -238 if (!quote) { -239 // no encapsulation needed - write out the original value -240 out.append(value, start, end); -241 return; -242 } -243 break; -244 default: -245 throw new IllegalStateException("Unexpected Quote value: " + quotePolicy); -246 } -247 -248 if (!quote) { -249 // no encapsulation needed - write out the original value -250 out.append(value, start, end); -251 return; -252 } -253 -254 // we hit something that needed encapsulation -255 out.append(quoteChar); -256 -257 // Pick up where we left off: pos should be positioned on the first character that caused -258 // the need for encapsulation. -259 while (pos < end) { -260 final char c = value.charAt(pos); -261 if (c == quoteChar) { -262 // write out the chunk up until this point -263 -264 // add 1 to the length to write out the encapsulator also -265 out.append(value, start, pos + 1); -266 // put the next starting position on the encapsulator so we will -267 // write it out again with the next string (effectively doubling it) -268 start = pos; -269 } -270 pos++; -271 } -272 -273 // write the last segment -274 out.append(value, start, pos); -275 out.append(quoteChar); -276 } -277 -278 /** -279 * Prints a comment on a new line among the delimiter separated values. -280 * -281 * <p> -282 * Comments will always begin on a new line and occupy a least one full line. The character specified to start -283 * comments and a space will be inserted at the beginning of each new line in the comment. -284 * </p> -285 * -286 * If comments are disabled in the current CSV format this method does nothing. -287 * -288 * @param comment -289 * the comment to output -290 * @throws IOException -291 * If an I/O error occurs -292 */ -293 public void printComment(final String comment) throws IOException { -294 if (!format.isCommentingEnabled()) { -295 return; -296 } -297 if (!newRecord) { -298 println(); -299 } -300 out.append(format.getCommentStart().charValue()); -301 out.append(SP); -302 for (int i = 0; i < comment.length(); i++) { -303 final char c = comment.charAt(i); -304 switch (c) { -305 case CR: -306 if (i + 1 < comment.length() && comment.charAt(i + 1) == LF) { -307 i++; -308 } -309 //$FALL-THROUGH$ break intentionally excluded. -310 case LF: -311 println(); -312 out.append(format.getCommentStart().charValue()); -313 out.append(SP); -314 break; -315 default: -316 out.append(c); -317 break; -318 } -319 } -320 println(); -321 } -322 -323 /** -324 * Outputs the record separator. -325 * -326 * @throws IOException -327 * If an I/O error occurs -328 */ -329 public void println() throws IOException { -330 final String recordSeparator = format.getRecordSeparator(); -331 if (recordSeparator != null) { -332 out.append(recordSeparator); -333 } -334 newRecord = true; -335 } -336 -337 /** -338 * Prints a single line of delimiter separated values. The values will be quoted if needed. Quotes and newLine -339 * characters will be escaped. -340 * -341 * @param values -342 * values to output. -343 * @throws IOException -344 * If an I/O error occurs -345 */ -346 public void printRecord(final Iterable<?> values) throws IOException { -347 for (final Object value : values) { -348 print(value); -349 } -350 println(); -351 } -352 -353 /** -354 * Prints a single line of delimiter separated values. The values will be quoted if needed. Quotes and newLine -355 * characters will be escaped. -356 * -357 * @param values -358 * values to output. -359 * @throws IOException -360 * If an I/O error occurs -361 */ -362 public void printRecord(final Object... values) throws IOException { -363 for (final Object value : values) { -364 print(value); -365 } -366 println(); -367 } -368 -369 /** -370 * Prints all the objects in the given collection. -371 * -372 * @param values -373 * the values to print. -374 * @throws IOException -375 * If an I/O error occurs -376 */ -377 public void printRecords(final Iterable<?> values) throws IOException { -378 for (final Object value : values) { -379 if (value instanceof Object[]) { -380 this.printRecord((Object[]) value); -381 } else if (value instanceof Iterable) { -382 this.printRecord((Iterable<?>) value); -383 } else { -384 this.printRecord(value); -385 } -386 } -387 } -388 -389 /** -390 * Prints all the objects in the given array. -391 * -392 * @param values -393 * the values to print. -394 * @throws IOException -395 * If an I/O error occurs -396 */ -397 public void printRecords(final Object[] values) throws IOException { -398 for (final Object value : values) { -399 if (value instanceof Object[]) { -400 this.printRecord((Object[]) value); -401 } else if (value instanceof Iterable) { -402 this.printRecord((Iterable<?>) value); -403 } else { -404 this.printRecord(value); -405 } -406 } -407 } -408 -409 /** -410 * Prints all the objects in the given JDBC result set. -411 * -412 * @param resultSet result set -413 * the values to print. -414 * @throws IOException -415 * If an I/O error occurs -416 * @throws SQLException if a database access error occurs -417 */ -418 public void printRecords(final ResultSet resultSet) throws SQLException, IOException { -419 final int columnCount = resultSet.getMetaData().getColumnCount(); -420 while (resultSet.next()) { -421 for (int i = 1; i <= columnCount; i++) { -422 print(resultSet.getString(i)); -423 } -424 println(); -425 } -426 } -427 -428 /** -429 * Gets the target Appendable. +215 } else if (c <= COMMENT) { +216 // Some other chars at the start of a value caused the parser to fail, so for now +217 // encapsulate if we start in anything less than '#'. We are being conservative +218 // by including the default comment char too. +219 quote = true; +220 } else { +221 while (pos < end) { +222 c = value.charAt(pos); +223 if (c == LF || c == CR || c == quoteChar || c == delimChar) { +224 quote = true; +225 break; +226 } +227 pos++; +228 } +229 +230 if (!quote) { +231 pos = end - 1; +232 c = value.charAt(pos); +233 // Some other chars at the end caused the parser to fail, so for now +234 // encapsulate if we end in anything less than ' ' +235 if (c <= SP) { +236 quote = true; +237 } +238 } +239 } +240 } +241 +242 if (!quote) { +243 // no encapsulation needed - write out the original value +244 out.append(value, start, end); +245 return; +246 } +247 break; +248 default: +249 throw new IllegalStateException("Unexpected Quote value: " + quoteModePolicy); +250 } +251 +252 if (!quote) { +253 // no encapsulation needed - write out the original value +254 out.append(value, start, end); +255 return; +256 } +257 +258 // we hit something that needed encapsulation +259 out.append(quoteChar); +260 +261 // Pick up where we left off: pos should be positioned on the first character that caused +262 // the need for encapsulation. +263 while (pos < end) { +264 final char c = value.charAt(pos); +265 if (c == quoteChar) { +266 // write out the chunk up until this point +267 +268 // add 1 to the length to write out the encapsulator also +269 out.append(value, start, pos + 1); +270 // put the next starting position on the encapsulator so we will +271 // write it out again with the next string (effectively doubling it) +272 start = pos; +273 } +274 pos++; +275 } +276 +277 // write the last segment +278 out.append(value, start, pos); +279 out.append(quoteChar); +280 } +281 +282 /** +283 * Prints a comment on a new line among the delimiter separated values. +284 * +285 * <p> +286 * Comments will always begin on a new line and occupy a least one full line. The character specified to start +287 * comments and a space will be inserted at the beginning of each new line in the comment. +288 * </p> +289 * +290 * If comments are disabled in the current CSV format this method does nothing. +291 * +292 * @param comment +293 * the comment to output +294 * @throws IOException +295 * If an I/O error occurs +296 */ +297 public void printComment(final String comment) throws IOException { +298 if (!format.isCommentMarkerSet()) { +299 return; +300 } +301 if (!newRecord) { +302 println(); +303 } +304 out.append(format.getCommentMarker().charValue()); +305 out.append(SP); +306 for (int i = 0; i < comment.length(); i++) { +307 final char c = comment.charAt(i); +308 switch (c) { +309 case CR: +310 if (i + 1 < comment.length() && comment.charAt(i + 1) == LF) { +311 i++; +312 } +313 //$FALL-THROUGH$ break intentionally excluded. +314 case LF: +315 println(); +316 out.append(format.getCommentMarker().charValue()); +317 out.append(SP); +318 break; +319 default: +320 out.append(c); +321 break; +322 } +323 } +324 println(); +325 } +326 +327 /** +328 * Outputs the record separator. +329 * +330 * @throws IOException +331 * If an I/O error occurs +332 */ +333 public void println() throws IOException { +334 final String recordSeparator = format.getRecordSeparator(); +335 if (recordSeparator != null) { +336 out.append(recordSeparator); +337 } +338 newRecord = true; +339 } +340 +341 /** +342 * Prints the given values a single record of delimiter separated values followed by the record separator. +343 * +344 * <p> +345 * The values will be quoted if needed. Quotes and newLine characters will be escaped. This method adds the record +346 * separator to the output after printing the record, so there is no need to call {@link #println()}. +347 * </p> +348 * +349 * @param values +350 * values to output. +351 * @throws IOException +352 * If an I/O error occurs +353 */ +354 public void printRecord(final Iterable<?> values) throws IOException { +355 for (final Object value : values) { +356 print(value); +357 } +358 println(); +359 } +360 +361 /** +362 * Prints the given values a single record of delimiter separated values followed by the record separator. +363 * +364 * <p> +365 * The values will be quoted if needed. Quotes and newLine characters will be escaped. This method adds the record +366 * separator to the output after printing the record, so there is no need to call {@link #println()}. +367 * </p> +368 * +369 * @param values +370 * values to output. +371 * @throws IOException +372 * If an I/O error occurs +373 */ +374 public void printRecord(final Object... values) throws IOException { +375 for (final Object value : values) { +376 print(value); +377 } +378 println(); +379 } +380 +381 /** +382 * Prints all the objects in the given collection handling nested collections/arrays as records. +383 * +384 * <p>If the given collection only contains simple objects, this method will print a single record like +385 * {@link #printRecord(Iterable)}. If the given collections contains nested collections/arrays those nested elements +386 * will each be printed as records using {@link #printRecord(Object...)}.</p> +387 * +388 * <p>Given the following data structure:</p> +389 * <pre> +390 * <code> +391 * List&lt;String[]&gt; data = ... +392 * data.add(new String[]{ "A", "B", "C" }); +393 * data.add(new String[]{ "1", "2", "3" }); +394 * data.add(new String[]{ "A1", "B2", "C3" }); +395 * </code> +396 * </pre> +397 * +398 * <p>Calling this method will print:</p> +399 * <pre> +400 * <code> +401 * A, B, C +402 * 1, 2, 3 +403 * A1, B2, C3 +404 * </code> +405 * </pre> +406 * +407 * @param values +408 * the values to print. +409 * @throws IOException +410 * If an I/O error occurs +411 */ +412 public void printRecords(final Iterable<?> values) throws IOException { +413 for (final Object value : values) { +414 if (value instanceof Object[]) { +415 this.printRecord((Object[]) value); +416 } else if (value instanceof Iterable) { +417 this.printRecord((Iterable<?>) value); +418 } else { +419 this.printRecord(value); +420 } +421 } +422 } +423 +424 /** +425 * Prints all the objects in the given array handling nested collections/arrays as records. +426 * +427 * <p>If the given array only contains simple objects, this method will print a single record like +428 * {@link #printRecord(Object...)}. If the given collections contains nested collections/arrays those nested +429 * elements will each be printed as records using {@link #printRecord(Object...)}.</p> 430 * -431 * @return the target Appendable. -432 */ -433 public Appendable getOut() { -434 return this.out; -435 } -436} +431 * <p>Given the following data structure:</p> +432 * <pre> +433 * <code> +434 * String[][] data = new String[3][] +435 * data[0] = String[]{ "A", "B", "C" }; +436 * data[1] = new String[]{ "1", "2", "3" }; +437 * data[2] = new String[]{ "A1", "B2", "C3" }; +438 * </code> +439 * </pre> +440 * +441 * <p>Calling this method will print:</p> +442 * <pre> +443 * <code> +444 * A, B, C +445 * 1, 2, 3 +446 * A1, B2, C3 +447 * </code> +448 * </pre> +449 * +450 * @param values +451 * the values to print. +452 * @throws IOException +453 * If an I/O error occurs +454 */ +455 public void printRecords(final Object... values) throws IOException { +456 for (final Object value : values) { +457 if (value instanceof Object[]) { +458 this.printRecord((Object[]) value); +459 } else if (value instanceof Iterable) { +460 this.printRecord((Iterable<?>) value); +461 } else { +462 this.printRecord(value); +463 } +464 } +465 } +466 +467 /** +468 * Prints all the objects in the given JDBC result set. +469 * +470 * @param resultSet result set +471 * the values to print. +472 * @throws IOException +473 * If an I/O error occurs +474 * @throws SQLException if a database access error occurs +475 */ +476 public void printRecords(final ResultSet resultSet) throws SQLException, IOException { +477 final int columnCount = resultSet.getMetaData().getColumnCount(); +478 while (resultSet.next()) { +479 for (int i = 1; i <= columnCount; i++) { +480 print(resultSet.getString(i)); +481 } +482 println(); +483 } +484 } +485 +486 /** +487 * Gets the target Appendable. +488 * +489 * @return the target Appendable. +490 */ +491 public Appendable getOut() { +492 return this.out; +493 } +494}