You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by df...@apache.org on 2009/02/11 11:59:15 UTC
svn commit: r743297 - in /commons/sandbox/dbutils/java5: ./
src/java/org/apache/commons/dbutils/
src/java/org/apache/commons/dbutils/handlers/
Author: dfabulich
Date: Wed Feb 11 10:59:15 2009
New Revision: 743297
URL: http://svn.apache.org/viewvc?rev=743297&view=rev
Log:
merging changes from bugfixing branch
Added:
commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java
- copied, changed from r743293, commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java
Removed:
commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/GenericListHandler.java
Modified:
commons/sandbox/dbutils/java5/ (props changed)
commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/BasicRowProcessor.java
commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/BeanProcessor.java
commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/QueryRunner.java
commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/ArrayListHandler.java
commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/BeanListHandler.java
commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/ColumnListHandler.java
commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/MapListHandler.java
Propchange: commons/sandbox/dbutils/java5/
------------------------------------------------------------------------------
svn:mergeinfo = /commons/sandbox/dbutils/bugfixing:741988-743293
Modified: commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/BasicRowProcessor.java
URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/BasicRowProcessor.java?rev=743297&r1=743296&r2=743297&view=diff
==============================================================================
--- commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/BasicRowProcessor.java (original)
+++ commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/BasicRowProcessor.java Wed Feb 11 10:59:15 2009
@@ -143,22 +143,52 @@
* A Map that converts all keys to lowercase Strings for case insensitive
* lookups. This is needed for the toMap() implementation because
* databases don't consistenly handle the casing of column names.
+ *
+ * <p>The keys are stored as they are given [BUG #DBUTILS-34], so we maintain
+ * an internal mapping from lowercase keys to the real keys in order to
+ * achieve the case insensitive lookup.
+ *
+ * <p>Note: This implementation does not allow <tt>null</tt>
+ * for key, whereas {@link HashMap} does, because of the code:
+ * <pre>
+ * key.toString().toLowerCase()
+ * </pre>
*/
private static class CaseInsensitiveHashMap extends HashMap<String, Object> {
+ /**
+ * The internal mapping from lowercase keys to the real keys.
+ *
+ * <p>
+ * Any query operation using the key
+ * ({@link #get(Object)}, {@link #containsKey(Object)})
+ * is done in three steps:
+ * <ul>
+ * <li>convert the parameter key to lower case</li>
+ * <li>get the actual key that corresponds to the lower case key</li>
+ * <li>query the map with the actual key</li>
+ * </ul>
+ * </p>
+ */
+ private final Map<String,String> lowerCaseMap = new HashMap<String,String>();
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
- private static final long serialVersionUID = 1841673097701957808L;
+ private static final long serialVersionUID = -2848100435296897392L;
/**
* @see java.util.Map#containsKey(java.lang.Object)
*/
@Override
public boolean containsKey(Object key) {
- return super.containsKey(key.toString().toLowerCase());
+ Object realKey = lowerCaseMap.get(key.toString().toLowerCase());
+ return super.containsKey(realKey);
+ // Possible optimisation here:
+ // Since the lowerCaseMap contains a mapping for all the keys,
+ // we could just do this:
+ // return lowerCaseMap.containsKey(key.toString().toLowerCase());
}
/**
@@ -166,7 +196,8 @@
*/
@Override
public Object get(Object key) {
- return super.get(key.toString().toLowerCase());
+ Object realKey = lowerCaseMap.get(key.toString().toLowerCase());
+ return super.get(realKey);
}
/**
@@ -174,16 +205,27 @@
*/
@Override
public Object put(String key, Object value) {
- return super.put(key.toLowerCase(), value);
+ /*
+ * In order to keep the map and lowerCaseMap synchronized,
+ * we have to remove the old mapping before putting the
+ * new one. Indeed, oldKey and key are not necessaliry equals.
+ * (That's why we call super.remove(oldKey) and not just
+ * super.put(key, value))
+ */
+ Object oldKey = lowerCaseMap.put(key.toString().toLowerCase(), key);
+ Object oldValue = super.remove(oldKey);
+ super.put(key, value);
+ return oldValue;
}
/**
* @see java.util.Map#putAll(java.util.Map)
*/
@Override
- public void putAll(Map<? extends String, ?> m) {
- for (String key : m.keySet()) {
- Object value = m.get(key);
+ public void putAll(Map<? extends String,?> m) {
+ for (Map.Entry<? extends String, ?> entry : m.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
this.put(key, value);
}
}
@@ -193,7 +235,8 @@
*/
@Override
public Object remove(Object key) {
- return super.remove(key.toString().toLowerCase());
+ Object realKey = lowerCaseMap.remove(key.toString().toLowerCase());
+ return super.remove(realKey);
}
}
Modified: commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/BeanProcessor.java
URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/BeanProcessor.java?rev=743297&r1=743296&r2=743297&view=diff
==============================================================================
--- commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/BeanProcessor.java (original)
+++ commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/BeanProcessor.java Wed Feb 11 10:59:15 2009
@@ -432,7 +432,11 @@
*/
protected Object processColumn(ResultSet rs, int index, Class<?> propType)
throws SQLException {
-
+
+ if ( !propType.isPrimitive() && rs.getObject(index) == null ) {
+ return null;
+ }
+
if (propType.equals(String.class)) {
return rs.getString(index);
Modified: commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/QueryRunner.java
URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/QueryRunner.java?rev=743297&r1=743296&r2=743297&view=diff
==============================================================================
--- commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/QueryRunner.java (original)
+++ commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/QueryRunner.java Wed Feb 11 10:59:15 2009
@@ -16,7 +16,11 @@
*/
package org.apache.commons.dbutils;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
import java.sql.Connection;
+import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -35,6 +39,11 @@
public class QueryRunner {
/**
+ * Is {@link ParameterMetaData#getParameterType(int)} broken (have we tried it yet)?
+ */
+ private volatile boolean pmdKnownBroken = false;
+
+ /**
* The DataSource to retrieve connections from.
*/
protected DataSource ds = null;
@@ -47,7 +56,18 @@
}
/**
- * Constructor for QueryRunner. Methods that do not take a
+ * Constructor for QueryRunner, allows workaround for Oracle drivers
+ * @param pmdKnownBroken Oracle drivers don't support {@link ParameterMetaData#getParameterType(int) };
+ * if <code>pmdKnownBroken</code> is set to true, we won't even try it; if false, we'll try it,
+ * and if it breaks, we'll remember not to use it again.
+ */
+ public QueryRunner(boolean pmdKnownBroken) {
+ super();
+ this.pmdKnownBroken = pmdKnownBroken;
+ }
+
+ /**
+ * Constructor for QueryRunner, allows workaround for Oracle drivers. Methods that do not take a
* <code>Connection</code> parameter will retrieve connections from this
* <code>DataSource</code>.
*
@@ -59,6 +79,22 @@
}
/**
+ * Constructor for QueryRunner, allows workaround for Oracle drivers. Methods that do not take a
+ * <code>Connection</code> parameter will retrieve connections from this
+ * <code>DataSource</code>.
+ *
+ * @param ds The <code>DataSource</code> to retrieve connections from.
+ * @param pmdKnownBroken Oracle drivers don't support {@link ParameterMetaData#getParameterType(int) };
+ * if <code>pmdKnownBroken</code> is set to true, we won't even try it; if false, we'll try it,
+ * and if it breaks, we'll remember not to use it again.
+ */
+ public QueryRunner(DataSource ds, boolean pmdKnownBroken) {
+ super();
+ this.pmdKnownBroken = pmdKnownBroken;
+ setDataSource(ds);
+ }
+
+ /**
* Execute a batch of SQL INSERT, UPDATE, or DELETE queries.
*
* @param conn The Connection to use to run the query. The caller is
@@ -124,13 +160,18 @@
* value to pass in.
* @throws SQLException if a database access error occurs
*/
- protected void fillStatement(PreparedStatement stmt, Object... params)
+ public void fillStatement(PreparedStatement stmt, Object... params)
throws SQLException {
if (params == null) {
return;
}
-
+
+ ParameterMetaData pmd = stmt.getParameterMetaData();
+ if (pmd.getParameterCount() < params.length) {
+ throw new SQLException("Too many parameters: expected "
+ + pmd.getParameterCount() + ", was given " + params.length);
+ }
for (int i = 0; i < params.length; i++) {
if (params[i] != null) {
stmt.setObject(i + 1, params[i]);
@@ -138,9 +179,98 @@
// VARCHAR works with many drivers regardless
// of the actual column type. Oddly, NULL and
// OTHER don't work with Oracle's drivers.
- stmt.setNull(i + 1, Types.VARCHAR);
+ int sqlType = Types.VARCHAR;
+ if (!pmdKnownBroken) {
+ try {
+ sqlType = pmd.getParameterType(i + 1);
+ } catch (SQLException e) {
+ pmdKnownBroken = true;
+ }
+ }
+ stmt.setNull(i + 1, sqlType);
+ }
+ }
+ }
+
+ /**
+ * Fill the <code>PreparedStatement</code> replacement parameters with the
+ * given object's bean property values.
+ *
+ * @param stmt
+ * PreparedStatement to fill
+ * @param bean
+ * a JavaBean object
+ * @param properties
+ * an ordered array of properties; this gives the order to insert
+ * values in the statement
+ * @throws SQLException
+ * if a database access error occurs
+ */
+ public void fillStatementWithBean(PreparedStatement stmt, Object bean,
+ PropertyDescriptor[] properties) throws SQLException {
+ Object[] params = new Object[properties.length];
+ for (int i = 0; i < properties.length; i++) {
+ PropertyDescriptor property = properties[i];
+ Object value = null;
+ try {
+ if (property.getReadMethod().getParameterTypes().length > 0) {
+ throw new SQLException(
+ "Can't use an indexed bean property as a SQL parameter: "
+ + property.getName());
+ }
+ value = property.getReadMethod().invoke(bean, new Object[0]);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ params[i] = value;
+ }
+ fillStatement(stmt, params);
+ }
+
+ /**
+ * Fill the <code>PreparedStatement</code> replacement parameters with the
+ * given object's bean property values.
+ *
+ * @param stmt
+ * PreparedStatement to fill
+ * @param bean
+ * a JavaBean object
+ * @param propertyNames
+ * an ordered array of property names (these should match the
+ * getters/setters); this gives the order to insert values in the
+ * statement
+ * @throws SQLException
+ * if a database access error occurs
+ */
+ public void fillStatementWithBean(PreparedStatement stmt, Object bean,
+ String... propertyNames) throws SQLException {
+ PropertyDescriptor[] descriptors;
+ try {
+ descriptors = Introspector.getBeanInfo(bean.getClass())
+ .getPropertyDescriptors();
+ } catch (IntrospectionException e) {
+ throw new RuntimeException(e);
+ }
+ PropertyDescriptor[] sorted = new PropertyDescriptor[propertyNames.length];
+ for (int i = 0; i < propertyNames.length; i++) {
+ String propertyName = propertyNames[i];
+ if (propertyName == null)
+ throw new NullPointerException("propertyName can't be null: "
+ + i);
+ boolean found = false;
+ for (int j = 0; j < descriptors.length; j++) {
+ PropertyDescriptor descriptor = descriptors[j];
+ if (propertyName.equals(descriptor.getName())) {
+ sorted[i] = descriptor;
+ found = true;
+ break;
+ }
}
+ if (!found)
+ throw new RuntimeException("Couldn't find bean property: "
+ + bean.getClass() + " " + propertyName);
}
+ fillStatementWithBean(stmt, bean, sorted);
}
/**
@@ -382,7 +512,9 @@
protected void rethrow(SQLException cause, String sql, Object... params)
throws SQLException {
- StringBuffer msg = new StringBuffer(cause.getMessage());
+ String causeMessage = cause.getMessage();
+ if (causeMessage == null) causeMessage = "";
+ StringBuffer msg = new StringBuffer(causeMessage);
msg.append(" Query: ");
msg.append(sql);
Copied: commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java (from r743293, commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java)
URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java?p2=commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java&p1=commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java&r1=743293&r2=743297&rev=743297&view=diff
==============================================================================
--- commons/sandbox/dbutils/bugfixing/src/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java (original)
+++ commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java Wed Feb 11 10:59:15 2009
@@ -29,7 +29,7 @@
*
* @see org.apache.commons.dbutils.ResultSetHandler
*/
-public abstract class AbstractListHandler implements ResultSetHandler {
+public abstract class AbstractListHandler<T> implements ResultSetHandler<List<T>> {
/**
* Whole <code>ResultSet</code> handler. It produce <code>List</code> as
* result. To convert individual rows into Java objects it uses
@@ -37,8 +37,8 @@
*
* @see #handleRow(ResultSet)
*/
- public Object handle(ResultSet rs) throws SQLException {
- List rows = new ArrayList();
+ public List<T> handle(ResultSet rs) throws SQLException {
+ List<T> rows = new ArrayList<T>();
while (rs.next()) {
rows.add(this.handleRow(rs));
}
@@ -52,5 +52,5 @@
* @return row processing result
* @throws SQLException error occurs
*/
- protected abstract Object handleRow(ResultSet rs) throws SQLException;
+ protected abstract T handleRow(ResultSet rs) throws SQLException;
}
Modified: commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/ArrayListHandler.java
URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/ArrayListHandler.java?rev=743297&r1=743296&r2=743297&view=diff
==============================================================================
--- commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/ArrayListHandler.java (original)
+++ commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/ArrayListHandler.java Wed Feb 11 10:59:15 2009
@@ -28,7 +28,7 @@
*
* @see org.apache.commons.dbutils.ResultSetHandler
*/
-public class ArrayListHandler extends GenericListHandler<Object[]> {
+public class ArrayListHandler extends AbstractListHandler<Object[]> {
/**
* The RowProcessor implementation to use when converting rows
@@ -62,7 +62,7 @@
* @return <code>Object[]</code>, never <code>null</code>.
*
* @throws SQLException if a database access error occurs
- * @see org.apache.commons.dbutils.handlers.GenericListHandler#handle(ResultSet)
+ * @see org.apache.commons.dbutils.handlers.AbstractListHandler#handle(ResultSet)
*/
protected Object[] handleRow(ResultSet rs) throws SQLException {
return this.convert.toArray(rs);
Modified: commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/BeanListHandler.java
URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/BeanListHandler.java?rev=743297&r1=743296&r2=743297&view=diff
==============================================================================
--- commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/BeanListHandler.java (original)
+++ commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/BeanListHandler.java Wed Feb 11 10:59:15 2009
@@ -18,7 +18,9 @@
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.List;
+import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.RowProcessor;
/**
@@ -28,7 +30,7 @@
*
* @see org.apache.commons.dbutils.ResultSetHandler
*/
-public class BeanListHandler<T> extends GenericListHandler<T> {
+public class BeanListHandler<T> implements ResultSetHandler<List<T>> {
/**
* The Class of beans produced by this handler.
@@ -65,16 +67,17 @@
}
/**
- * Convert the <code>ResultSet</code> row into a bean with
+ * Convert the whole <code>ResultSet</code> into a List of beans with
* the <code>Class</code> given in the constructor.
*
- * @return A bean, never <code>null</code>.
+ * @param rs The <code>ResultSet</code> to handle.
+ *
+ * @return A List of beans, never <code>null</code>.
*
* @throws SQLException if a database access error occurs
- * @see org.apache.commons.dbutils.handlers.GenericListHandler#handle(ResultSet)
+ * @see org.apache.commons.dbutils.RowProcessor#toBeanList(ResultSet, Class)
*/
- protected T handleRow(ResultSet rs) throws SQLException {
- return this.convert.toBean(rs, type);
+ public List<T> handle(ResultSet rs) throws SQLException {
+ return this.convert.toBeanList(rs, type);
}
-
}
Modified: commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/ColumnListHandler.java
URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/ColumnListHandler.java?rev=743297&r1=743296&r2=743297&view=diff
==============================================================================
--- commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/ColumnListHandler.java (original)
+++ commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/ColumnListHandler.java Wed Feb 11 10:59:15 2009
@@ -27,7 +27,7 @@
* @see org.apache.commons.dbutils.ResultSetHandler
* @since DbUtils 1.1
*/
-public class ColumnListHandler extends GenericListHandler<Object> {
+public class ColumnListHandler extends AbstractListHandler<Object> {
/**
* The column number to retrieve.
@@ -75,7 +75,7 @@
*
* @throws SQLException if a database access error occurs
*
- * @see org.apache.commons.dbutils.handlers.GenericListHandler#handle(ResultSet)
+ * @see org.apache.commons.dbutils.handlers.AbstractListHandler#handle(ResultSet)
*/
protected Object handleRow(ResultSet rs) throws SQLException {
if (this.columnName == null) {
Modified: commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/MapListHandler.java
URL: http://svn.apache.org/viewvc/commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/MapListHandler.java?rev=743297&r1=743296&r2=743297&view=diff
==============================================================================
--- commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/MapListHandler.java (original)
+++ commons/sandbox/dbutils/java5/src/java/org/apache/commons/dbutils/handlers/MapListHandler.java Wed Feb 11 10:59:15 2009
@@ -29,7 +29,7 @@
*
* @see org.apache.commons.dbutils.ResultSetHandler
*/
-public class MapListHandler extends GenericListHandler<Map<String,Object>> {
+public class MapListHandler extends AbstractListHandler<Map<String,Object>> {
/**
* The RowProcessor implementation to use when converting rows
@@ -63,7 +63,7 @@
*
* @throws SQLException if a database access error occurs
*
- * @see org.apache.commons.dbutils.handlers.GenericListHandler#handle(ResultSet)
+ * @see org.apache.commons.dbutils.handlers.AbstractListHandler#handle(ResultSet)
*/
protected Map<String,Object> handleRow(ResultSet rs) throws SQLException {
return this.convert.toMap(rs);