dbutils给bean类对象赋值源码分析

本文重点

以ResultSetHandler的实现类BeanListHandler为例,探索dbutils的QueryRunner的实现细节,重点是如何给java bean类对象赋值。

  public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException {
        PreparedStatement stmt = null;
        ResultSet rs = null;
        T result = null;

        try {
        //开始预处理
            stmt = this.prepareStatement(conn, sql);
        //注入参数
            this.fillStatement(stmt, params);
        //执行sql
            rs = this.wrap(stmt.executeQuery());
        //处理结果
        //重点进入这里    
            result = rsh.handle(rs);
        } catch (SQLException var33) {
            this.rethrow(var33, sql, params);
        } finally {
            try {
                this.close(rs);
            } finally {
                this.close((Statement)stmt);
            }
        }

        return result;
    }

进入BeanListHandler下的方法

 public List<T> handle(ResultSet rs) throws SQLException {
 //这里的this.convert是实现RowProcessor接口的BasicRowProcessor的实例
 //type是bean的class类对象
        return this.convert.toBeanList(rs, this.type);
    }

进入BasicRowProcessor下的方法

 public <T> List<T> toBeanList(ResultSet rs, Class<T> type) throws SQLException {
 //convert是BeanProcessor类的实例
        return this.convert.toBeanList(rs, type);
    }

step into BeanProcessor
这个是重点要观察的方法

  public <T> List<T> toBeanList(ResultSet rs, Class<T> type) throws SQLException {
        List<T> results = new ArrayList();
        if (!rs.next()) {
            return results;
        } else {
        //props数组记录了bean类的每一个成员变量的名字和读写方法的名字,即get和set方法。
            PropertyDescriptor[] props = this.propertyDescriptors(type);
        //rsmd记录了元数据
            ResultSetMetaData rsmd = rs.getMetaData();
            int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);

            do {
                results.add(this.createBean(rs, type, props, columnToProperty));
            } while(rs.next());

            return results;
        }
    }

props数组记录了bean类的每一个成员变量的名字和读写方法的名字,即get和set方法。
在这里插入图片描述
rsmd记录了元数据
step into mapColumnsToProperties()

 protected int[] mapColumnsToProperties(ResultSetMetaData rsmd, PropertyDescriptor[] props) throws SQLException {
 //     cols表示元数据的列
        int cols = rsmd.getColumnCount();
        int[] columnToProperty = new int[cols + 1];
        Arrays.fill(columnToProperty, -1);
// 元数据的列从1开始
        for(int col = 1; col <= cols; ++col) {
// 获取元数据的列的别名
            String columnName = rsmd.getColumnLabel(col);
// 如果没有别名则获取字段名
            if (null == columnName || 0 == columnName.length()) {
                columnName = rsmd.getColumnName(col);
            }

            for(int i = 0; i < props.length; ++i) {
            // sql中的字段名或别名忽略大小写后和bean的field名称做对比,若相同则写入对应关系的数组。
                if (columnName.equalsIgnoreCase(props[i].getName())) {
                    columnToProperty[col] = i;
                    break;
                }
            }
        }

        return columnToProperty;
    }

step into createBean

 private <T> T createBean(ResultSet rs, Class<T> type, PropertyDescriptor[] props, int[] columnToProperty) throws SQLException {
 //创建bean类实例
        T bean = this.newInstance(type);

        for(int i = 1; i < columnToProperty.length; ++i) {
            if (columnToProperty[i] != -1) {
                PropertyDescriptor prop = props[columnToProperty[i]];
                //得到变量类型
                Class<?> propType = prop.getPropertyType();
                //根据索引和变量类型取出值来
                Object value = this.processColumn(rs, i, propType);
                //如果值为null,则给默认值
                if (propType != null && value == null && propType.isPrimitive()) {
                    value = primitiveDefaults.get(propType);
                }

                this.callSetter(bean, prop, value);
            }
        }

        return bean;
    }

其中的processColumn源码为

 protected Object processColumn(ResultSet rs, int index, Class<?> propType) throws SQLException {
 //		如果不是原始类型且结果集里的数据为空
        if (!propType.isPrimitive() && rs.getObject(index) == null) {
            return null;
            //不是很懂这边一样的分支语句为什么要重复一遍
        } else if (!propType.isPrimitive() && rs.getObject(index) == null) {
            return null;
        } else if (propType.equals(String.class)) {
            return rs.getString(index);
        } else if (!propType.equals(Integer.TYPE) && !propType.equals(Integer.class)) {
            if (!propType.equals(Boolean.TYPE) && !propType.equals(Boolean.class)) {
                if (!propType.equals(Long.TYPE) && !propType.equals(Long.class)) {
                    if (!propType.equals(Double.TYPE) && !propType.equals(Double.class)) {
                        if (!propType.equals(Float.TYPE) && !propType.equals(Float.class)) {
                            if (!propType.equals(Short.TYPE) && !propType.equals(Short.class)) {
                                if (!propType.equals(Byte.TYPE) && !propType.equals(Byte.class)) {
                                    return propType.equals(Timestamp.class) ? rs.getTimestamp(index) : rs.getObject(index);
                                } else {
                                    return rs.getByte(index);
                                }
                            } else {
                                return rs.getShort(index);
                            }
                        } else {
                            return rs.getFloat(index);
                        }
                    } else {
                        return rs.getDouble(index);
                    }
                } else {
                    return rs.getLong(index);
                }
            } else {
                return rs.getBoolean(index);
            }
        } else {
            return rs.getInt(index);
        }
    }

最后进入callSetter方法

 private void callSetter(Object target, PropertyDescriptor prop, Object value) throws SQLException {
 //获取字段的set方法
        Method setter = prop.getWriteMethod();
        if (setter != null) {
            Class<?>[] params = setter.getParameterTypes();

            try {
                if (value != null && value instanceof Date) {
                    if (params[0].getName().equals("java.sql.Date")) {
                        value = new java.sql.Date(((Date)value).getTime());
                    } else if (params[0].getName().equals("java.sql.Time")) {
                        value = new Time(((Date)value).getTime());
                    } else if (params[0].getName().equals("java.sql.Timestamp")) {
                        value = new Timestamp(((Date)value).getTime());
                    }
                }
//判断set方法中形参的类型和value值是否兼容,若是则调用setter.invoke进行赋值。
                if (this.isCompatibleType(value, params[0])) {
                    setter.invoke(target, value);
                } else {
                    throw new SQLException("Cannot set " + prop.getName() + ": incompatible types.");
                }
            } catch (IllegalArgumentException var7) {
                throw new SQLException("Cannot set " + prop.getName() + ": " + var7.getMessage());
            } catch (IllegalAccessException var8) {
                throw new SQLException("Cannot set " + prop.getName() + ": " + var8.getMessage());
            } catch (InvocationTargetException var9) {
                throw new SQLException("Cannot set " + prop.getName() + ": " + var9.getMessage());
            }
        }
    }

这样我们就把一行表记录添加到List中了。

isCompatibleType方法如下

   private boolean isCompatibleType(Object value, Class<?> type) {
        if (value != null && !type.isInstance(value)) {
            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 {
                return type.equals(Boolean.TYPE) && Boolean.class.isInstance(value);
            }
        } else {
            return true;
        }
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值