You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2018/05/04 20:25:45 UTC
commons-dbutils git commit: [DBUTILS-139] Update Java requirement
from version 6 to 7. Remove redundant specification of type arguments.
Repository: commons-dbutils
Updated Branches:
refs/heads/master 298f30f93 -> 141238598
[DBUTILS-139] Update Java requirement from version 6 to 7. Remove
redundant specification of type arguments.
Project: http://git-wip-us.apache.org/repos/asf/commons-dbutils/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-dbutils/commit/14123859
Tree: http://git-wip-us.apache.org/repos/asf/commons-dbutils/tree/14123859
Diff: http://git-wip-us.apache.org/repos/asf/commons-dbutils/diff/14123859
Branch: refs/heads/master
Commit: 1412385988b5b384f1615dab820b62ff7ff4a835
Parents: 298f30f
Author: Gary Gregory <ga...@gmail.com>
Authored: Fri May 4 14:25:42 2018 -0600
Committer: Gary Gregory <ga...@gmail.com>
Committed: Fri May 4 14:25:42 2018 -0600
----------------------------------------------------------------------
.../commons/dbutils/BasicRowProcessor.java | 2 +-
.../apache/commons/dbutils/BeanProcessor.java | 1068 +++++++++---------
.../org/apache/commons/dbutils/QueryLoader.java | 2 +-
.../org/apache/commons/dbutils/QueryRunner.java | 2 +-
.../dbutils/handlers/AbstractKeyedHandler.java | 2 +-
.../dbutils/handlers/AbstractListHandler.java | 2 +-
.../wrappers/SqlNullCheckedResultSet.java | 2 +-
7 files changed, 540 insertions(+), 540 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/14123859/src/main/java/org/apache/commons/dbutils/BasicRowProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils/BasicRowProcessor.java b/src/main/java/org/apache/commons/dbutils/BasicRowProcessor.java
index fa0db45..e8a3e9d 100644
--- a/src/main/java/org/apache/commons/dbutils/BasicRowProcessor.java
+++ b/src/main/java/org/apache/commons/dbutils/BasicRowProcessor.java
@@ -212,7 +212,7 @@ public class BasicRowProcessor implements RowProcessor {
* </ul>
* </p>
*/
- private final Map<String, String> lowerCaseMap = new HashMap<String, String>();
+ private final Map<String, String> lowerCaseMap = new HashMap<>();
/**
* Required for serialization support.
http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/14123859/src/main/java/org/apache/commons/dbutils/BeanProcessor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils/BeanProcessor.java b/src/main/java/org/apache/commons/dbutils/BeanProcessor.java
index b15920f..df361fe 100644
--- a/src/main/java/org/apache/commons/dbutils/BeanProcessor.java
+++ b/src/main/java/org/apache/commons/dbutils/BeanProcessor.java
@@ -1,534 +1,534 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.dbutils;
-
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.ServiceLoader;
-
-/**
- * <p>
- * <code>BeanProcessor</code> matches column names to bean property names
- * and converts <code>ResultSet</code> columns into objects for those bean
- * properties. Subclasses should override the methods in the processing chain
- * to customize behavior.
- * </p>
- *
- * <p>
- * This class is thread-safe.
- * </p>
- *
- * @see BasicRowProcessor
- *
- * @since DbUtils 1.1
- */
-public class BeanProcessor {
-
- /**
- * Special array value used by <code>mapColumnsToProperties</code> that
- * indicates there is no bean property that matches a column from a
- * <code>ResultSet</code>.
- */
- protected static final int PROPERTY_NOT_FOUND = -1;
-
- /**
- * Set a bean's primitive properties to these defaults when SQL NULL
- * is returned. These are the same as the defaults that ResultSet get*
- * methods return in the event of a NULL column.
- */
- private static final Map<Class<?>, Object> primitiveDefaults = new HashMap<Class<?>, Object>();
-
- private static final List<ColumnHandler> columnHandlers = new ArrayList<ColumnHandler>();
-
- private static final List<PropertyHandler> propertyHandlers = new ArrayList<PropertyHandler>();
-
- /**
- * ResultSet column to bean property name overrides.
- */
- private final Map<String, String> columnToPropertyOverrides;
-
- static {
- primitiveDefaults.put(Integer.TYPE, Integer.valueOf(0));
- primitiveDefaults.put(Short.TYPE, Short.valueOf((short) 0));
- primitiveDefaults.put(Byte.TYPE, Byte.valueOf((byte) 0));
- primitiveDefaults.put(Float.TYPE, Float.valueOf(0f));
- primitiveDefaults.put(Double.TYPE, Double.valueOf(0d));
- primitiveDefaults.put(Long.TYPE, Long.valueOf(0L));
- primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE);
- primitiveDefaults.put(Character.TYPE, Character.valueOf((char) 0));
-
- // Use a ServiceLoader to find implementations
- for (ColumnHandler handler : ServiceLoader.load(ColumnHandler.class)) {
- columnHandlers.add(handler);
- }
-
- // Use a ServiceLoader to find implementations
- for (PropertyHandler handler : ServiceLoader.load(PropertyHandler.class)) {
- propertyHandlers.add(handler);
- }
- }
-
- /**
- * Constructor for BeanProcessor.
- */
- public BeanProcessor() {
- this(new HashMap<String, String>());
- }
-
- /**
- * Constructor for BeanProcessor configured with column to property name overrides.
- *
- * @param columnToPropertyOverrides ResultSet column to bean property name overrides
- * @since 1.5
- */
- public BeanProcessor(Map<String, String> columnToPropertyOverrides) {
- super();
- if (columnToPropertyOverrides == null) {
- throw new IllegalArgumentException("columnToPropertyOverrides map cannot be null");
- }
- this.columnToPropertyOverrides = columnToPropertyOverrides;
- }
-
- /**
- * Convert a <code>ResultSet</code> row into a JavaBean. This
- * implementation uses reflection and <code>BeanInfo</code> classes to
- * match column names to bean property names. Properties are matched to
- * columns based on several factors:
- * <br/>
- * <ol>
- * <li>
- * The class has a writable property with the same name as a column.
- * The name comparison is case insensitive.
- * </li>
- *
- * <li>
- * The column type can be converted to the property's set method
- * parameter type with a ResultSet.get* method. If the conversion fails
- * (ie. the property was an int and the column was a Timestamp) an
- * SQLException is thrown.
- * </li>
- * </ol>
- *
- * <p>
- * Primitive bean properties are set to their defaults when SQL NULL is
- * returned from the <code>ResultSet</code>. Numeric fields are set to 0
- * and booleans are set to false. Object bean properties are set to
- * <code>null</code> when SQL NULL is returned. This is the same behavior
- * as the <code>ResultSet</code> get* methods.
- * </p>
- * @param <T> The type of bean to create
- * @param rs ResultSet that supplies the bean data
- * @param type Class from which to create the bean instance
- * @throws SQLException if a database access error occurs
- * @return the newly created bean
- */
- public <T> T toBean(ResultSet rs, Class<? extends T> type) throws SQLException {
- T bean = this.newInstance(type);
- return this.populateBean(rs, bean);
- }
-
- /**
- * Convert a <code>ResultSet</code> into a <code>List</code> of JavaBeans.
- * This implementation uses reflection and <code>BeanInfo</code> classes to
- * match column names to bean property names. Properties are matched to
- * columns based on several factors:
- * <br/>
- * <ol>
- * <li>
- * The class has a writable property with the same name as a column.
- * The name comparison is case insensitive.
- * </li>
- *
- * <li>
- * The column type can be converted to the property's set method
- * parameter type with a ResultSet.get* method. If the conversion fails
- * (ie. the property was an int and the column was a Timestamp) an
- * SQLException is thrown.
- * </li>
- * </ol>
- *
- * <p>
- * Primitive bean properties are set to their defaults when SQL NULL is
- * returned from the <code>ResultSet</code>. Numeric fields are set to 0
- * and booleans are set to false. Object bean properties are set to
- * <code>null</code> when SQL NULL is returned. This is the same behavior
- * as the <code>ResultSet</code> get* methods.
- * </p>
- * @param <T> The type of bean to create
- * @param rs ResultSet that supplies the bean data
- * @param type Class from which to create the bean instance
- * @throws SQLException if a database access error occurs
- * @return the newly created List of beans
- */
- public <T> List<T> toBeanList(ResultSet rs, Class<? extends T> type) throws SQLException {
- List<T> results = new ArrayList<T>();
-
- if (!rs.next()) {
- return results;
- }
-
- PropertyDescriptor[] props = this.propertyDescriptors(type);
- ResultSetMetaData rsmd = rs.getMetaData();
- int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
-
- do {
- results.add(this.createBean(rs, type, props, columnToProperty));
- } while (rs.next());
-
- return results;
- }
-
- /**
- * Creates a new object and initializes its fields from the ResultSet.
- * @param <T> The type of bean to create
- * @param rs The result set.
- * @param type The bean type (the return type of the object).
- * @param props The property descriptors.
- * @param columnToProperty The column indices in the result set.
- * @return An initialized object.
- * @throws SQLException if a database error occurs.
- */
- private <T> T createBean(ResultSet rs, Class<T> type,
- PropertyDescriptor[] props, int[] columnToProperty)
- throws SQLException {
-
- T bean = this.newInstance(type);
- return populateBean(rs, bean, props, columnToProperty);
- }
-
- /**
- * Initializes the fields of the provided bean from the ResultSet.
- * @param <T> The type of bean
- * @param rs The result set.
- * @param bean The bean to be populated.
- * @return An initialized object.
- * @throws SQLException if a database error occurs.
- */
- public <T> T populateBean(ResultSet rs, T bean) throws SQLException {
- PropertyDescriptor[] props = this.propertyDescriptors(bean.getClass());
- ResultSetMetaData rsmd = rs.getMetaData();
- int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
-
- return populateBean(rs, bean, props, columnToProperty);
- }
-
- /**
- * This method populates a bean from the ResultSet based upon the underlying meta-data.
- *
- * @param <T> The type of bean
- * @param rs The result set.
- * @param bean The bean to be populated.
- * @param props The property descriptors.
- * @param columnToProperty The column indices in the result set.
- * @return An initialized object.
- * @throws SQLException if a database error occurs.
- */
- private <T> T populateBean(ResultSet rs, T bean,
- PropertyDescriptor[] props, int[] columnToProperty)
- throws SQLException {
-
- for (int i = 1; i < columnToProperty.length; i++) {
-
- if (columnToProperty[i] == PROPERTY_NOT_FOUND) {
- continue;
- }
-
- PropertyDescriptor prop = props[columnToProperty[i]];
- Class<?> propType = prop.getPropertyType();
-
- Object value = null;
- if(propType != null) {
- value = this.processColumn(rs, i, propType);
-
- if (value == null && propType.isPrimitive()) {
- value = primitiveDefaults.get(propType);
- }
- }
-
- this.callSetter(bean, prop, value);
- }
-
- return bean;
- }
-
- /**
- * Calls the setter method on the target object for the given property.
- * If no setter method exists for the property, this method does nothing.
- * @param target The object to set the property on.
- * @param prop The property to set.
- * @param value The value to pass into the setter.
- * @throws SQLException if an error occurs setting the property.
- */
- private void callSetter(Object target, PropertyDescriptor prop, Object value)
- throws SQLException {
-
- Method setter = getWriteMethod(target, prop, value);
-
- if (setter == null || setter.getParameterTypes().length != 1) {
- return;
- }
-
- try {
- Class<?> firstParam = setter.getParameterTypes()[0];
- for (PropertyHandler handler : propertyHandlers) {
- if (handler.match(firstParam, value)) {
- value = handler.apply(firstParam, value);
- break;
- }
- }
-
- // Don't call setter if the value object isn't the right type
- if (this.isCompatibleType(value, firstParam)) {
- setter.invoke(target, new Object[]{value});
- } else {
- throw new SQLException(
- "Cannot set " + prop.getName() + ": incompatible types, cannot convert "
- + value.getClass().getName() + " to " + firstParam.getName());
- // value cannot be null here because isCompatibleType allows null
- }
-
- } catch (IllegalArgumentException e) {
- throw new SQLException(
- "Cannot set " + prop.getName() + ": " + e.getMessage());
-
- } catch (IllegalAccessException e) {
- throw new SQLException(
- "Cannot set " + prop.getName() + ": " + e.getMessage());
-
- } catch (InvocationTargetException e) {
- throw new SQLException(
- "Cannot set " + prop.getName() + ": " + e.getMessage());
- }
- }
-
- /**
- * ResultSet.getObject() returns an Integer object for an INT column. The
- * setter method for the property might take an Integer or a primitive int.
- * This method returns true if the value can be successfully passed into
- * the setter method. Remember, Method.invoke() handles the unwrapping
- * of Integer into an int.
- *
- * @param value The value to be passed into the setter method.
- * @param type The setter's parameter type (non-null)
- * @return boolean True if the value is compatible (null => true)
- */
- private boolean isCompatibleType(Object value, Class<?> type) {
- // Do object check first, then primitives
- if (value == null || type.isInstance(value) || matchesPrimitive(type, value.getClass())) {
- return true;
-
- }
- return false;
-
- }
-
- /**
- * Check whether a value is of the same primitive type as <code>targetType</code>.
- *
- * @param targetType The primitive type to target.
- * @param valueType The value to match to the primitive type.
- * @return Whether <code>valueType</code> can be coerced (e.g. autoboxed) into <code>targetType</code>.
- */
- private boolean matchesPrimitive(Class<?> targetType, Class<?> valueType) {
- if (!targetType.isPrimitive()) {
- return false;
- }
-
- try {
- // see if there is a "TYPE" field. This is present for primitive wrappers.
- Field typeField = valueType.getField("TYPE");
- Object primitiveValueType = typeField.get(valueType);
-
- if (targetType == primitiveValueType) {
- return true;
- }
- } catch (NoSuchFieldException e) {
- // lacking the TYPE field is a good sign that we're not working with a primitive wrapper.
- // we can't match for compatibility
- } catch (IllegalAccessException e) {
- // an inaccessible TYPE field is a good sign that we're not working with a primitive wrapper.
- // nothing to do. we can't match for compatibility
- }
- return false;
- }
-
- /**
- * Get the write method to use when setting {@code value} to the {@code target}.
- *
- * @param target Object where the write method will be called.
- * @param prop BeanUtils information.
- * @param value The value that will be passed to the write method.
- * @return The {@link java.lang.reflect.Method} to call on {@code target} to write {@code value} or {@code null} if
- * there is no suitable write method.
- */
- protected Method getWriteMethod(Object target, PropertyDescriptor prop, Object value) {
- Method method = prop.getWriteMethod();
- return method;
- }
-
- /**
- * Factory method that returns a new instance of the given Class. This
- * is called at the start of the bean creation process and may be
- * overridden to provide custom behavior like returning a cached bean
- * instance.
- * @param <T> The type of object to create
- * @param c The Class to create an object from.
- * @return A newly created object of the Class.
- * @throws SQLException if creation failed.
- */
- protected <T> T newInstance(Class<T> c) throws SQLException {
- try {
- return c.newInstance();
-
- } catch (InstantiationException e) {
- throw new SQLException(
- "Cannot create " + c.getName() + ": " + e.getMessage());
-
- } catch (IllegalAccessException e) {
- throw new SQLException(
- "Cannot create " + c.getName() + ": " + e.getMessage());
- }
- }
-
- /**
- * Returns a PropertyDescriptor[] for the given Class.
- *
- * @param c The Class to retrieve PropertyDescriptors for.
- * @return A PropertyDescriptor[] describing the Class.
- * @throws SQLException if introspection failed.
- */
- private PropertyDescriptor[] propertyDescriptors(Class<?> c)
- throws SQLException {
- // Introspector caches BeanInfo classes for better performance
- BeanInfo beanInfo = null;
- try {
- beanInfo = Introspector.getBeanInfo(c);
-
- } catch (IntrospectionException e) {
- throw new SQLException(
- "Bean introspection failed: " + e.getMessage());
- }
-
- return beanInfo.getPropertyDescriptors();
- }
-
- /**
- * The positions in the returned array represent column numbers. The
- * values stored at each position represent the index in the
- * <code>PropertyDescriptor[]</code> for the bean property that matches
- * the column name. If no bean property was found for a column, the
- * position is set to <code>PROPERTY_NOT_FOUND</code>.
- *
- * @param rsmd The <code>ResultSetMetaData</code> containing column
- * information.
- *
- * @param props The bean property descriptors.
- *
- * @throws SQLException if a database access error occurs
- *
- * @return An int[] with column index to property index mappings. The 0th
- * element is meaningless because JDBC column indexing starts at 1.
- */
- protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
- PropertyDescriptor[] props) throws SQLException {
-
- int cols = rsmd.getColumnCount();
- int[] columnToProperty = new int[cols + 1];
- Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
-
- for (int col = 1; col <= cols; col++) {
- String columnName = rsmd.getColumnLabel(col);
- if (null == columnName || 0 == columnName.length()) {
- columnName = rsmd.getColumnName(col);
- }
- String propertyName = columnToPropertyOverrides.get(columnName);
- if (propertyName == null) {
- propertyName = columnName;
- }
- for (int i = 0; i < props.length; i++) {
-
- if (propertyName.equalsIgnoreCase(props[i].getName())) {
- columnToProperty[col] = i;
- break;
- }
- }
- }
-
- return columnToProperty;
- }
-
- /**
- * Convert a <code>ResultSet</code> column into an object. Simple
- * implementations could just call <code>rs.getObject(index)</code> while
- * more complex implementations could perform type manipulation to match
- * the column's type to the bean property type.
- *
- * <p>
- * This implementation calls the appropriate <code>ResultSet</code> getter
- * method for the given property type to perform the type conversion. If
- * the property type doesn't match one of the supported
- * <code>ResultSet</code> types, <code>getObject</code> is called.
- * </p>
- *
- * @param rs The <code>ResultSet</code> currently being processed. It is
- * positioned on a valid row before being passed into this method.
- *
- * @param index The current column index being processed.
- *
- * @param propType The bean property type that this column needs to be
- * converted into.
- *
- * @throws SQLException if a database access error occurs
- *
- * @return The object from the <code>ResultSet</code> at the given column
- * index after optional type processing or <code>null</code> if the column
- * value was SQL NULL.
- */
- protected Object processColumn(ResultSet rs, int index, Class<?> propType)
- throws SQLException {
-
- Object retval = rs.getObject(index);
-
- if ( !propType.isPrimitive() && retval == null ) {
- return null;
- }
-
- for (ColumnHandler handler : columnHandlers) {
- if (handler.match(propType)) {
- retval = handler.apply(rs, index);
- break;
- }
- }
-
- return retval;
-
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.dbutils;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+/**
+ * <p>
+ * <code>BeanProcessor</code> matches column names to bean property names
+ * and converts <code>ResultSet</code> columns into objects for those bean
+ * properties. Subclasses should override the methods in the processing chain
+ * to customize behavior.
+ * </p>
+ *
+ * <p>
+ * This class is thread-safe.
+ * </p>
+ *
+ * @see BasicRowProcessor
+ *
+ * @since DbUtils 1.1
+ */
+public class BeanProcessor {
+
+ /**
+ * Special array value used by <code>mapColumnsToProperties</code> that
+ * indicates there is no bean property that matches a column from a
+ * <code>ResultSet</code>.
+ */
+ protected static final int PROPERTY_NOT_FOUND = -1;
+
+ /**
+ * Set a bean's primitive properties to these defaults when SQL NULL
+ * is returned. These are the same as the defaults that ResultSet get*
+ * methods return in the event of a NULL column.
+ */
+ private static final Map<Class<?>, Object> primitiveDefaults = new HashMap<>();
+
+ private static final List<ColumnHandler> columnHandlers = new ArrayList<>();
+
+ private static final List<PropertyHandler> propertyHandlers = new ArrayList<>();
+
+ /**
+ * ResultSet column to bean property name overrides.
+ */
+ private final Map<String, String> columnToPropertyOverrides;
+
+ static {
+ primitiveDefaults.put(Integer.TYPE, Integer.valueOf(0));
+ primitiveDefaults.put(Short.TYPE, Short.valueOf((short) 0));
+ primitiveDefaults.put(Byte.TYPE, Byte.valueOf((byte) 0));
+ primitiveDefaults.put(Float.TYPE, Float.valueOf(0f));
+ primitiveDefaults.put(Double.TYPE, Double.valueOf(0d));
+ primitiveDefaults.put(Long.TYPE, Long.valueOf(0L));
+ primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE);
+ primitiveDefaults.put(Character.TYPE, Character.valueOf((char) 0));
+
+ // Use a ServiceLoader to find implementations
+ for (ColumnHandler handler : ServiceLoader.load(ColumnHandler.class)) {
+ columnHandlers.add(handler);
+ }
+
+ // Use a ServiceLoader to find implementations
+ for (PropertyHandler handler : ServiceLoader.load(PropertyHandler.class)) {
+ propertyHandlers.add(handler);
+ }
+ }
+
+ /**
+ * Constructor for BeanProcessor.
+ */
+ public BeanProcessor() {
+ this(new HashMap<String, String>());
+ }
+
+ /**
+ * Constructor for BeanProcessor configured with column to property name overrides.
+ *
+ * @param columnToPropertyOverrides ResultSet column to bean property name overrides
+ * @since 1.5
+ */
+ public BeanProcessor(Map<String, String> columnToPropertyOverrides) {
+ super();
+ if (columnToPropertyOverrides == null) {
+ throw new IllegalArgumentException("columnToPropertyOverrides map cannot be null");
+ }
+ this.columnToPropertyOverrides = columnToPropertyOverrides;
+ }
+
+ /**
+ * Convert a <code>ResultSet</code> row into a JavaBean. This
+ * implementation uses reflection and <code>BeanInfo</code> classes to
+ * match column names to bean property names. Properties are matched to
+ * columns based on several factors:
+ * <br/>
+ * <ol>
+ * <li>
+ * The class has a writable property with the same name as a column.
+ * The name comparison is case insensitive.
+ * </li>
+ *
+ * <li>
+ * The column type can be converted to the property's set method
+ * parameter type with a ResultSet.get* method. If the conversion fails
+ * (ie. the property was an int and the column was a Timestamp) an
+ * SQLException is thrown.
+ * </li>
+ * </ol>
+ *
+ * <p>
+ * Primitive bean properties are set to their defaults when SQL NULL is
+ * returned from the <code>ResultSet</code>. Numeric fields are set to 0
+ * and booleans are set to false. Object bean properties are set to
+ * <code>null</code> when SQL NULL is returned. This is the same behavior
+ * as the <code>ResultSet</code> get* methods.
+ * </p>
+ * @param <T> The type of bean to create
+ * @param rs ResultSet that supplies the bean data
+ * @param type Class from which to create the bean instance
+ * @throws SQLException if a database access error occurs
+ * @return the newly created bean
+ */
+ public <T> T toBean(ResultSet rs, Class<? extends T> type) throws SQLException {
+ T bean = this.newInstance(type);
+ return this.populateBean(rs, bean);
+ }
+
+ /**
+ * Convert a <code>ResultSet</code> into a <code>List</code> of JavaBeans.
+ * This implementation uses reflection and <code>BeanInfo</code> classes to
+ * match column names to bean property names. Properties are matched to
+ * columns based on several factors:
+ * <br/>
+ * <ol>
+ * <li>
+ * The class has a writable property with the same name as a column.
+ * The name comparison is case insensitive.
+ * </li>
+ *
+ * <li>
+ * The column type can be converted to the property's set method
+ * parameter type with a ResultSet.get* method. If the conversion fails
+ * (ie. the property was an int and the column was a Timestamp) an
+ * SQLException is thrown.
+ * </li>
+ * </ol>
+ *
+ * <p>
+ * Primitive bean properties are set to their defaults when SQL NULL is
+ * returned from the <code>ResultSet</code>. Numeric fields are set to 0
+ * and booleans are set to false. Object bean properties are set to
+ * <code>null</code> when SQL NULL is returned. This is the same behavior
+ * as the <code>ResultSet</code> get* methods.
+ * </p>
+ * @param <T> The type of bean to create
+ * @param rs ResultSet that supplies the bean data
+ * @param type Class from which to create the bean instance
+ * @throws SQLException if a database access error occurs
+ * @return the newly created List of beans
+ */
+ public <T> List<T> toBeanList(ResultSet rs, Class<? extends T> type) throws SQLException {
+ List<T> results = new ArrayList<>();
+
+ if (!rs.next()) {
+ return results;
+ }
+
+ PropertyDescriptor[] props = this.propertyDescriptors(type);
+ ResultSetMetaData rsmd = rs.getMetaData();
+ int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
+
+ do {
+ results.add(this.createBean(rs, type, props, columnToProperty));
+ } while (rs.next());
+
+ return results;
+ }
+
+ /**
+ * Creates a new object and initializes its fields from the ResultSet.
+ * @param <T> The type of bean to create
+ * @param rs The result set.
+ * @param type The bean type (the return type of the object).
+ * @param props The property descriptors.
+ * @param columnToProperty The column indices in the result set.
+ * @return An initialized object.
+ * @throws SQLException if a database error occurs.
+ */
+ private <T> T createBean(ResultSet rs, Class<T> type,
+ PropertyDescriptor[] props, int[] columnToProperty)
+ throws SQLException {
+
+ T bean = this.newInstance(type);
+ return populateBean(rs, bean, props, columnToProperty);
+ }
+
+ /**
+ * Initializes the fields of the provided bean from the ResultSet.
+ * @param <T> The type of bean
+ * @param rs The result set.
+ * @param bean The bean to be populated.
+ * @return An initialized object.
+ * @throws SQLException if a database error occurs.
+ */
+ public <T> T populateBean(ResultSet rs, T bean) throws SQLException {
+ PropertyDescriptor[] props = this.propertyDescriptors(bean.getClass());
+ ResultSetMetaData rsmd = rs.getMetaData();
+ int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
+
+ return populateBean(rs, bean, props, columnToProperty);
+ }
+
+ /**
+ * This method populates a bean from the ResultSet based upon the underlying meta-data.
+ *
+ * @param <T> The type of bean
+ * @param rs The result set.
+ * @param bean The bean to be populated.
+ * @param props The property descriptors.
+ * @param columnToProperty The column indices in the result set.
+ * @return An initialized object.
+ * @throws SQLException if a database error occurs.
+ */
+ private <T> T populateBean(ResultSet rs, T bean,
+ PropertyDescriptor[] props, int[] columnToProperty)
+ throws SQLException {
+
+ for (int i = 1; i < columnToProperty.length; i++) {
+
+ if (columnToProperty[i] == PROPERTY_NOT_FOUND) {
+ continue;
+ }
+
+ PropertyDescriptor prop = props[columnToProperty[i]];
+ Class<?> propType = prop.getPropertyType();
+
+ Object value = null;
+ if(propType != null) {
+ value = this.processColumn(rs, i, propType);
+
+ if (value == null && propType.isPrimitive()) {
+ value = primitiveDefaults.get(propType);
+ }
+ }
+
+ this.callSetter(bean, prop, value);
+ }
+
+ return bean;
+ }
+
+ /**
+ * Calls the setter method on the target object for the given property.
+ * If no setter method exists for the property, this method does nothing.
+ * @param target The object to set the property on.
+ * @param prop The property to set.
+ * @param value The value to pass into the setter.
+ * @throws SQLException if an error occurs setting the property.
+ */
+ private void callSetter(Object target, PropertyDescriptor prop, Object value)
+ throws SQLException {
+
+ Method setter = getWriteMethod(target, prop, value);
+
+ if (setter == null || setter.getParameterTypes().length != 1) {
+ return;
+ }
+
+ try {
+ Class<?> firstParam = setter.getParameterTypes()[0];
+ for (PropertyHandler handler : propertyHandlers) {
+ if (handler.match(firstParam, value)) {
+ value = handler.apply(firstParam, value);
+ break;
+ }
+ }
+
+ // Don't call setter if the value object isn't the right type
+ if (this.isCompatibleType(value, firstParam)) {
+ setter.invoke(target, new Object[]{value});
+ } else {
+ throw new SQLException(
+ "Cannot set " + prop.getName() + ": incompatible types, cannot convert "
+ + value.getClass().getName() + " to " + firstParam.getName());
+ // value cannot be null here because isCompatibleType allows null
+ }
+
+ } catch (IllegalArgumentException e) {
+ throw new SQLException(
+ "Cannot set " + prop.getName() + ": " + e.getMessage());
+
+ } catch (IllegalAccessException e) {
+ throw new SQLException(
+ "Cannot set " + prop.getName() + ": " + e.getMessage());
+
+ } catch (InvocationTargetException e) {
+ throw new SQLException(
+ "Cannot set " + prop.getName() + ": " + e.getMessage());
+ }
+ }
+
+ /**
+ * ResultSet.getObject() returns an Integer object for an INT column. The
+ * setter method for the property might take an Integer or a primitive int.
+ * This method returns true if the value can be successfully passed into
+ * the setter method. Remember, Method.invoke() handles the unwrapping
+ * of Integer into an int.
+ *
+ * @param value The value to be passed into the setter method.
+ * @param type The setter's parameter type (non-null)
+ * @return boolean True if the value is compatible (null => true)
+ */
+ private boolean isCompatibleType(Object value, Class<?> type) {
+ // Do object check first, then primitives
+ if (value == null || type.isInstance(value) || matchesPrimitive(type, value.getClass())) {
+ return true;
+
+ }
+ return false;
+
+ }
+
+ /**
+ * Check whether a value is of the same primitive type as <code>targetType</code>.
+ *
+ * @param targetType The primitive type to target.
+ * @param valueType The value to match to the primitive type.
+ * @return Whether <code>valueType</code> can be coerced (e.g. autoboxed) into <code>targetType</code>.
+ */
+ private boolean matchesPrimitive(Class<?> targetType, Class<?> valueType) {
+ if (!targetType.isPrimitive()) {
+ return false;
+ }
+
+ try {
+ // see if there is a "TYPE" field. This is present for primitive wrappers.
+ Field typeField = valueType.getField("TYPE");
+ Object primitiveValueType = typeField.get(valueType);
+
+ if (targetType == primitiveValueType) {
+ return true;
+ }
+ } catch (NoSuchFieldException e) {
+ // lacking the TYPE field is a good sign that we're not working with a primitive wrapper.
+ // we can't match for compatibility
+ } catch (IllegalAccessException e) {
+ // an inaccessible TYPE field is a good sign that we're not working with a primitive wrapper.
+ // nothing to do. we can't match for compatibility
+ }
+ return false;
+ }
+
+ /**
+ * Get the write method to use when setting {@code value} to the {@code target}.
+ *
+ * @param target Object where the write method will be called.
+ * @param prop BeanUtils information.
+ * @param value The value that will be passed to the write method.
+ * @return The {@link java.lang.reflect.Method} to call on {@code target} to write {@code value} or {@code null} if
+ * there is no suitable write method.
+ */
+ protected Method getWriteMethod(Object target, PropertyDescriptor prop, Object value) {
+ Method method = prop.getWriteMethod();
+ return method;
+ }
+
+ /**
+ * Factory method that returns a new instance of the given Class. This
+ * is called at the start of the bean creation process and may be
+ * overridden to provide custom behavior like returning a cached bean
+ * instance.
+ * @param <T> The type of object to create
+ * @param c The Class to create an object from.
+ * @return A newly created object of the Class.
+ * @throws SQLException if creation failed.
+ */
+ protected <T> T newInstance(Class<T> c) throws SQLException {
+ try {
+ return c.newInstance();
+
+ } catch (InstantiationException e) {
+ throw new SQLException(
+ "Cannot create " + c.getName() + ": " + e.getMessage());
+
+ } catch (IllegalAccessException e) {
+ throw new SQLException(
+ "Cannot create " + c.getName() + ": " + e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a PropertyDescriptor[] for the given Class.
+ *
+ * @param c The Class to retrieve PropertyDescriptors for.
+ * @return A PropertyDescriptor[] describing the Class.
+ * @throws SQLException if introspection failed.
+ */
+ private PropertyDescriptor[] propertyDescriptors(Class<?> c)
+ throws SQLException {
+ // Introspector caches BeanInfo classes for better performance
+ BeanInfo beanInfo = null;
+ try {
+ beanInfo = Introspector.getBeanInfo(c);
+
+ } catch (IntrospectionException e) {
+ throw new SQLException(
+ "Bean introspection failed: " + e.getMessage());
+ }
+
+ return beanInfo.getPropertyDescriptors();
+ }
+
+ /**
+ * The positions in the returned array represent column numbers. The
+ * values stored at each position represent the index in the
+ * <code>PropertyDescriptor[]</code> for the bean property that matches
+ * the column name. If no bean property was found for a column, the
+ * position is set to <code>PROPERTY_NOT_FOUND</code>.
+ *
+ * @param rsmd The <code>ResultSetMetaData</code> containing column
+ * information.
+ *
+ * @param props The bean property descriptors.
+ *
+ * @throws SQLException if a database access error occurs
+ *
+ * @return An int[] with column index to property index mappings. The 0th
+ * element is meaningless because JDBC column indexing starts at 1.
+ */
+ protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
+ PropertyDescriptor[] props) throws SQLException {
+
+ int cols = rsmd.getColumnCount();
+ int[] columnToProperty = new int[cols + 1];
+ Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
+
+ for (int col = 1; col <= cols; col++) {
+ String columnName = rsmd.getColumnLabel(col);
+ if (null == columnName || 0 == columnName.length()) {
+ columnName = rsmd.getColumnName(col);
+ }
+ String propertyName = columnToPropertyOverrides.get(columnName);
+ if (propertyName == null) {
+ propertyName = columnName;
+ }
+ for (int i = 0; i < props.length; i++) {
+
+ if (propertyName.equalsIgnoreCase(props[i].getName())) {
+ columnToProperty[col] = i;
+ break;
+ }
+ }
+ }
+
+ return columnToProperty;
+ }
+
+ /**
+ * Convert a <code>ResultSet</code> column into an object. Simple
+ * implementations could just call <code>rs.getObject(index)</code> while
+ * more complex implementations could perform type manipulation to match
+ * the column's type to the bean property type.
+ *
+ * <p>
+ * This implementation calls the appropriate <code>ResultSet</code> getter
+ * method for the given property type to perform the type conversion. If
+ * the property type doesn't match one of the supported
+ * <code>ResultSet</code> types, <code>getObject</code> is called.
+ * </p>
+ *
+ * @param rs The <code>ResultSet</code> currently being processed. It is
+ * positioned on a valid row before being passed into this method.
+ *
+ * @param index The current column index being processed.
+ *
+ * @param propType The bean property type that this column needs to be
+ * converted into.
+ *
+ * @throws SQLException if a database access error occurs
+ *
+ * @return The object from the <code>ResultSet</code> at the given column
+ * index after optional type processing or <code>null</code> if the column
+ * value was SQL NULL.
+ */
+ protected Object processColumn(ResultSet rs, int index, Class<?> propType)
+ throws SQLException {
+
+ Object retval = rs.getObject(index);
+
+ if ( !propType.isPrimitive() && retval == null ) {
+ return null;
+ }
+
+ for (ColumnHandler handler : columnHandlers) {
+ if (handler.match(propType)) {
+ retval = handler.apply(rs, index);
+ break;
+ }
+ }
+
+ return retval;
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/14123859/src/main/java/org/apache/commons/dbutils/QueryLoader.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils/QueryLoader.java b/src/main/java/org/apache/commons/dbutils/QueryLoader.java
index 26881ef..cec9fbd 100644
--- a/src/main/java/org/apache/commons/dbutils/QueryLoader.java
+++ b/src/main/java/org/apache/commons/dbutils/QueryLoader.java
@@ -52,7 +52,7 @@ public class QueryLoader {
/**
* Maps query set names to Maps of their queries.
*/
- private final Map<String, Map<String, String>> queries = new HashMap<String, Map<String, String>>();
+ private final Map<String, Map<String, String>> queries = new HashMap<>();
/**
* QueryLoader constructor.
http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/14123859/src/main/java/org/apache/commons/dbutils/QueryRunner.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils/QueryRunner.java b/src/main/java/org/apache/commons/dbutils/QueryRunner.java
index 4a8dc2d..321caee 100644
--- a/src/main/java/org/apache/commons/dbutils/QueryRunner.java
+++ b/src/main/java/org/apache/commons/dbutils/QueryRunner.java
@@ -928,7 +928,7 @@ public class QueryRunner extends AbstractQueryRunner {
}
CallableStatement stmt = null;
- List<T> results = new LinkedList<T>();
+ List<T> results = new LinkedList<>();
try {
stmt = this.prepareCall(conn, sql);
http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/14123859/src/main/java/org/apache/commons/dbutils/handlers/AbstractKeyedHandler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils/handlers/AbstractKeyedHandler.java b/src/main/java/org/apache/commons/dbutils/handlers/AbstractKeyedHandler.java
index 2fc8d5d..c16f587 100644
--- a/src/main/java/org/apache/commons/dbutils/handlers/AbstractKeyedHandler.java
+++ b/src/main/java/org/apache/commons/dbutils/handlers/AbstractKeyedHandler.java
@@ -63,7 +63,7 @@ public abstract class AbstractKeyedHandler<K, V> implements ResultSetHandler<Map
* @return Map to store records in
*/
protected Map<K, V> createMap() {
- return new HashMap<K, V>();
+ return new HashMap<>();
}
/**
http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/14123859/src/main/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java b/src/main/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java
index 504b58e..a8fb5fe 100644
--- a/src/main/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java
+++ b/src/main/java/org/apache/commons/dbutils/handlers/AbstractListHandler.java
@@ -43,7 +43,7 @@ public abstract class AbstractListHandler<T> implements ResultSetHandler<List<T>
*/
@Override
public List<T> handle(ResultSet rs) throws SQLException {
- List<T> rows = new ArrayList<T>();
+ List<T> rows = new ArrayList<>();
while (rs.next()) {
rows.add(this.handleRow(rs));
}
http://git-wip-us.apache.org/repos/asf/commons-dbutils/blob/14123859/src/main/java/org/apache/commons/dbutils/wrappers/SqlNullCheckedResultSet.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/dbutils/wrappers/SqlNullCheckedResultSet.java b/src/main/java/org/apache/commons/dbutils/wrappers/SqlNullCheckedResultSet.java
index 85f273c..ff54f68 100644
--- a/src/main/java/org/apache/commons/dbutils/wrappers/SqlNullCheckedResultSet.java
+++ b/src/main/java/org/apache/commons/dbutils/wrappers/SqlNullCheckedResultSet.java
@@ -74,7 +74,7 @@ public class SqlNullCheckedResultSet implements InvocationHandler {
* Maps normal method names (ie. "getBigDecimal") to the corresponding null
* Method object (ie. getNullBigDecimal).
*/
- private static final Map<String, Method> nullMethods = new HashMap<String, Method>();
+ private static final Map<String, Method> nullMethods = new HashMap<>();
/**
* The {@code getNull} string prefix.