Jdbc41Bridge.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.dbcp2;

  18. import java.io.InputStream;
  19. import java.io.Reader;
  20. import java.math.BigDecimal;
  21. import java.net.URL;
  22. import java.sql.Array;
  23. import java.sql.Blob;
  24. import java.sql.Clob;
  25. import java.sql.Connection;
  26. import java.sql.DatabaseMetaData;
  27. import java.sql.Date;
  28. import java.sql.Ref;
  29. import java.sql.ResultSet;
  30. import java.sql.RowId;
  31. import java.sql.SQLException;
  32. import java.sql.SQLFeatureNotSupportedException;
  33. import java.sql.SQLXML;
  34. import java.sql.Statement;
  35. import java.sql.Time;
  36. import java.sql.Timestamp;
  37. import java.util.concurrent.Executor;
  38. import java.util.logging.Logger;

  39. import javax.sql.CommonDataSource;

  40. /**
  41.  * Defines bridge methods to JDBC 4.1 (Java 7 or above) methods to allow call sites to operate safely (without
  42.  * {@link AbstractMethodError}) when using a JDBC driver written for JDBC 4.0 (Java 6 or above).
  43.  * <p>
  44.  * 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.
  45.  * </p>
  46.  * <p>
  47.  * This should probably be moved or at least copied in some form to Apache Commons DbUtils.
  48.  * </p>
  49.  *
  50.  * @since 2.6.0
  51.  */
  52. public class Jdbc41Bridge {

  53.     /**
  54.      * Delegates to {@link Connection#abort(Executor)} without throwing an {@link AbstractMethodError}.
  55.      * <p>
  56.      * If the JDBC driver does not implement {@link Connection#abort(Executor)}, then call {@link Connection#close()}.
  57.      * </p>
  58.      *
  59.      * @param connection
  60.      *            the receiver
  61.      * @param executor
  62.      *            See {@link Connection#abort(Executor)}.
  63.      * @throws SQLException
  64.      *             See {@link Connection#abort(Executor)}.
  65.      * @see Connection#abort(Executor)
  66.      */
  67.     public static void abort(final Connection connection, final Executor executor) throws SQLException {
  68.         try {
  69.             connection.abort(executor);
  70.         } catch (final AbstractMethodError e) {
  71.             connection.close();
  72.         }
  73.     }

  74.     /**
  75.      * Delegates to {@link Statement#closeOnCompletion()} without throwing an {@link AbstractMethodError}.
  76.      * <p>
  77.      * If the JDBC driver does not implement {@link Statement#closeOnCompletion()}, then just check that the connection
  78.      * is closed to then throw an SQLException.
  79.      * </p>
  80.      *
  81.      * @param statement
  82.      *            See {@link Statement#closeOnCompletion()}
  83.      * @throws SQLException
  84.      *             See {@link Statement#closeOnCompletion()}
  85.      * @see Statement#closeOnCompletion()
  86.      */
  87.     public static void closeOnCompletion(final Statement statement) throws SQLException {
  88.         try {
  89.             statement.closeOnCompletion();
  90.         } catch (final AbstractMethodError e) {
  91.             if (statement.isClosed()) {
  92.                 throw new SQLException("Statement closed");
  93.             }
  94.         }
  95.     }

  96.     /**
  97.      * Delegates to {@link DatabaseMetaData#generatedKeyAlwaysReturned()} without throwing a
  98.      * {@link AbstractMethodError}.
  99.      * <p>
  100.      * If the JDBC driver does not implement {@link DatabaseMetaData#generatedKeyAlwaysReturned()}, then return false.
  101.      * </p>
  102.      *
  103.      * @param databaseMetaData
  104.      *            See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
  105.      * @return See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
  106.      * @throws SQLException
  107.      *             See {@link DatabaseMetaData#generatedKeyAlwaysReturned()}
  108.      * @see DatabaseMetaData#generatedKeyAlwaysReturned()
  109.      */
  110.     public static boolean generatedKeyAlwaysReturned(final DatabaseMetaData databaseMetaData) throws SQLException {
  111.         try {
  112.             return databaseMetaData.generatedKeyAlwaysReturned();
  113.         } catch (final AbstractMethodError e) {
  114.             // do nothing
  115.             return false;
  116.         }
  117.     }

  118.     /**
  119.      * Delegates to {@link Connection#getNetworkTimeout()} without throwing an {@link AbstractMethodError}.
  120.      * <p>
  121.      * If the JDBC driver does not implement {@link Connection#getNetworkTimeout()}, then return 0.
  122.      * </p>
  123.      *
  124.      * @param connection
  125.      *            the receiver
  126.      * @return See {@link Connection#getNetworkTimeout()}
  127.      * @throws SQLException
  128.      *             See {@link Connection#getNetworkTimeout()}
  129.      * @see Connection#getNetworkTimeout()
  130.      */
  131.     public static int getNetworkTimeout(final Connection connection) throws SQLException {
  132.         try {
  133.             return connection.getNetworkTimeout();
  134.         } catch (final AbstractMethodError e) {
  135.             return 0;
  136.         }
  137.     }

  138.     /**
  139.      * Delegates to {@link ResultSet#getObject(int, Class)} without throwing an {@link AbstractMethodError}.
  140.      * <p>
  141.      * If the JDBC driver does not implement {@link ResultSet#getObject(int, Class)}, then return 0.
  142.      * </p>
  143.      *
  144.      * @param <T>
  145.      *            See {@link ResultSet#getObject(int, Class)}
  146.      * @param resultSet
  147.      *            See {@link ResultSet#getObject(int, Class)}
  148.      * @param columnIndex
  149.      *            See {@link ResultSet#getObject(int, Class)}
  150.      * @param type
  151.      *            See {@link ResultSet#getObject(int, Class)}
  152.      * @return See {@link ResultSet#getObject(int, Class)}
  153.      * @throws SQLException
  154.      *             See {@link ResultSet#getObject(int, Class)}
  155.      * @see ResultSet#getObject(int, Class)
  156.      */
  157.     @SuppressWarnings("unchecked")
  158.     public static <T> T getObject(final ResultSet resultSet, final int columnIndex, final Class<T> type)
  159.             throws SQLException {
  160.         try {
  161.             return resultSet.getObject(columnIndex, type);
  162.         } catch (final AbstractMethodError e) {
  163.             if (type == String.class) {
  164.                 return (T) resultSet.getString(columnIndex);
  165.             }
  166.             // Numbers
  167.             if (type == Integer.class) {
  168.                 return (T) Integer.valueOf(resultSet.getInt(columnIndex));
  169.             }
  170.             if (type == Long.class) {
  171.                 return (T) Long.valueOf(resultSet.getLong(columnIndex));
  172.             }
  173.             if (type == Double.class) {
  174.                 return (T) Double.valueOf(resultSet.getDouble(columnIndex));
  175.             }
  176.             if (type == Float.class) {
  177.                 return (T) Float.valueOf(resultSet.getFloat(columnIndex));
  178.             }
  179.             if (type == Short.class) {
  180.                 return (T) Short.valueOf(resultSet.getShort(columnIndex));
  181.             }
  182.             if (type == BigDecimal.class) {
  183.                 return (T) resultSet.getBigDecimal(columnIndex);
  184.             }
  185.             if (type == Byte.class) {
  186.                 return (T) Byte.valueOf(resultSet.getByte(columnIndex));
  187.             }
  188.             // Dates
  189.             if (type == Date.class) {
  190.                 return (T) resultSet.getDate(columnIndex);
  191.             }
  192.             if (type == Time.class) {
  193.                 return (T) resultSet.getTime(columnIndex);
  194.             }
  195.             if (type == Timestamp.class) {
  196.                 return (T) resultSet.getTimestamp(columnIndex);
  197.             }
  198.             // Streams
  199.             if (type == InputStream.class) {
  200.                 return (T) resultSet.getBinaryStream(columnIndex);
  201.             }
  202.             if (type == Reader.class) {
  203.                 return (T) resultSet.getCharacterStream(columnIndex);
  204.             }
  205.             // Other
  206.             if (type == Object.class) {
  207.                 return (T) resultSet.getObject(columnIndex);
  208.             }
  209.             if (type == Boolean.class) {
  210.                 return (T) Boolean.valueOf(resultSet.getBoolean(columnIndex));
  211.             }
  212.             if (type == Array.class) {
  213.                 return (T) resultSet.getArray(columnIndex);
  214.             }
  215.             if (type == Blob.class) {
  216.                 return (T) resultSet.getBlob(columnIndex);
  217.             }
  218.             if (type == Clob.class) {
  219.                 return (T) resultSet.getClob(columnIndex);
  220.             }
  221.             if (type == Ref.class) {
  222.                 return (T) resultSet.getRef(columnIndex);
  223.             }
  224.             if (type == RowId.class) {
  225.                 return (T) resultSet.getRowId(columnIndex);
  226.             }
  227.             if (type == SQLXML.class) {
  228.                 return (T) resultSet.getSQLXML(columnIndex);
  229.             }
  230.             if (type == URL.class) {
  231.                 return (T) resultSet.getURL(columnIndex);
  232.             }
  233.             throw new SQLFeatureNotSupportedException(
  234.                     String.format("resultSet=%s, columnIndex=%,d, type=%s", resultSet, columnIndex, type));
  235.         }
  236.     }

  237.     /**
  238.      * Delegates to {@link ResultSet#getObject(String, Class)} without throwing an {@link AbstractMethodError}.
  239.      *
  240.      * @param <T>
  241.      *            See {@link ResultSet#getObject(String, Class)}
  242.      * @param resultSet
  243.      *            See {@link ResultSet#getObject(String, Class)}
  244.      * @param columnLabel
  245.      *            See {@link ResultSet#getObject(String, Class)}
  246.      * @param type
  247.      *            See {@link ResultSet#getObject(String, Class)}
  248.      * @return See {@link ResultSet#getObject(String, Class)}
  249.      * @throws SQLException
  250.      *             See {@link ResultSet#getObject(String, Class)}
  251.      * @see ResultSet#getObject(int, Class)
  252.      */
  253.     @SuppressWarnings("unchecked")
  254.     public static <T> T getObject(final ResultSet resultSet, final String columnLabel, final Class<T> type)
  255.             throws SQLException {
  256.         try {
  257.             return resultSet.getObject(columnLabel, type);
  258.         } catch (final AbstractMethodError e) {
  259.             // Numbers
  260.             if (type == Integer.class) {
  261.                 return (T) Integer.valueOf(resultSet.getInt(columnLabel));
  262.             }
  263.             if (type == Long.class) {
  264.                 return (T) Long.valueOf(resultSet.getLong(columnLabel));
  265.             }
  266.             if (type == Double.class) {
  267.                 return (T) Double.valueOf(resultSet.getDouble(columnLabel));
  268.             }
  269.             if (type == Float.class) {
  270.                 return (T) Float.valueOf(resultSet.getFloat(columnLabel));
  271.             }
  272.             if (type == Short.class) {
  273.                 return (T) Short.valueOf(resultSet.getShort(columnLabel));
  274.             }
  275.             if (type == BigDecimal.class) {
  276.                 return (T) resultSet.getBigDecimal(columnLabel);
  277.             }
  278.             if (type == Byte.class) {
  279.                 return (T) Byte.valueOf(resultSet.getByte(columnLabel));
  280.             }
  281.             // Dates
  282.             if (type == Date.class) {
  283.                 return (T) resultSet.getDate(columnLabel);
  284.             }
  285.             if (type == Time.class) {
  286.                 return (T) resultSet.getTime(columnLabel);
  287.             }
  288.             if (type == Timestamp.class) {
  289.                 return (T) resultSet.getTimestamp(columnLabel);
  290.             }
  291.             // Streams
  292.             if (type == InputStream.class) {
  293.                 return (T) resultSet.getBinaryStream(columnLabel);
  294.             }
  295.             if (type == Reader.class) {
  296.                 return (T) resultSet.getCharacterStream(columnLabel);
  297.             }
  298.             // Other
  299.             if (type == Object.class) {
  300.                 return (T) resultSet.getObject(columnLabel);
  301.             }
  302.             if (type == Boolean.class) {
  303.                 return (T) Boolean.valueOf(resultSet.getBoolean(columnLabel));
  304.             }
  305.             if (type == Array.class) {
  306.                 return (T) resultSet.getArray(columnLabel);
  307.             }
  308.             if (type == Blob.class) {
  309.                 return (T) resultSet.getBlob(columnLabel);
  310.             }
  311.             if (type == Clob.class) {
  312.                 return (T) resultSet.getClob(columnLabel);
  313.             }
  314.             if (type == Ref.class) {
  315.                 return (T) resultSet.getRef(columnLabel);
  316.             }
  317.             if (type == RowId.class) {
  318.                 return (T) resultSet.getRowId(columnLabel);
  319.             }
  320.             if (type == SQLXML.class) {
  321.                 return (T) resultSet.getSQLXML(columnLabel);
  322.             }
  323.             if (type == URL.class) {
  324.                 return (T) resultSet.getURL(columnLabel);
  325.             }
  326.             throw new SQLFeatureNotSupportedException(
  327.                     String.format("resultSet=%s, columnLabel=%s, type=%s", resultSet, columnLabel, type));
  328.         }
  329.     }

  330.     /**
  331.      * Delegates to {@link CommonDataSource#getParentLogger()} without throwing an {@link AbstractMethodError}.
  332.      * <p>
  333.      * If the JDBC driver does not implement {@link CommonDataSource#getParentLogger()}, then return null.
  334.      * </p>
  335.      *
  336.      * @param commonDataSource
  337.      *            See {@link CommonDataSource#getParentLogger()}
  338.      * @return See {@link CommonDataSource#getParentLogger()}
  339.      * @throws SQLFeatureNotSupportedException
  340.      *             See {@link CommonDataSource#getParentLogger()}
  341.      */
  342.     public static Logger getParentLogger(final CommonDataSource commonDataSource) throws SQLFeatureNotSupportedException {
  343.         try {
  344.             return commonDataSource.getParentLogger();
  345.         } catch (final AbstractMethodError e) {
  346.             throw new SQLFeatureNotSupportedException("javax.sql.CommonDataSource#getParentLogger()");
  347.         }
  348.     }

  349.     /**
  350.      * Delegates to {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)} without throwing a
  351.      * {@link AbstractMethodError}.
  352.      * <p>
  353.      * If the JDBC driver does not implement {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)},
  354.      * then return null.
  355.      * </p>
  356.      *
  357.      * @param databaseMetaData
  358.      *            the receiver
  359.      * @param catalog
  360.      *            See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
  361.      * @param schemaPattern
  362.      *            See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
  363.      * @param tableNamePattern
  364.      *            See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
  365.      * @param columnNamePattern
  366.      *            See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
  367.      * @return See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
  368.      * @throws SQLException
  369.      *             See {@link DatabaseMetaData#getPseudoColumns(String, String, String, String)}
  370.      * @see DatabaseMetaData#getPseudoColumns(String, String, String, String)
  371.      */
  372.     public static ResultSet getPseudoColumns(final DatabaseMetaData databaseMetaData, final String catalog,
  373.             final String schemaPattern, final String tableNamePattern, final String columnNamePattern)
  374.             throws SQLException {
  375.         try {
  376.             return databaseMetaData.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern);
  377.         } catch (final AbstractMethodError e) {
  378.             // do nothing
  379.             return null;
  380.         }
  381.     }

  382.     /**
  383.      * Delegates to {@link Connection#getSchema()} without throwing an {@link AbstractMethodError}.
  384.      * <p>
  385.      * If the JDBC driver does not implement {@link Connection#getSchema()}, then return null.
  386.      * </p>
  387.      *
  388.      * @param connection
  389.      *            the receiver
  390.      * @return null for a JDBC 4 driver or a value per {@link Connection#getSchema()}.
  391.      * @throws SQLException
  392.      *             See {@link Connection#getSchema()}.
  393.      * @see Connection#getSchema()
  394.      */
  395.     public static String getSchema(final Connection connection) throws SQLException {
  396.         try {
  397.             return connection.getSchema();
  398.         } catch (final AbstractMethodError e) {
  399.             // do nothing
  400.             return null;
  401.         }
  402.     }

  403.     /**
  404.      * Delegates to {@link Statement#isCloseOnCompletion()} without throwing an {@link AbstractMethodError}.
  405.      * <p>
  406.      * If the JDBC driver does not implement {@link Statement#isCloseOnCompletion()}, then just check that the
  407.      * connection is closed to then throw an SQLException.
  408.      * </p>
  409.      *
  410.      * @param statement
  411.      *            See {@link Statement#isCloseOnCompletion()}
  412.      * @return See {@link Statement#isCloseOnCompletion()}
  413.      * @throws SQLException
  414.      *             See {@link Statement#isCloseOnCompletion()}
  415.      * @see Statement#closeOnCompletion()
  416.      */
  417.     public static boolean isCloseOnCompletion(final Statement statement) throws SQLException {
  418.         try {
  419.             return statement.isCloseOnCompletion();
  420.         } catch (final AbstractMethodError e) {
  421.             if (statement.isClosed()) {
  422.                 throw new SQLException("Statement closed");
  423.             }
  424.             return false;
  425.         }
  426.     }

  427.     /**
  428.      * Delegates to {@link Connection#setNetworkTimeout(Executor, int)} without throwing an {@link AbstractMethodError}.
  429.      * <p>
  430.      * If the JDBC driver does not implement {@link Connection#setNetworkTimeout(Executor, int)}, then do nothing.
  431.      * </p>
  432.      *
  433.      * @param connection
  434.      *            the receiver
  435.      * @param executor
  436.      *            See {@link Connection#setNetworkTimeout(Executor, int)}
  437.      * @param milliseconds
  438.      *            {@link Connection#setNetworkTimeout(Executor, int)}
  439.      * @throws SQLException
  440.      *             {@link Connection#setNetworkTimeout(Executor, int)}
  441.      * @see Connection#setNetworkTimeout(Executor, int)
  442.      */
  443.     public static void setNetworkTimeout(final Connection connection, final Executor executor, final int milliseconds)
  444.             throws SQLException {
  445.         try {
  446.             connection.setNetworkTimeout(executor, milliseconds);
  447.         } catch (final AbstractMethodError ignored) {
  448.             // do nothing
  449.         }
  450.     }

  451.     /**
  452.      * Delegates to {@link Connection#setSchema(String)} without throwing an {@link AbstractMethodError}.
  453.      * <p>
  454.      * If the JDBC driver does not implement {@link Connection#setSchema(String)}, then do nothing.
  455.      * </p>
  456.      *
  457.      * @param connection
  458.      *            the receiver
  459.      * @param schema
  460.      *            See {@link Connection#setSchema(String)}.
  461.      * @throws SQLException
  462.      *             See {@link Connection#setSchema(String)}.
  463.      * @see Connection#setSchema(String)
  464.      */
  465.     public static void setSchema(final Connection connection, final String schema) throws SQLException {
  466.         try {
  467.             connection.setSchema(schema);
  468.         } catch (final AbstractMethodError ignored) {
  469.             // do nothing
  470.         }
  471.     }

  472. }