This patch allows the object get/set datatypes to be float, double, or int (if possible). The current codebase requires get/set datatypes to be BigDecimal.
Index: BasicRowProcessor.java =================================================================== RCS file: /home/cvspublic/jakarta-commons/dbutils/src/java/org/apache/commons/dbutils/BasicRowProcessor.java,v retrieving revision 1.10 diff -r1.10 BasicRowProcessor.java 2c2,58 < * Copyright 2002-2004 The Apache Software Foundation --- > * $Header: > /home/cvs/jakarta-commons/dbutils/src/java/org/apache/commons/dbutils/BasicRowProcessor.java,v > 1.5 2003/11/11 00:53:19 dgraham Exp $ > * $Revision: 1.5 $ > * $Date: 2003/11/11 00:53:19 $ > * > * ==================================================================== > * > * The Apache Software License, Version 1.1 > * > * Copyright (c) 2002-2003 The Apache Software Foundation. All rights > * reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions > * are met: > * > * 1. Redistributions of source code must retain the above copyright > * notice, this list of conditions and the following disclaimer. > * > * 2. Redistributions in binary form must reproduce the above copyright > * notice, this list of conditions and the following disclaimer in > * the documentation and/or other materials provided with the > * distribution. > * > * 3. The end-user documentation included with the redistribution, if > * any, must include the following acknowledgement: > * "This product includes software developed by the > * Apache Software Foundation (http://www.apache.org/)." > * Alternately, this acknowledgement may appear in the software itself, > * if and wherever such third-party acknowledgements normally appear. > * > * 4. The names "The Jakarta Project", "Commons", and "Apache Software > * Foundation" must not be used to endorse or promote products derived > * from this software without prior written permission. For written > * permission, please contact [EMAIL PROTECTED] > * > * 5. Products derived from this software may not be called "Apache" > * nor may "Apache" appear in their names without prior written > * permission of the Apache Software Foundation. > * > * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED > * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES > * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR > * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, > * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT > * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > * SUCH DAMAGE. > * ==================================================================== > * > * This software consists of voluntary contributions made by many > * individuals on behalf of the Apache Software Foundation. For more > * information on the Apache Software Foundation, please see > * <http://www.apache.org/>. 4,14d59 < * Licensed 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. 15a61 > 17a64,69 > 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; 20a73 > import java.util.ArrayList; 24a78 > import java.math.BigDecimal; 28,32c82,83 < * < * <p> < * This class is thread-safe. < * </p> < * --- > * This class is a thread-safe Singleton. > * 33a85,89 > * > * @author Henri Yandell > * @author Juozas Baliuka > * @author David Graham > * @author Yoav Shapira 38,39c94,113 < * The default BeanProcessor instance to use if not supplied in the < * constructor. --- > * 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 primitiveDefaults = new HashMap(); > > static { > primitiveDefaults.put(Integer.TYPE, new Integer(0)); > primitiveDefaults.put(Short.TYPE, new Short((short) 0)); > primitiveDefaults.put(Byte.TYPE, new Byte((byte) 0)); > primitiveDefaults.put(Float.TYPE, new Float(0)); > primitiveDefaults.put(Double.TYPE, new Double(0)); > primitiveDefaults.put(Long.TYPE, new Long(0)); > primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE); > primitiveDefaults.put(Character.TYPE, new Character('\u0000')); > } > > /** > * Special array index that indicates there is no bean property that > * matches a column from a ResultSet. 41c115 < private static final BeanProcessor defaultConvert = new BeanProcessor(); --- > private static final int PROPERTY_NOT_FOUND = -1; 52,53d125 < * @deprecated Create instances with the constructors instead. This will < * be removed after DbUtils 1.1. 60,76c132 < * Use this to process beans. < */ < private BeanProcessor convert = null; < < /** < * BasicRowProcessor constructor. Bean processing defaults to a < * BeanProcessor instance. < */ < public BasicRowProcessor() { < this(defaultConvert); < } < < /** < * BasicRowProcessor constructor. < * @param convert The BeanProcessor to use when converting columns to < * bean properties. < * @since DbUtils 1.1 --- > * Protected constructor for BasicRowProcessor subclasses only. 78c134 < public BasicRowProcessor(BeanProcessor convert) { --- > protected BasicRowProcessor() { 80d135 < this.convert = convert; 85c140 < * This implementation copies column values into the array in the same --- > * This implementation copies column values into the array in the same 104,106c159,183 < * Convert a <code>ResultSet</code> row into a JavaBean. This < * implementation delegates to a BeanProcessor instance. < * @see org.apache.commons.dbutils.BeanProcessor#toBean(java.sql.ResultSet, java.lang.Class) --- > * 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 property's set method parameter type matches the column > * type. If the data types do not match, the setter will not be called. > * </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> > * 110c187,196 < return this.convert.toBean(rs, type); --- > > PropertyDescriptor[] props = this.propertyDescriptors(type); > > ResultSetMetaData rsmd = rs.getMetaData(); > > int[] columnToProperty = this.mapColumnsToProperties(rsmd, props); > > int cols = rsmd.getColumnCount(); > > return this.createBean(rs, type, props, columnToProperty, cols); 114,116c200,224 < * Convert a <code>ResultSet</code> into a <code>List</code> of JavaBeans. < * This implementation delegates to a BeanProcessor instance. < * @see org.apache.commons.dbutils.BeanProcessor#toBeanList(java.sql.ResultSet, java.lang.Class) --- > * 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 property's set method parameter type matches the column > * type. If the data types do not match, the setter will not be called. > * </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> > * 120c228,244 < return this.convert.toBeanList(rs, type); --- > List results = new ArrayList(); > > if (!rs.next()) { > return results; > } > > PropertyDescriptor[] props = this.propertyDescriptors(type); > ResultSetMetaData rsmd = rs.getMetaData(); > int[] columnToProperty = this.mapColumnsToProperties(rsmd, props); > int cols = rsmd.getColumnCount(); > > do { > results.add(this.createBean(rs, type, props, columnToProperty, cols)); > > } while (rs.next()); > > return results; 124c248,328 < * Convert a <code>ResultSet</code> row into a <code>Map</code>. This --- > * Creates a new object and initializes its fields from the ResultSet. > * > * @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 > * @param cols The number of columns > * @return An initialized object. > * @throws SQLException If a database error occurs > */ > private Object createBean( > ResultSet rs, > Class type, > PropertyDescriptor[] props, > int[] columnToProperty, > int cols) > throws SQLException { > > Object bean = this.newInstance(type); > > for (int i = 1; i <= cols; i++) { > > if (columnToProperty[i] == PROPERTY_NOT_FOUND) { > continue; > } > > Object value = rs.getObject(i); > > PropertyDescriptor prop = props[columnToProperty[i]]; > Class propType = prop.getPropertyType(); > > if (propType != null && value == null && propType.isPrimitive()) { > value = primitiveDefaults.get(propType); > } > > this.callSetter(bean, prop, value); > } > > return bean; > } > > /** > * The positions in the returned array represent column numbers. The values > * stored at each position represent the index in the PropertyDescriptor[] > * for the bean property that matches the column name. If no bean property > * was found for a column, the position is set to PROPERTY_NOT_FOUND. > * > * @param rsmd The result set meta data containing column information > * @param props The bean property descriptors > * @return An int[] with column index to property index mappings. The 0th > * element is meaningless as column indexing starts at 1. > * > * @throws SQLException If a database error occurs > */ > private int[] mapColumnsToProperties( > ResultSetMetaData rsmd, > PropertyDescriptor[] props) > throws SQLException { > > int cols = rsmd.getColumnCount(); > int columnToProperty[] = new int[cols + 1]; > > for (int col = 1; col <= cols; col++) { > String columnName = rsmd.getColumnName(col); > for (int i = 0; i < props.length; i++) { > > if (columnName.equalsIgnoreCase(props[i].getName())) { > columnToProperty[col] = i; > break; > > } else { > columnToProperty[col] = PROPERTY_NOT_FOUND; > } > } > } > > return columnToProperty; > } > > /** > * Convert a <code>ResultSet</code> row into a <code>Map</code>. This 126c330 < * names as keys. Calls to <code>map.get("COL")</code> and --- > * names as keys. Calls to <code>map.get("COL")</code> and 141c345,523 < --- > > /** > * 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 = prop.getWriteMethod(); > > if (setter == null) { > return; > } > > Class[] params = setter.getParameterTypes(); > try { > // 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 > { > //see if there are any conversions that can be made w/o resulting > //in data loss... > value = convertObject(value, params[0]); > if (value != null) > { > setter.invoke(target, new Object[] { value }); > } > } > > } 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. > * @return boolean True if the value is compatible. > */ > 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; > > } else { > return false; > } > > } > > /** > * attempt to make a data type conversion from value to type > * @param value Object object to be converted > * @param type Class target converstion type > * @return Object resulting conversion, null if conversion was not possible > * @todo additional conversions? > */ > private Object convertObject(Object value, Class type) { > Object converted = null; > if (value != null) { > > if (BigDecimal.class.isInstance(value)) > { > //attempt conversion; only perform if dataloss can be avoided > BigDecimal bd = (BigDecimal)value; > if (type.equals(Integer.TYPE)) > { > if (bd.scale() == 0) { > converted = new Integer(bd.intValue()); > } > } > else if (type.equals(Float.TYPE)) > { > converted = new Float(bd.floatValue()); > } > else if (type.equals(Double.TYPE)) > { > converted = new Double(bd.doubleValue()); > } > } > } > return converted; > } > > /** > * Returns a new instance of the given Class. > * > * @param c The Class to create an object from. > * @return A newly created object of the Class. > * @throws SQLException if creation failed. > */ > private Object newInstance(Class 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(); > } > 144,145c526,527 < * lookups. This is needed for the toMap() implementation because < * databases don't consistenly handle the casing of column names. --- > * lookups. This is needed for the toMap() implementation because > * databases don't consistenly handle the casing of column names. 183c565 < * @see java.util.Map#remove(java.lang.Object) --- > * @see java.util.Map#remove(java.lang.ObjecT) 189c571 < --- >
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]