1 /*
   2  * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.sql;
  27 
  28 import java.io.IOException;
  29 import java.io.InvalidObjectException;
  30 import java.io.ObjectInputStream;
  31 import java.io.ObjectOutputStream;
  32 import java.util.Arrays;
  33 
  34 /**
  35  * The subclass of {@link SQLException} thrown when an error
  36  * occurs during a batch update operation.  In addition to the
  37  * information provided by {@link SQLException}, a
  38  * <code>BatchUpdateException</code> provides the update
  39  * counts for all commands that were executed successfully during the
  40  * batch update, that is, all commands that were executed before the error
  41  * occurred.  The order of elements in an array of update counts
  42  * corresponds to the order in which commands were added to the batch.
  43  * <P>
  44  * After a command in a batch update fails to execute properly
  45  * and a <code>BatchUpdateException</code> is thrown, the driver
  46  * may or may not continue to process the remaining commands in
  47  * the batch.  If the driver continues processing after a failure,
  48  * the array returned by the method
  49  * <code>BatchUpdateException.getUpdateCounts</code> will have
  50  * an element for every command in the batch rather than only
  51  * elements for the commands that executed successfully before
  52  * the error.  In the case where the driver continues processing
  53  * commands, the array element for any command
  54  * that failed is <code>Statement.EXECUTE_FAILED</code>.
  55  * <P>
  56  * A JDBC driver implementation should use
  57  * the constructor {@code BatchUpdateException(String reason, String SQLState,
  58  * int vendorCode, long []updateCounts,Throwable cause) } instead of
  59  * constructors that take {@code int[]} for the update counts to avoid the
  60  * possibility of overflow.
  61  * <p>
  62  * If {@code Statement.executeLargeBatch} method is invoked it is recommended that
  63  * {@code getLargeUpdateCounts} be called instead of {@code getUpdateCounts}
  64  * in order to avoid a possible overflow of the integer update count.
  65  * @since 1.2
  66  */
  67 
  68 public class BatchUpdateException extends SQLException {
  69 
  70   /**
  71    * Constructs a <code>BatchUpdateException</code> object initialized with a given
  72    * <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code> and
  73    * <code>updateCounts</code>.
  74    * The <code>cause</code> is not initialized, and may subsequently be
  75    * initialized by a call to the
  76    * {@link Throwable#initCause(java.lang.Throwable)} method.
  77    * <p>
  78    * <strong>Note:</strong> There is no validation of {@code updateCounts} for
  79    * overflow and because of this it is recommended that you use the constructor
  80    * {@code BatchUpdateException(String reason, String SQLState,
  81    * int vendorCode, long []updateCounts,Throwable cause) }.
  82    * </p>
  83    * @param reason a description of the error
  84    * @param SQLState an XOPEN or SQL:2003 code identifying the exception
  85    * @param vendorCode an exception code used by a particular
  86    * database vendor
  87    * @param updateCounts an array of <code>int</code>, with each element
  88    * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
  89    * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
  90    * the batch for JDBC drivers that continue processing
  91    * after a command failure; an update count or
  92    * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
  93    * prior to the failure for JDBC drivers that stop processing after a command
  94    * failure
  95    * @since 1.2
  96    * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
  97    * java.lang.Throwable)
  98    */
  99   public BatchUpdateException( String reason, String SQLState, int vendorCode,
 100                                int[] updateCounts ) {
 101       super(reason, SQLState, vendorCode);
 102       this.updateCounts  = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
 103       this.longUpdateCounts = (updateCounts == null) ? null : copyUpdateCount(updateCounts);
 104   }
 105 
 106   /**
 107    * Constructs a <code>BatchUpdateException</code> object initialized with a given
 108    * <code>reason</code>, <code>SQLState</code> and
 109    * <code>updateCounts</code>.
 110    * The <code>cause</code> is not initialized, and may subsequently be
 111    * initialized by a call to the
 112    * {@link Throwable#initCause(java.lang.Throwable)} method. The vendor code
 113    * is initialized to 0.
 114    * <p>
 115    * <strong>Note:</strong> There is no validation of {@code updateCounts} for
 116    * overflow and because of this it is recommended that you use the constructor
 117    * {@code BatchUpdateException(String reason, String SQLState,
 118    * int vendorCode, long []updateCounts,Throwable cause) }.
 119    * </p>
 120    * @param reason a description of the exception
 121    * @param SQLState an XOPEN or SQL:2003 code identifying the exception
 122    * @param updateCounts an array of <code>int</code>, with each element
 123    * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
 124    * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
 125    * the batch for JDBC drivers that continue processing
 126    * after a command failure; an update count or
 127    * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
 128    * prior to the failure for JDBC drivers that stop processing after a command
 129    * failure
 130    * @since 1.2
 131    * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
 132    * java.lang.Throwable)
 133    */
 134   public BatchUpdateException(String reason, String SQLState,
 135                               int[] updateCounts) {
 136       this(reason, SQLState, 0, updateCounts);
 137   }
 138 
 139   /**
 140    * Constructs a <code>BatchUpdateException</code> object initialized with a given
 141    * <code>reason</code> and <code>updateCounts</code>.
 142    * The <code>cause</code> is not initialized, and may subsequently be
 143    * initialized by a call to the
 144    * {@link Throwable#initCause(java.lang.Throwable)} method.  The
 145    * <code>SQLState</code> is initialized to <code>null</code>
 146    * and the vendor code is initialized to 0.
 147    * <p>
 148    * <strong>Note:</strong> There is no validation of {@code updateCounts} for
 149    * overflow and because of this it is recommended that you use the constructor
 150    * {@code BatchUpdateException(String reason, String SQLState,
 151    * int vendorCode, long []updateCounts,Throwable cause) }.
 152    * </p>
 153    * @param reason a description of the exception
 154    * @param updateCounts an array of <code>int</code>, with each element
 155    * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
 156    * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
 157    * the batch for JDBC drivers that continue processing
 158    * after a command failure; an update count or
 159    * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
 160    * prior to the failure for JDBC drivers that stop processing after a command
 161    * failure
 162    * @since 1.2
 163    * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
 164    * java.lang.Throwable)
 165    */
 166   public  BatchUpdateException(String reason, int[] updateCounts) {
 167       this(reason, null, 0, updateCounts);
 168   }
 169 
 170   /**
 171    * Constructs a <code>BatchUpdateException</code> object initialized with a given
 172    * <code>updateCounts</code>.
 173    * initialized by a call to the
 174    * {@link Throwable#initCause(java.lang.Throwable)} method. The  <code>reason</code>
 175    * and <code>SQLState</code> are initialized to null and the vendor code
 176    * is initialized to 0.
 177    * <p>
 178    * <strong>Note:</strong> There is no validation of {@code updateCounts} for
 179    * overflow and because of this it is recommended that you use the constructor
 180    * {@code BatchUpdateException(String reason, String SQLState,
 181    * int vendorCode, long []updateCounts,Throwable cause) }.
 182    * </p>
 183    * @param updateCounts an array of <code>int</code>, with each element
 184    * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
 185    * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
 186    * the batch for JDBC drivers that continue processing
 187    * after a command failure; an update count or
 188    * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
 189    * prior to the failure for JDBC drivers that stop processing after a command
 190    * failure
 191    * @since 1.2
 192    * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
 193    * java.lang.Throwable)
 194    */
 195   public BatchUpdateException(int[] updateCounts) {
 196       this(null, null, 0, updateCounts);
 197   }
 198 
 199   /**
 200    * Constructs a <code>BatchUpdateException</code> object.
 201    * The <code>reason</code>, <code>SQLState</code> and <code>updateCounts</code>
 202    *  are initialized to <code>null</code> and the vendor code is initialized to 0.
 203    * The <code>cause</code> is not initialized, and may subsequently be
 204    * initialized by a call to the
 205    * {@link Throwable#initCause(java.lang.Throwable)} method.
 206    *
 207    * @since 1.2
 208    * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
 209    * java.lang.Throwable)
 210    */
 211   public BatchUpdateException() {
 212         this(null, null, 0, null);
 213   }
 214 
 215   /**
 216    * Constructs a <code>BatchUpdateException</code> object initialized with
 217    *  a given <code>cause</code>.
 218    * The <code>SQLState</code> and <code>updateCounts</code>
 219    * are initialized
 220    * to <code>null</code> and the vendor code is initialized to 0.
 221    * The <code>reason</code>  is initialized to <code>null</code> if
 222    * <code>cause==null</code> or to <code>cause.toString()</code> if
 223    *  <code>cause!=null</code>.
 224    * @param cause the underlying reason for this <code>SQLException</code>
 225    * (which is saved for later retrieval by the <code>getCause()</code> method);
 226    * may be null indicating the cause is non-existent or unknown.
 227    * @since 1.6
 228    * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
 229    * java.lang.Throwable)
 230    */
 231   public BatchUpdateException(Throwable cause) {
 232       this((cause == null ? null : cause.toString()), null, 0, (int[])null, cause);
 233   }
 234 
 235   /**
 236    * Constructs a <code>BatchUpdateException</code> object initialized with a
 237    * given <code>cause</code> and <code>updateCounts</code>.
 238    * The <code>SQLState</code> is initialized
 239    * to <code>null</code> and the vendor code is initialized to 0.
 240    * The <code>reason</code>  is initialized to <code>null</code> if
 241    * <code>cause==null</code> or to <code>cause.toString()</code> if
 242    * <code>cause!=null</code>.
 243    * <p>
 244    * <strong>Note:</strong> There is no validation of {@code updateCounts} for
 245    * overflow and because of this it is recommended that you use the constructor
 246    * {@code BatchUpdateException(String reason, String SQLState,
 247    * int vendorCode, long []updateCounts,Throwable cause) }.
 248    * </p>
 249    * @param updateCounts an array of <code>int</code>, with each element
 250    * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
 251    * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
 252    * the batch for JDBC drivers that continue processing
 253    * after a command failure; an update count or
 254    * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
 255    * prior to the failure for JDBC drivers that stop processing after a command
 256    * failure
 257    * @param cause the underlying reason for this <code>SQLException</code>
 258    * (which is saved for later retrieval by the <code>getCause()</code> method); may be null indicating
 259    * the cause is non-existent or unknown.
 260    * @since 1.6
 261    * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
 262    * java.lang.Throwable)
 263    */
 264   public BatchUpdateException(int []updateCounts , Throwable cause) {
 265       this((cause == null ? null : cause.toString()), null, 0, updateCounts, cause);
 266   }
 267 
 268   /**
 269    * Constructs a <code>BatchUpdateException</code> object initialized with
 270    * a given <code>reason</code>, <code>cause</code>
 271    * and <code>updateCounts</code>. The <code>SQLState</code> is initialized
 272    * to <code>null</code> and the vendor code is initialized to 0.
 273    * <p>
 274    * <strong>Note:</strong> There is no validation of {@code updateCounts} for
 275    * overflow and because of this it is recommended that you use the constructor
 276    * {@code BatchUpdateException(String reason, String SQLState,
 277    * int vendorCode, long []updateCounts,Throwable cause) }.
 278    * </p>
 279    * @param reason a description of the exception
 280    * @param updateCounts an array of <code>int</code>, with each element
 281    *indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
 282    * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
 283    * the batch for JDBC drivers that continue processing
 284    * after a command failure; an update count or
 285    * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
 286    * prior to the failure for JDBC drivers that stop processing after a command
 287    * failure
 288    * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method);
 289    * may be null indicating
 290    * the cause is non-existent or unknown.
 291    * @since 1.6
 292    * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
 293    * java.lang.Throwable)
 294    */
 295   public BatchUpdateException(String reason, int []updateCounts, Throwable cause) {
 296       this(reason, null, 0, updateCounts, cause);
 297   }
 298 
 299   /**
 300    * Constructs a <code>BatchUpdateException</code> object initialized with
 301    * a given <code>reason</code>, <code>SQLState</code>,<code>cause</code>, and
 302    * <code>updateCounts</code>. The vendor code is initialized to 0.
 303    *
 304    * @param reason a description of the exception
 305    * @param SQLState an XOPEN or SQL:2003 code identifying the exception
 306    * @param updateCounts an array of <code>int</code>, with each element
 307    * indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
 308    * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
 309    * the batch for JDBC drivers that continue processing
 310    * after a command failure; an update count or
 311    * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
 312    * prior to the failure for JDBC drivers that stop processing after a command
 313    * failure
 314    * <p>
 315    * <strong>Note:</strong> There is no validation of {@code updateCounts} for
 316    * overflow and because of this it is recommended that you use the constructor
 317    * {@code BatchUpdateException(String reason, String SQLState,
 318    * int vendorCode, long []updateCounts,Throwable cause) }.
 319    * </p>
 320    * @param cause the underlying reason for this <code>SQLException</code>
 321    * (which is saved for later retrieval by the <code>getCause()</code> method);
 322    * may be null indicating
 323    * the cause is non-existent or unknown.
 324    * @since 1.6
 325    * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
 326    * java.lang.Throwable)
 327    */
 328   public BatchUpdateException(String reason, String SQLState,
 329           int []updateCounts, Throwable cause) {
 330       this(reason, SQLState, 0, updateCounts, cause);
 331   }
 332 
 333   /**
 334    * Constructs a <code>BatchUpdateException</code> object initialized with
 335    * a given <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
 336    * <code>cause</code> and <code>updateCounts</code>.
 337    *
 338    * @param reason a description of the error
 339    * @param SQLState an XOPEN or SQL:2003 code identifying the exception
 340    * @param vendorCode an exception code used by a particular
 341    * database vendor
 342    * @param updateCounts an array of <code>int</code>, with each element
 343    *indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
 344    * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
 345    * the batch for JDBC drivers that continue processing
 346    * after a command failure; an update count or
 347    * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
 348    * prior to the failure for JDBC drivers that stop processing after a command
 349    * failure
 350    * <p>
 351    * <strong>Note:</strong> There is no validation of {@code updateCounts} for
 352    * overflow and because of this it is recommended that you use the constructor
 353    * {@code BatchUpdateException(String reason, String SQLState,
 354    * int vendorCode, long []updateCounts,Throwable cause) }.
 355    * </p>
 356    * @param cause the underlying reason for this <code>SQLException</code> (which is saved for later retrieval by the <code>getCause()</code> method);
 357    * may be null indicating
 358    * the cause is non-existent or unknown.
 359    * @since 1.6
 360    * @see #BatchUpdateException(java.lang.String, java.lang.String, int, long[],
 361    * java.lang.Throwable)
 362    */
 363   public BatchUpdateException(String reason, String SQLState, int vendorCode,
 364                                 int []updateCounts,Throwable cause) {
 365         super(reason, SQLState, vendorCode, cause);
 366         this.updateCounts  = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
 367         this.longUpdateCounts = (updateCounts == null) ? null : copyUpdateCount(updateCounts);
 368   }
 369 
 370   /**
 371    * Retrieves the update count for each update statement in the batch
 372    * update that executed successfully before this exception occurred.
 373    * A driver that implements batch updates may or may not continue to
 374    * process the remaining commands in a batch when one of the commands
 375    * fails to execute properly. If the driver continues processing commands,
 376    * the array returned by this method will have as many elements as
 377    * there are commands in the batch; otherwise, it will contain an
 378    * update count for each command that executed successfully before
 379    * the <code>BatchUpdateException</code> was thrown.
 380    * <P>
 381    * The possible return values for this method were modified for
 382    * the Java 2 SDK, Standard Edition, version 1.3.  This was done to
 383    * accommodate the new option of continuing to process commands
 384    * in a batch update after a <code>BatchUpdateException</code> object
 385    * has been thrown.
 386    *
 387    * @return an array of <code>int</code> containing the update counts
 388    * for the updates that were executed successfully before this error
 389    * occurred.  Or, if the driver continues to process commands after an
 390    * error, one of the following for every command in the batch:
 391    * <OL>
 392    * <LI>an update count
 393    *  <LI><code>Statement.SUCCESS_NO_INFO</code> to indicate that the command
 394    *     executed successfully but the number of rows affected is unknown
 395    *  <LI><code>Statement.EXECUTE_FAILED</code> to indicate that the command
 396    *     failed to execute successfully
 397    * </OL>
 398    * @since 1.3
 399    * @see #getLargeUpdateCounts()
 400    */
 401   public int[] getUpdateCounts() {
 402       return (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
 403   }
 404 
 405   /**
 406    * Constructs a <code>BatchUpdateException</code> object initialized with
 407    * a given <code>reason</code>, <code>SQLState</code>, <code>vendorCode</code>
 408    * <code>cause</code> and <code>updateCounts</code>.
 409    * <p>
 410    * This constructor should be used when the returned update count may exceed
 411    * {@link Integer#MAX_VALUE}.
 412    *
 413    * @param reason a description of the error
 414    * @param SQLState an XOPEN or SQL:2003 code identifying the exception
 415    * @param vendorCode an exception code used by a particular
 416    * database vendor
 417    * @param updateCounts an array of <code>long</code>, with each element
 418    *indicating the update count, <code>Statement.SUCCESS_NO_INFO</code> or
 419    * <code>Statement.EXECUTE_FAILED</code> for each SQL command in
 420    * the batch for JDBC drivers that continue processing
 421    * after a command failure; an update count or
 422    * <code>Statement.SUCCESS_NO_INFO</code> for each SQL command in the batch
 423    * prior to the failure for JDBC drivers that stop processing after a command
 424    * failure
 425    * @param cause the underlying reason for this <code>SQLException</code>
 426    * (which is saved for later retrieval by the <code>getCause()</code> method);
 427    * may be null indicating the cause is non-existent or unknown.
 428    * @since 1.8
 429    */
 430   public BatchUpdateException(String reason, String SQLState, int vendorCode,
 431           long []updateCounts,Throwable cause) {
 432       super(reason, SQLState, vendorCode, cause);
 433       this.longUpdateCounts  = (updateCounts == null) ? null : Arrays.copyOf(updateCounts, updateCounts.length);
 434       this.updateCounts = (longUpdateCounts == null) ? null : copyUpdateCount(longUpdateCounts);
 435   }
 436 
 437   /**
 438    * Retrieves the update count for each update statement in the batch
 439    * update that executed successfully before this exception occurred.
 440    * A driver that implements batch updates may or may not continue to
 441    * process the remaining commands in a batch when one of the commands
 442    * fails to execute properly. If the driver continues processing commands,
 443    * the array returned by this method will have as many elements as
 444    * there are commands in the batch; otherwise, it will contain an
 445    * update count for each command that executed successfully before
 446    * the <code>BatchUpdateException</code> was thrown.
 447    * <p>
 448    * This method should be used when {@code Statement.executeLargeBatch} is
 449    * invoked and the returned update count may exceed {@link Integer#MAX_VALUE}.
 450    *
 451    * @return an array of <code>long</code> containing the update counts
 452    * for the updates that were executed successfully before this error
 453    * occurred.  Or, if the driver continues to process commands after an
 454    * error, one of the following for every command in the batch:
 455    * <OL>
 456    * <LI>an update count
 457    *  <LI><code>Statement.SUCCESS_NO_INFO</code> to indicate that the command
 458    *     executed successfully but the number of rows affected is unknown
 459    *  <LI><code>Statement.EXECUTE_FAILED</code> to indicate that the command
 460    *     failed to execute successfully
 461    * </OL>
 462    * @since 1.8
 463    */
 464   public long[] getLargeUpdateCounts() {
 465       return (longUpdateCounts == null) ? null :
 466               Arrays.copyOf(longUpdateCounts, longUpdateCounts.length);
 467   }
 468 
 469   /**
 470    * The array that describes the outcome of a batch execution.
 471    * @serial
 472    * @since 1.2
 473    */
 474   private  int[] updateCounts;
 475 
 476   /*
 477    * Starting with Java SE 8, JDBC has added support for returning an update
 478    * count > Integer.MAX_VALUE.  Because of this the following changes were made
 479    * to BatchUpdateException:
 480    * <ul>
 481    * <li>Add field longUpdateCounts</li>
 482    * <li>Add Constructorr which takes long[] for update counts</li>
 483    * <li>Add getLargeUpdateCounts method</li>
 484    * </ul>
 485    * When any of the constructors are called, the int[] and long[] updateCount
 486    * fields are populated by copying the one array to each other.
 487    *
 488    * As the JDBC driver passes in the updateCounts, there has always been the
 489    * possiblity for overflow and BatchUpdateException does not need to account
 490    * for that, it simply copies the arrays.
 491    *
 492    * JDBC drivers should always use the constructor that specifies long[] and
 493    * JDBC application developers should call getLargeUpdateCounts.
 494    */
 495 
 496   /**
 497    * The array that describes the outcome of a batch execution.
 498    * @serial
 499    * @since 1.8
 500    */
 501   private  long[] longUpdateCounts;
 502 
 503   private static final long serialVersionUID = 5977529877145521757L;
 504 
 505   /*
 506    * Utility method to copy int[] updateCount to long[] updateCount
 507    */
 508   private static long[] copyUpdateCount(int[] uc) {
 509       long[] copy = new long[uc.length];
 510       for(int i= 0; i< uc.length; i++) {
 511           copy[i] = uc[i];
 512       }
 513       return copy;
 514   }
 515 
 516   /*
 517    * Utility method to copy long[] updateCount to int[] updateCount.
 518    * No checks for overflow will be done as it is expected a  user will call
 519    * getLargeUpdateCounts.
 520    */
 521   private static int[] copyUpdateCount(long[] uc) {
 522       int[] copy = new int[uc.length];
 523       for(int i= 0; i< uc.length; i++) {
 524           copy[i] = (int) uc[i];
 525       }
 526       return copy;
 527   }
 528     /**
 529      * readObject is called to restore the state of the
 530      * {@code BatchUpdateException} from a stream.
 531      */
 532     private void readObject(ObjectInputStream s)
 533             throws IOException, ClassNotFoundException {
 534 
 535        ObjectInputStream.GetField fields = s.readFields();
 536        int[] tmp = (int[])fields.get("updateCounts", null);
 537        long[] tmp2 = (long[])fields.get("longUpdateCounts", null);
 538        if(tmp != null && tmp2 != null && tmp.length != tmp2.length)
 539            throw new InvalidObjectException("update counts are not the expected size");
 540        if (tmp != null)
 541            updateCounts = tmp.clone();
 542        if (tmp2 != null)
 543            longUpdateCounts = tmp2.clone();
 544        if(updateCounts == null && longUpdateCounts != null)
 545            updateCounts = copyUpdateCount(longUpdateCounts);
 546        if(longUpdateCounts == null && updateCounts != null)
 547            longUpdateCounts = copyUpdateCount(updateCounts);
 548 
 549     }
 550 
 551     /**
 552      * writeObject is called to save the state of the {@code BatchUpdateException}
 553      * to a stream.
 554      */
 555     private void writeObject(ObjectOutputStream s)
 556             throws IOException, ClassNotFoundException {
 557 
 558         ObjectOutputStream.PutField fields = s.putFields();
 559         fields.put("updateCounts", updateCounts);
 560         fields.put("longUpdateCounts", longUpdateCounts);
 561         s.writeFields();
 562     }
 563 }