在dbutils中,BeanProcessor是一個很重要的類:將列和bean對象的屬性進行匹配,將列的值賦予bean的對象。這個是使用了反射來進行的。 java
來看下類的outline: sql
從上圖能夠看出,有「建立對象」、「調用setter」、「得到類的屬性描述符」等方法,還有一個最重要的方法mapColumnsToProperties(ResultSetMetaData,PropertyDescriptor),這個方法是將結果集和類的屬性進行一個匹配。toBean是將一行記錄轉換成一個bean對象。toBeanList就是將多行記錄變成bean對象的List集合。 express
下面看一下它的具體實現。 apache
/* * 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.InvocationTargetException; import java.lang.reflect.Method; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.SQLXML; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * <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> * BeanProcessor將列名和bean的屬性名進行匹配;將ResultSet的列轉換成對象的屬性。想要定製行爲,能夠覆蓋這些方法。 * * <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>. * <p> * 特殊的數組值,給mapColumnsToProperties使用。代表了在ResultSet中某一列 * 在javabean中沒有對應的屬性 * </p> */ 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. * <p> * 以基本數據類型爲key,以0和FALSE爲默認值 * </p> */ private static final Map<Class<?>, Object> primitiveDefaults = new HashMap<Class<?>, Object>(); /** * 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)); } /** * 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<T> type) throws SQLException { //得到類的屬性描述符 PropertyDescriptor[] props = this.propertyDescriptors(type); //得到ResultSet的元數據 ResultSetMetaData rsmd = rs.getMetaData(); int[] columnToProperty = this.mapColumnsToProperties(rsmd, props); return this.createBean(rs, type, props, columnToProperty); } /** * 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<T> type) throws SQLException { List<T> results = new ArrayList<T>(); //若是ResultSet中沒有記錄,那麼就返回一個size爲0的集合List if (!rs.next()) { return results; } PropertyDescriptor[] props = this.propertyDescriptors(type); ResultSetMetaData rsmd = rs.getMetaData(); int[] columnToProperty = this.mapColumnsToProperties(rsmd, props); // TODO 這裏爲何要使用do while,使用while也能夠實現啊 do { //調用一次createBean,就產生一個bean對象 results.add(this.createBean(rs, type, props, columnToProperty)); } while (rs.next()); //返回一個有內容的集合List return results; } /** * Creates a new object and initializes its fields from the ResultSet. * 建立一個object,實例化object的字段,值來自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); /* * 從1開始計算,由於0存儲的沒意義 * i爲列數 */ for (int i = 1; i < columnToProperty.length; i++) { //若是值爲-1,那麼就說明此列在屬性描述符數組中沒有對應的屬性 if (columnToProperty[i] == PROPERTY_NOT_FOUND) { continue; } //根據列數拿到對應的屬性描述符 PropertyDescriptor prop = props[columnToProperty[i]]; //拿到屬性的類型 Class<?> propType = prop.getPropertyType(); //得到列值 Object value = this.processColumn(rs, i, propType); //屬性的類型不爲null,值爲null,且爲基本類型,就給予一個默認的值 if (propType != null && value == null && propType.isPrimitive()) { value = primitiveDefaults.get(propType); } //而後調用此屬性的setter方法,設置值 this.callSetter(bean, prop, value); } //當循環結束後,就將bean中能賦值的屬性都賦值了 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. * <p> * 調用目標對象指定屬性的setter方法。若是沒有setter方法,那麼此方法就終止了 * </p> * @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 { //得到指定屬性的setter方法 Method setter = prop.getWriteMethod(); //setter爲null,那麼就終止了,什麼也不幹 if (setter == null) { return; } //得到setter方法的參數類型 Class<?>[] params = setter.getParameterTypes(); try { // convert types for some popular ones if (value instanceof java.util.Date) { //拿出setter方法的參數類型名字 final String targetType = params[0].getName(); if ("java.sql.Date".equals(targetType)) { value = new java.sql.Date(((java.util.Date) value).getTime()); } else if ("java.sql.Time".equals(targetType)) { value = new java.sql.Time(((java.util.Date) value).getTime()); } else if ("java.sql.Timestamp".equals(targetType)) { value = new java.sql.Timestamp(((java.util.Date) value).getTime()); } } // Don't call setter if the value object isn't the right type if (this.isCompatibleType(value, params[0])) { setter.invoke(target, new Object[]{value}); } else { throw new SQLException( "Cannot set " + prop.getName() + ": incompatible types, cannot convert " + value.getClass().getName() + " to " + params[0].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)) { return true; } else if (type.equals(Integer.TYPE) && Integer.class.isInstance(value)) { return true; } else if (type.equals(Long.TYPE) && Long.class.isInstance(value)) { return true; } else if (type.equals(Double.TYPE) && Double.class.isInstance(value)) { return true; } else if (type.equals(Float.TYPE) && Float.class.isInstance(value)) { return true; } else if (type.equals(Short.TYPE) && Short.class.isInstance(value)) { return true; } else if (type.equals(Byte.TYPE) && Byte.class.isInstance(value)) { return true; } else if (type.equals(Character.TYPE) && Character.class.isInstance(value)) { return true; } else if (type.equals(Boolean.TYPE) && Boolean.class.isInstance(value)) { return true; } return false; } /** * 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. * 工廠方法,根據給定的Class返回一個新的實例(使用了反射)。在bean建立流程的開始 * 會調用此方法。 * @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>. * <p> * 返回的int數組中的位置表明着列的號數。每一個位置上的值表明着一個bean的 * PropertyDescriptor[]中的第幾個元素 * </p> * 能夠說columnToProperty中的index表明着列的號數(除了0) * 每一個元素的值表明的PropertyDescriptor[]的第幾個元素 * 如:columnToProperty[1] = 0;那麼就是列1對應着PropertyDescriptor[] * 的第0個元素。這個int[]數組將列數和屬性描述符之間的對應關係保存了起來 * @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 { //得到ResultSet的列數 int cols = rsmd.getColumnCount(); /* * 數組的lenght比列數大1,數組的第0個元素不放置東西 * 數組的第1個元素與列1對應,一次類推 */ int[] columnToProperty = new int[cols + 1]; //將數組中的全部元素填充爲-1 Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND); for (int col = 1; col <= cols; col++) { //先得到列的ColumnLabel,若是沒有,就改得到列名 String columnName = rsmd.getColumnLabel(col); if (null == columnName || 0 == columnName.length()) { columnName = rsmd.getColumnName(col); } //columnToPropertyOverrides默認在無參構造函數內有賦值 String propertyName = columnToPropertyOverrides.get(columnName); if (propertyName == null) { propertyName = columnName; } for (int i = 0; i < props.length; i++) { //propertyName若是等於屬性描述符的name,使用0以上的數字覆蓋掉原來的-1 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 { //若是屬性不是基本類型的,並且對應的列的值爲null,那麼返回null if ( !propType.isPrimitive() && rs.getObject(index) == null ) { return null; } /* * 若是屬性是String類型的,就取出值 * 若是是基本類型或基本類型的包裝類,那麼就取出值 * 其餘的Object類型,直接getObject */ if (propType.equals(String.class)) { return rs.getString(index); } else if ( propType.equals(Integer.TYPE) || propType.equals(Integer.class)) { return Integer.valueOf(rs.getInt(index)); } else if ( propType.equals(Boolean.TYPE) || propType.equals(Boolean.class)) { return Boolean.valueOf(rs.getBoolean(index)); } else if (propType.equals(Long.TYPE) || propType.equals(Long.class)) { return Long.valueOf(rs.getLong(index)); } else if ( propType.equals(Double.TYPE) || propType.equals(Double.class)) { return Double.valueOf(rs.getDouble(index)); } else if ( propType.equals(Float.TYPE) || propType.equals(Float.class)) { return Float.valueOf(rs.getFloat(index)); } else if ( propType.equals(Short.TYPE) || propType.equals(Short.class)) { return Short.valueOf(rs.getShort(index)); } else if (propType.equals(Byte.TYPE) || propType.equals(Byte.class)) { return Byte.valueOf(rs.getByte(index)); } else if (propType.equals(Timestamp.class)) { return rs.getTimestamp(index); } else if (propType.equals(SQLXML.class)) { return rs.getSQLXML(index); } else { return rs.getObject(index); } } }
總的來講:BeanProcessor就是對bean的操做。 數組
toArray:將記錄變成數組 app
toBean:將記錄變成對象 less
toBeanList:將記錄變成bean的集合 ide
toMap:將記錄變成Map對象 函數
它有一個實現類:BasicRowProcessor。 ui
BasicRowProcessor實現了對ResultSet的處理。其實是BasicRowProcessor和BeanProcessor一塊兒合做的。
/* * 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.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; /** * Basic implementation of the <code>RowProcessor</code> interface. * RowProcessor接口的基本實現 * 有些方法實現委託給了BeanProcessor對象實現 * <p> * This class is thread-safe. * </p> * * @see RowProcessor */ public class BasicRowProcessor implements RowProcessor { /** * The default BeanProcessor instance to use if not supplied in the * constructor. * 一個BeanProcessor對象 */ private static final BeanProcessor defaultConvert = new BeanProcessor(); /** * The Singleton instance of this class. * 單例 */ private static final BasicRowProcessor instance = new BasicRowProcessor(); /** * Returns the Singleton instance of this class. * * @return The single instance of this class. * @deprecated Create instances with the constructors instead. This will * be removed after DbUtils 1.1. */ @Deprecated public static BasicRowProcessor instance() { return instance; } /** * Use this to process beans. */ private final BeanProcessor convert; /** * BasicRowProcessor constructor. Bean processing defaults to a * BeanProcessor instance. * <p> * BasicRowProcessor構造器。Bean處理默認使用了一個BeanProcessor對象 * </p> */ public BasicRowProcessor() { this(defaultConvert); } /** * BasicRowProcessor constructor. * @param convert The BeanProcessor to use when converting columns to * bean properties. * @since DbUtils 1.1 */ public BasicRowProcessor(BeanProcessor convert) { super(); this.convert = convert; } /** * Convert a <code>ResultSet</code> row into an <code>Object[]</code>. * This implementation copies column values into the array in the same * order they're returned from the <code>ResultSet</code>. Array elements * will be set to <code>null</code> if the column was SQL NULL. * 將一個ResultSet中的一行轉換成一個Object[],每個列值就是數組中的一個元素。 * 這個實現將列的值拷貝到數組中,二者時間 * 的順序一致。若是列值爲SQL NULL,那麼在數組中就會設置爲null * @see org.apache.commons.dbutils.RowProcessor#toArray(java.sql.ResultSet) * @param rs ResultSet that supplies the array data * @throws SQLException if a database access error occurs * @return the newly created array */ @Override public Object[] toArray(ResultSet rs) throws SQLException { ResultSetMetaData meta = rs.getMetaData(); //得到列數 int cols = meta.getColumnCount(); //根據列數,建立一個對應大小的數組 Object[] result = new Object[cols]; //將列值放到數組中 for (int i = 0; i < cols; i++) { result[i] = rs.getObject(i + 1); } //返回結果 return result; } /** * Convert a <code>ResultSet</code> row into a JavaBean. This * implementation delegates to a BeanProcessor instance. * 將ResultSet中的一行轉換成一個javaBean。具體實現委派給一個BeanProcessor實例。 * @see org.apache.commons.dbutils.RowProcessor#toBean(java.sql.ResultSet, java.lang.Class) * @see org.apache.commons.dbutils.BeanProcessor#toBean(java.sql.ResultSet, java.lang.Class) * @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 */ @Override public <T> T toBean(ResultSet rs, Class<T> type) throws SQLException { return this.convert.toBean(rs, type); } /** * Convert a <code>ResultSet</code> into a <code>List</code> of JavaBeans. * This implementation delegates to a BeanProcessor instance. * 將一個ResultSet轉換成一個javaBean集合。具體實現委派給一個BeanProcessor實例。 * @see org.apache.commons.dbutils.RowProcessor#toBeanList(java.sql.ResultSet, java.lang.Class) * @see org.apache.commons.dbutils.BeanProcessor#toBeanList(java.sql.ResultSet, java.lang.Class) * @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 A <code>List</code> of beans with the given type in the order * they were returned by the <code>ResultSet</code>. */ @Override public <T> List<T> toBeanList(ResultSet rs, Class<T> type) throws SQLException { return this.convert.toBeanList(rs, type); } /** * Convert a <code>ResultSet</code> row into a <code>Map</code>. This * implementation returns a <code>Map</code> with case insensitive column * names as keys. Calls to <code>map.get("COL")</code> and * <code>map.get("col")</code> return the same value. * 將一個ResultSet中的額一行轉換成一個Map對象。列名爲key,值爲value。Map的key不區分 * 大小寫。map.get("col")和map.get("COL")都返回同一個值 * @see org.apache.commons.dbutils.RowProcessor#toMap(java.sql.ResultSet) * @param rs ResultSet that supplies the map data * @throws SQLException if a database access error occurs * @return the newly created Map */ @Override public Map<String, Object> toMap(ResultSet rs) throws SQLException { /* * 建立一個Map對象,能夠看到使用了一個內部類CaseInsensitiveHashMap * 由於key無論大小寫,都將返回同一個值。JDK中沒有提供這種類型的Map, * 因此要自定義了 */ Map<String, Object> result = new CaseInsensitiveHashMap(); //得到ResultSet的元數據 ResultSetMetaData rsmd = rs.getMetaData(); //得到列數 int cols = rsmd.getColumnCount(); for (int i = 1; i <= cols; i++) { //以列名爲key,列值爲value存放到Map中 result.put(rsmd.getColumnName(i), rs.getObject(i)); } return result; } /** * A Map that converts all keys to lowercase Strings for case insensitive * lookups. This is needed for the toMap() implementation because * databases don't consistently 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 = -2848100435296897392L; /** {@inheritDoc} */ @Override public boolean containsKey(Object key) { Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH)); 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()); } /** {@inheritDoc} */ @Override public Object get(Object key) { Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH)); return super.get(realKey); } /** {@inheritDoc} */ @Override public Object put(String key, Object 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.toLowerCase(Locale.ENGLISH), key); Object oldValue = super.remove(oldKey); super.put(key, value); return oldValue; } /** {@inheritDoc} */ @Override 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); } } /** {@inheritDoc} */ @Override public Object remove(Object key) { Object realKey = lowerCaseMap.remove(key.toString().toLowerCase(Locale.ENGLISH)); return super.remove(realKey); } } }
BasicRowProcessor實現了RowProcessor接口,下面簡單講下方法的實現
一、toArray:將一行記錄變成一個數組。根據列數來建立一個對應大小的Object[]。而後將列值取出放到Object[]中。
二、toBean:將一行記錄變成一個bean對象。其實它內部調用了BeanProcessor中的toBean方法,具體的能夠看看上面BeanProcessor的源碼。
三、toBeanList:此方法跟toBean方法相似,也是調用了Beanprocessor中的toBeanList方法。
四、toMap:將一行記錄變成一個Map對象。列名爲key,列值爲value。它使用了一個自定義的CaseInsensitiveHashMap。此map實現了key不區分大小寫。這對於咱們的使用特別方便。
PS:從01-03,把dbutils中是核心類都講了,以後的各類Handler主要是調用了BasicRowProcessor和BeanProcessor類。以後會大概講些Handler。