001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.dbcp2; 018 019import java.io.InputStream; 020import java.io.Reader; 021import java.math.BigDecimal; 022import java.net.URL; 023import java.sql.Array; 024import java.sql.Blob; 025import java.sql.Clob; 026import java.sql.Connection; 027import java.sql.DatabaseMetaData; 028import java.sql.Date; 029import java.sql.Ref; 030import java.sql.ResultSet; 031import java.sql.RowId; 032import java.sql.SQLException; 033import java.sql.SQLFeatureNotSupportedException; 034import java.sql.SQLXML; 035import java.sql.Statement; 036import java.sql.Time; 037import java.sql.Timestamp; 038import java.util.concurrent.Executor; 039import java.util.logging.Logger; 040 041import javax.sql.CommonDataSource; 042 043/** 044 * Defines bridge methods to JDBC 4.1 (Java 7 or above) methods to allow call sites to operate safely (without 045 * {@link AbstractMethodError}) when using a JDBC driver written for JDBC 4.0 (Java 6 or above). 046 * <p> 047 * There should be no need to this kind of code for JDBC 4.2 in Java 8 due to JDBC's use of default methods. 048 * </p> 049 * <p> 050 * This should probably be moved or at least copied in some form to Apache Commons DbUtils. 051 * </p> 052 * 053 * @since 2.6.0 054 */ 055public class Jdbc41Bridge { 056 057 /** 058 * Delegates to {@link Connection#abort(Executor)} without throwing an {@link AbstractMethodError}. 059 * <p> 060 * If the JDBC driver does not implement {@link Connection#abort(Executor)}, then call {@link Connection#close()}. 061 * </p> 062 * 063 * @param connection 064 * the receiver 065 * @param executor 066 * See {@link Connection#abort(Executor)}. 067 * @throws SQLException 068 * See {@link Connection#abort(Executor)}. 069 * @see Connection#abort(Executor) 070 */ 071 public static void abort(final Connection connection, final Executor executor) throws SQLException { 072 try { 073 connection.abort(executor); 074 } catch (final AbstractMethodError e) { 075 connection.close(); 076 } 077 } 078 079 /** 080 * Delegates to {@link Statement#closeOnCompletion()} without throwing an {@link AbstractMethodError}. 081 * <p> 082 * If the JDBC driver does not implement {@link Statement#closeOnCompletion()}, then just check that the connection 083 * is closed to then throw an SQLException. 084 * </p> 085 * 086 * @param statement 087 * See {@link Statement#closeOnCompletion()} 088 * @throws SQLException 089 * See {@link Statement#closeOnCompletion()} 090 * @see Statement#closeOnCompletion() 091 */ 092 public static void closeOnCompletion(final Statement statement) throws SQLException { 093 try { 094 statement.closeOnCompletion(); 095 } catch (final AbstractMethodError e) { 096 if (statement.isClosed()) { 097 throw new SQLException("Statement closed"); 098 } 099 } 100 } 101 102 /** 103 * Delegates to {@link DatabaseMetaData#generatedKeyAlwaysReturned()} without throwing a 104 * {@link AbstractMethodError}. 105 * <p> 106 * If the JDBC driver does not implement {@link DatabaseMetaData#generatedKeyAlwaysReturned()}, then return false. 107 * </p> 108 * 109 * @param databaseMetaData 110 * See {@link DatabaseMetaData#generatedKeyAlwaysReturned()} 111 * @return See {@link DatabaseMetaData#generatedKeyAlwaysReturned()} 112 * @throws SQLException 113 * See {@link DatabaseMetaData#generatedKeyAlwaysReturned()} 114 * @see DatabaseMetaData#generatedKeyAlwaysReturned() 115 */ 116 public static boolean generatedKeyAlwaysReturned(final DatabaseMetaData databaseMetaData) throws SQLException { 117 try { 118 return databaseMetaData.generatedKeyAlwaysReturned(); 119 } catch (final AbstractMethodError e) { 120 // do nothing 121 return false; 122 } 123 } 124 125 /** 126 * Delegates to {@link Connection#getNetworkTimeout()} without throwing an {@link AbstractMethodError}. 127 * <p> 128 * If the JDBC driver does not implement {@link Connection#getNetworkTimeout()}, then return 0. 129 * </p> 130 * 131 * @param connection 132 * the receiver 133 * @return See {@link Connection#getNetworkTimeout()} 134 * @throws SQLException 135 * See {@link Connection#getNetworkTimeout()} 136 * @see Connection#getNetworkTimeout() 137 */ 138 public static int getNetworkTimeout(final Connection connection) throws SQLException { 139 try { 140 return connection.getNetworkTimeout(); 141 } catch (final AbstractMethodError e) { 142 return 0; 143 } 144 } 145 146 /** 147 * Delegates to {@link ResultSet#getObject(int, Class)} without throwing an {@link AbstractMethodError}. 148 * <p> 149 * If the JDBC driver does not implement {@link ResultSet#getObject(int, Class)}, then return 0. 150 * </p> 151 * 152 * @param <T> 153 * See {@link ResultSet#getObject(int, Class)} 154 * @param resultSet 155 * See {@link ResultSet#getObject(int, Class)} 156 * @param columnIndex 157 * See {@link ResultSet#getObject(int, Class)} 158 * @param type 159 * See {@link ResultSet#getObject(int, Class)} 160 * @return See {@link ResultSet#getObject(int, Class)} 161 * @throws SQLException 162 * See {@link ResultSet#getObject(int, Class)} 163 * @see ResultSet#getObject(int, Class) 164 */ 165 @SuppressWarnings("unchecked") 166 public static <T> T getObject(final ResultSet resultSet, final int columnIndex, final Class<T> type) 167 throws SQLException { 168 try { 169 return resultSet.getObject(columnIndex, type); 170 } catch (final AbstractMethodError e) { 171 if (type == String.class) { 172 return (T) resultSet.getString(columnIndex); 173 } 174 // Numbers 175 if (type == Integer.class) { 176 return (T) Integer.valueOf(resultSet.getInt(columnIndex)); 177 } 178 if (type == Long.class) { 179 return (T) Long.valueOf(resultSet.getLong(columnIndex)); 180 } 181 if (type == Double.class) { 182 return (T) Double.valueOf(resultSet.getDouble(columnIndex)); 183 } 184 if (type == Float.class) { 185 return (T) Float.valueOf(resultSet.getFloat(columnIndex)); 186 } 187 if (type == Short.class) { 188 return (T) Short.valueOf(resultSet.getShort(columnIndex)); 189 } 190 if (type == BigDecimal.class) { 191 return (T) resultSet.getBigDecimal(columnIndex); 192 } 193 if (type == Byte.class) { 194 return (T) Byte.valueOf(resultSet.getByte(columnIndex)); 195 } 196 // Dates 197 if (type == Date.class) { 198 return (T) resultSet.getDate(columnIndex); 199 } 200 if (type == Time.class) { 201 return (T) resultSet.getTime(columnIndex); 202 } 203 if (type == Timestamp.class) { 204 return (T) resultSet.getTimestamp(columnIndex); 205 } 206 // Streams 207 if (type == InputStream.class) { 208 return (T) resultSet.getBinaryStream(columnIndex); 209 } 210 if (type == Reader.class) { 211 return (T) resultSet.getCharacterStream(columnIndex); 212 } 213 // Other 214 if (type == Object.class) { 215 return (T) resultSet.getObject(columnIndex); 216 } 217 if (type == Boolean.class) { 218 return (T) Boolean.valueOf(resultSet.getBoolean(columnIndex)); 219 } 220 if (type == Array.class) { 221 return (T) resultSet.getArray(columnIndex); 222 } 223 if (type == Blob.class) { 224 return (T) resultSet.getBlob(columnIndex); 225 } 226 if (type == Clob.class) { 227 return (T) resultSet.getClob(columnIndex); 228 } 229 if (type == Ref.class) { 230 return (T) resultSet.getRef(columnIndex); 231 } 232 if (type == RowId.class) { 233 return (T) resultSet.getRowId(columnIndex); 234 } 235 if (type == SQLXML.class) { 236 return (T) resultSet.getSQLXML(columnIndex); 237 } 238 if (type == URL.class) { 239 return (T) resultSet.getURL(columnIndex); 240 } 241 throw new SQLFeatureNotSupportedException( 242 String.format("resultSet=%s, columnIndex=%,d, type=%s", resultSet, columnIndex, type)); 243 } 244 } 245 246 /** 247 * Delegates to {@link ResultSet#getObject(String, Class)} without throwing an {@link AbstractMethodError}. 248 * 249 * @param <T> 250 * See {@link ResultSet#getObject(String, Class)} 251 * @param resultSet 252 * See {@link ResultSet#getObject(String, Class)} 253 * @param columnLabel 254 * See {@link ResultSet#getObject(String, Class)} 255 * @param type 256 * See {@link ResultSet#getObject(String, Class)} 257 * @return See {@link ResultSet#getObject(String, Class)} 258 * @throws SQLException 259 * See {@link ResultSet#getObject(String, Class)} 260 * @see ResultSet#getObject(int, Class) 261 */ 262 @SuppressWarnings("unchecked") 263 public static <T> T getObject(final ResultSet resultSet, final String columnLabel, final Class<T> type) 264 throws SQLException { 265 try { 266 return resultSet.getObject(columnLabel, type); 267 } catch (final AbstractMethodError e) { 268 // Numbers 269 if (type == Integer.class) { 270 return (T) Integer.valueOf(resultSet.getInt(columnLabel)); 271 } 272 if (type == Long.class) { 273 return (T) Long.valueOf(resultSet.getLong(columnLabel)); 274 } 275 if (type == Double.class) { 276 return (T) Double.valueOf(resultSet.getDouble(columnLabel)); 277 } 278 if (type == Float.class) { 279 return (T) Float.valueOf(resultSet.getFloat(columnLabel)); 280 } 281 if (type == Short.class) { 282 return (T) Short.valueOf(resultSet.getShort(columnLabel)); 283 } 284 if (type == BigDecimal.class) { 285 return (T) resultSet.getBigDecimal(columnLabel); 286 } 287 if (type == Byte.class) { 288 return (T) Byte.valueOf(resultSet.getByte(columnLabel)); 289 } 290 // Dates 291 if (type == Date.class) { 292 return (T) resultSet.getDate(columnLabel); 293 } 294 if (type == Time.class) { 295 return (T) resultSet.getTime(columnLabel); 296 } 297 if (type == Timestamp.class) { 298 return (T) resultSet.getTimestamp(columnLabel); 299 } 300 // Streams 301 if (type == InputStream.class) { 302 return (T) resultSet.getBinaryStream(columnLabel); 303 } 304 if (type == Reader.class) { 305 return (T) resultSet.getCharacterStream(columnLabel); 306 } 307 // Other 308 if (type == Object.class) { 309 return (T) resultSet.getObject(columnLabel); 310 } 311 if (type == Boolean.class) { 312 return (T) Boolean.valueOf(resultSet.getBoolean(columnLabel)); 313 } 314 if (type == Array.class) { 315 return (T) resultSet.getArray(columnLabel); 316 } 317 if (type == Blob.class) { 318 return (T) resultSet.getBlob(columnLabel); 319 } 320 if (type == Clob.class) { 321 return (T) resultSet.getClob(columnLabel); 322 } 323 if (type == Ref.class) { 324 return (T) resultSet.getRef(columnLabel); 325 } 326 if (type == RowId.class) { 327 return (T) resultSet.getRowId(columnLabel); 328 } 329 if (type == SQLXML.class) { 330 return (T) resultSet.getSQLXML(columnLabel); 331 } 332 if (type == URL.class) { 333 return (T) resultSet.getURL(columnLabel); 334 } 335 throw new SQLFeatureNotSupportedException( 336 String.format("resultSet=%s, columnLabel=%s, type=%s", resultSet, columnLabel, type)); 337 } 338 } 339 340 /** 341 * Delegates to {@link CommonDataSource#getParentLogger()} without throwing an {@link AbstractMethodError}. 342 * <p> 343 * If the JDBC driver does not implement {@link CommonDataSource#getParentLogger()}, then return null. 344 * </p> 345 * 346 * @param commonDataSource 347 * See {@link CommonDataSource#getParentLogger()} 348 * @return See {@link CommonDataSource#getParentLogger()} 349 * @throws SQLFeatureNotSupportedException 350 * See {@link CommonDataSource#getParentLogger()} 351 */ 352 public static Logger getParentLogger(final CommonDataSource commonDataSource) throws SQLFeatureNotSupportedException { 353 try { 354 return commonDataSource.getParentLogger(); 355 } catch (final AbstractMethodError e) { 356 throw new SQLFeatureNotSupportedException("javax.sql.CommonDataSource#getParentLogger()"); 357 } 358 } 359 360 /** 361 * Delegates to {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} without throwing a 362 * {@link AbstractMethodError}. 363 * <p> 364 * If the JDBC driver does not implement {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}, 365 * then return null. 366 * </p> 367 * 368 * @param databaseMetaData 369 * the receiver 370 * @param catalog 371 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 372 * @param schemaPattern 373 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 374 * @param tableNamePattern 375 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 376 * @param columnNamePattern 377 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 378 * @return See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 379 * @throws SQLException 380 * See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} 381 * @see DatabaseMetaData#getPseudoColumns(String, String, String, String) 382 */ 383 public static ResultSet getPseudoColumns(final DatabaseMetaData databaseMetaData, final String catalog, 384 final String schemaPattern, final String tableNamePattern, final String columnNamePattern) 385 throws SQLException { 386 try { 387 return databaseMetaData.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern); 388 } catch (final AbstractMethodError e) { 389 // do nothing 390 return null; 391 } 392 } 393 394 /** 395 * Delegates to {@link Connection#getSchema()} without throwing an {@link AbstractMethodError}. 396 * <p> 397 * If the JDBC driver does not implement {@link Connection#getSchema()}, then return null. 398 * </p> 399 * 400 * @param connection 401 * the receiver 402 * @return null for a JDBC 4 driver or a value per {@link Connection#getSchema()}. 403 * @throws SQLException 404 * See {@link Connection#getSchema()}. 405 * @see Connection#getSchema() 406 */ 407 public static String getSchema(final Connection connection) throws SQLException { 408 try { 409 return connection.getSchema(); 410 } catch (final AbstractMethodError e) { 411 // do nothing 412 return null; 413 } 414 } 415 416 /** 417 * Delegates to {@link Statement#isCloseOnCompletion()} without throwing an {@link AbstractMethodError}. 418 * <p> 419 * If the JDBC driver does not implement {@link Statement#isCloseOnCompletion()}, then just check that the 420 * connection is closed to then throw an SQLException. 421 * </p> 422 * 423 * @param statement 424 * See {@link Statement#isCloseOnCompletion()} 425 * @return See {@link Statement#isCloseOnCompletion()} 426 * @throws SQLException 427 * See {@link Statement#isCloseOnCompletion()} 428 * @see Statement#closeOnCompletion() 429 */ 430 public static boolean isCloseOnCompletion(final Statement statement) throws SQLException { 431 try { 432 return statement.isCloseOnCompletion(); 433 } catch (final AbstractMethodError e) { 434 if (statement.isClosed()) { 435 throw new SQLException("Statement closed"); 436 } 437 return false; 438 } 439 } 440 441 /** 442 * Delegates to {@link Connection#setNetworkTimeout(Executor, int)} without throwing an {@link AbstractMethodError}. 443 * <p> 444 * If the JDBC driver does not implement {@link Connection#setNetworkTimeout(Executor, int)}, then do nothing. 445 * </p> 446 * 447 * @param connection 448 * the receiver 449 * @param executor 450 * See {@link Connection#setNetworkTimeout(Executor, int)} 451 * @param milliseconds 452 * {@link Connection#setNetworkTimeout(Executor, int)} 453 * @throws SQLException 454 * {@link Connection#setNetworkTimeout(Executor, int)} 455 * @see Connection#setNetworkTimeout(Executor, int) 456 */ 457 public static void setNetworkTimeout(final Connection connection, final Executor executor, final int milliseconds) 458 throws SQLException { 459 try { 460 connection.setNetworkTimeout(executor, milliseconds); 461 } catch (final AbstractMethodError ignored) { 462 // do nothing 463 } 464 } 465 466 /** 467 * Delegates to {@link Connection#setSchema(String)} without throwing an {@link AbstractMethodError}. 468 * <p> 469 * If the JDBC driver does not implement {@link Connection#setSchema(String)}, then do nothing. 470 * </p> 471 * 472 * @param connection 473 * the receiver 474 * @param schema 475 * See {@link Connection#setSchema(String)}. 476 * @throws SQLException 477 * See {@link Connection#setSchema(String)}. 478 * @see Connection#setSchema(String) 479 */ 480 public static void setSchema(final Connection connection, final String schema) throws SQLException { 481 try { 482 connection.setSchema(schema); 483 } catch (final AbstractMethodError ignored) { 484 // do nothing 485 } 486 } 487 488}