20 | */
21 | package com.opensource.dbhelp;
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dialect/PageSqlParserFactory.java:
--------------------------------------------------------------------------------
1 | package com.opensource.dbhelp.dialect;
2 |
3 | import com.opensource.dbhelp.dialect.mysql.MySqlPageParser;
4 | import com.opensource.dbhelp.dialect.oracle.OraclePageSqlParser;
5 |
6 | /**
7 | * 获取翻页sql解析对象
8 | *
9 | * Copyright: Copyright (c) 13-1-15 上午9:27
10 | *
11 | * Company: GNU General Public License
12 | *
13 | * Author: GNU General Public License
14 | *
15 | * Version: 1.0
16 | *
17 | */
18 | public class PageSqlParserFactory {
19 |
20 | /**
21 | * 获取翻页解析对象
22 | *
23 | * @param dialect
24 | * 数据库类型
25 | * @return PageSqlParser
26 | */
27 | public static PageSqlParser getParser(String dialect) {
28 | if ("mysql".equals(dialect)) {
29 | return new MySqlPageParser();
30 | } else {
31 | return new OraclePageSqlParser();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/wrappers/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 |
5 | /**
6 | * Wrappers that add functionality to java.sql classes.
7 | */
8 | package com.opensource.dbhelp.dbutils.wrappers;
9 |
10 |
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/handlers/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 |
5 | /**
6 | * Implementations of the com.opensource.dbhelp.dbutils.ResultSetHandler interface.
7 | */
8 | package com.opensource.dbhelp.dbutils.handlers;
9 |
10 |
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dialect/PageSqlParser.java:
--------------------------------------------------------------------------------
1 | package com.opensource.dbhelp.dialect;
2 |
3 | /**
4 | * 翻页SQL接口
5 | *
6 | * Copyright: Copyright (c) 13-1-14 下午3:57
7 | *
8 | * Company: GNU General Public License
9 | *
10 | * Author: GNU General Public License
11 | *
12 | * Version: 1.0
13 | *
14 | */
15 | public interface PageSqlParser {
16 |
17 | /**
18 | * 生成查询一页数据的sql语句
19 | *
20 | * @param sql
21 | * 原查询语句
22 | * @param hasOffset
23 | * true 不是第一页 false 第一页
24 | * @return 查询当前页的SQL
25 | */
26 | public String getPageSql(String sql, boolean hasOffset);
27 |
28 | /**
29 | * 获取查询记录数的sql语句
30 | *
31 | * @param sql
32 | * 原查询语句
33 | * @return 查询记录数的SQL
34 | */
35 | public String getCountingSql(String sql);
36 |
37 | /**
38 | * 附加翻页参数
39 | *
40 | * @param params
41 | * 原有参数
42 | * @param hasOffset
43 | * true 不是第一页 false 第一页
44 | * @param startIndex
45 | * 开始索引
46 | * @param pageSize
47 | * 每页记录数
48 | * @return 附加翻页后的传入参数
49 | */
50 | public Object[] attachPageParam(Object[] params, boolean hasOffset, int startIndex, int pageSize);
51 | }
52 |
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dialect/mysql/MySqlPageParser.java:
--------------------------------------------------------------------------------
1 | package com.opensource.dbhelp.dialect.mysql;
2 |
3 | import org.apache.commons.lang3.ArrayUtils;
4 |
5 | import com.opensource.dbhelp.dialect.PageSqlParser;
6 |
7 | /**
8 | * Mysql 翻页接口实现
9 | *
10 | * Copyright: Copyright (c) 13-1-14 下午4:01
11 | *
12 | * Company: GNU General Public License
13 | *
14 | * Author: GNU General Public License
15 | *
16 | * Version: 1.0
17 | *
18 | */
19 | public class MySqlPageParser implements PageSqlParser {
20 |
21 | @Override
22 | public String getPageSql(String sql, boolean hasOffset) {
23 | if (hasOffset) {
24 | return sql + " limit ?, ?";
25 | } else {
26 | return sql + " limit ?";
27 | }
28 | }
29 |
30 | @Override
31 | public String getCountingSql(String sql) {
32 | return "select count(1) from ( " + sql + ") as __tc";
33 | }
34 |
35 | @Override
36 | public Object[] attachPageParam(Object[] params, boolean hasOffset, int startIndex, int pageSize) {
37 | if (hasOffset) {
38 | params = ArrayUtils.add(params, startIndex - 1);
39 | params = ArrayUtils.add(params, pageSize);
40 | } else {
41 | params = ArrayUtils.add(params, pageSize);
42 | }
43 | return params;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 |
5 | /**
6 | * DbUtils is a small set of classes designed to make working with JDBC easier. JDBC resource cleanup code is mundane, error prone work so these classes abstract out all of the cleanup tasks from your code leaving you with what you really wanted to do with JDBC in the first place: query and update data. This package contains the core classes and interfaces - DbUtils, QueryRunner and the ResultSetHandler interface should be your first items of interest.
7 | */
8 | package com.opensource.dbhelp.dbutils;
9 |
10 |
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dialect/oracle/OraclePageSqlParser.java:
--------------------------------------------------------------------------------
1 | package com.opensource.dbhelp.dialect.oracle;
2 |
3 | import org.apache.commons.lang3.ArrayUtils;
4 |
5 | import com.opensource.dbhelp.dialect.PageSqlParser;
6 |
7 | /**
8 | * Oracle 翻页接口实现
9 | *
10 | * Copyright: Copyright (c) 13-1-14 下午3:57
11 | *
12 | * Company: GNU General Public License
13 | *
14 | * Author: GNU General Public License
15 | *
16 | * Version: 1.0
17 | *
18 | */
19 | public class OraclePageSqlParser implements PageSqlParser {
20 |
21 | @Override
22 | public String getPageSql(String sql, boolean hasOffset) {
23 | StringBuilder ret = new StringBuilder(sql.length() + 100);
24 | if (hasOffset) {
25 | ret.append("select * from ( select row_.*, rownum rownum_ from ( ");
26 | } else {
27 | ret.append("select * from ( ");
28 | }
29 | ret.append(sql);
30 | if (hasOffset) {
31 | ret.append(" ) row_ where rownum < ?) where rownum_ >= ?");
32 | } else {
33 | ret.append(" ) where rownum < ?");
34 | }
35 | return ret.toString();
36 | }
37 |
38 | @Override
39 | public String getCountingSql(String sql) {
40 | return "select count(1) from ( " + sql + ")";
41 | }
42 |
43 | @Override
44 | public Object[] attachPageParam(Object[] params, boolean hasOffset, int startIndex, int pageSize) {
45 | if (hasOffset) {
46 | params = ArrayUtils.add(params, startIndex + pageSize);
47 | params = ArrayUtils.add(params, startIndex);
48 | } else {
49 | params = ArrayUtils.add(params, startIndex + pageSize);
50 | }
51 | return params;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/ResultSetHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 | package com.opensource.dbhelp.dbutils;
5 |
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 |
9 | /**
10 | * Implementations of this interface convert ResultSets into other objects.
11 | *
12 | * @param
13 | * the target type the input ResultSet will be converted to.
14 | */
15 | public interface ResultSetHandler {
16 |
17 | /**
18 | * Turn the ResultSet into an Object.
19 | *
20 | * @param rs
21 | * The ResultSet to handle. It has not been touched before being passed to this method.
22 | * @return An Object initialized with ResultSet data. It is legal for implementations to return null if the ResultSet contained 0 rows.
23 | * @throws java.sql.SQLException
24 | * if a database access error occurs
25 | */
26 | T handle(ResultSet rs) throws SQLException;
27 |
28 | }
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/page/ListPage.java:
--------------------------------------------------------------------------------
1 | package com.opensource.dbhelp.page;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * 使用List封装数据的分页对象。
8 | *
21 | */
22 | public abstract class AbstractPagedStatement {
23 |
24 | /** 每页允许的最大记录数 */
25 | public final static int MAX_PAGESIZE = Page.MAX_PAGESIZE;
26 |
27 | /** 查询总记录数的SQL */
28 | protected String countSql;
29 |
30 | /** 查询SQL */
31 | protected String querySql;
32 |
33 | /** 当前显示页 */
34 | protected int currentPage;
35 |
36 | /** 每页记录数 */
37 | protected int pageSize;
38 |
39 | /** 当前显示页从记录集开始的位置 */
40 | protected int startIndex;
41 |
42 | /** 总记录数 */
43 | protected int totalCount;
44 |
45 | /** 显示当前页是否需要偏移 */
46 | protected boolean hasOffset;
47 |
48 | protected PageSqlParser pageSqlParser;
49 |
50 | /**
51 | * 构造一查询出当页数据的PageStatement,并指定每页显示记录条数
52 | *
53 | * @param dialect
54 | * database dialect
55 | * @param sql
56 | * query sql
57 | * @param currentPage
58 | * 页码
59 | * @param pageSize
60 | * 每页容量
61 | */
62 | public AbstractPagedStatement(String dialect, String sql, int currentPage, int pageSize) {
63 | this.currentPage = currentPage;
64 | this.pageSize = pageSize;
65 | this.startIndex = Page.getStartOfAnyPage(currentPage, pageSize);
66 | this.hasOffset = currentPage > 1;
67 |
68 | pageSqlParser = PageSqlParserFactory.getParser(dialect);
69 | this.countSql = pageSqlParser.getCountingSql(sql);
70 | this.querySql = pageSqlParser.getPageSql(sql, hasOffset);
71 | }
72 |
73 | /**
74 | * 执行查询
75 | *
76 | * @param type
77 | * 预定义的查询类型,会返回不同类型分页对象
78 | * @return 分页对象
79 | * @throws SQLException
80 | * if a database access error occurs
81 | */
82 | protected abstract Page executeQuery(int type) throws SQLException;
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/CamelBeanProcessor.java:
--------------------------------------------------------------------------------
1 | package com.opensource.dbhelp.dbutils;
2 |
3 | import java.beans.PropertyDescriptor;
4 | import java.sql.ResultSetMetaData;
5 | import java.sql.SQLException;
6 | import java.util.Arrays;
7 |
8 | import org.apache.commons.lang3.text.WordUtils;
9 |
10 | /**
11 | * 记录集字段及bean属性之间的映射转换实现类。
12 | *
13 | * 重写dbutils中“beanProcessor”的"mapColumnsToProperties"方法, 使其可以实现数据表user_id到对象userId和user_id到对象属性user_id之间的自动转换。 注:引用时需要注意的是平台优先处理“user_id到对象userId”。
14 | *
15 | * Copyright: Copyright (c) Feb 6, 2009 3:39:21 PM
16 | *
17 | * Company: GNU General Public License
18 | *
19 | * Author: GNU General Public License
20 | *
21 | * Version: 1.1
22 | *
23 | */
24 | public class CamelBeanProcessor extends BeanProcessor {
25 |
26 | /**
27 | * 对象属性和字段关系映射
28 | *
29 | * @param rsmd
30 | * 元字符结果集
31 | * @param props
32 | * 对象属性数组
33 | * @return 对象和数据表字段关系位置数组
34 | */
35 | @Override
36 | protected int[] mapColumnsToProperties(ResultSetMetaData rsmd, PropertyDescriptor[] props) throws SQLException {
37 |
38 | int cols = rsmd.getColumnCount();
39 | int columnToProperty[] = new int[cols + 1];
40 | Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
41 |
42 | for (int col = 1; col <= cols; col++) {
43 | String columnName = rsmd.getColumnLabel(col);
44 | if (null == columnName || 0 == columnName.length()) {
45 | columnName = rsmd.getColumnName(col);
46 | }
47 |
48 | for (int i = 0; i < props.length; i++) {
49 | if (formatColName(columnName).equalsIgnoreCase(props[i].getName())) {
50 | columnToProperty[col] = i;
51 | break;
52 | }
53 | if (columnName.equalsIgnoreCase(props[i].getName())) {
54 | columnToProperty[col] = i;
55 | break;
56 | }
57 | }
58 | }
59 |
60 | return columnToProperty;
61 | }
62 |
63 | /**
64 | * 格式化字符将user_id或USER_ID字段返回成userId
65 | *
66 | * @param name
67 | * 字段名
68 | * @return 转化后的属性名
69 | */
70 | private String formatColName(String name) {
71 | if (name == null || "".equals(name)) {
72 | return "";
73 | }
74 | String rstr = name.toLowerCase();
75 | rstr = WordUtils.uncapitalize(WordUtils.capitalize(rstr, "_".toCharArray()));
76 | rstr = rstr.replaceAll("_", "");
77 | return rstr;
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/StringRowProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 | package com.opensource.dbhelp.dbutils;
5 |
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 | import java.util.Map;
9 |
10 | /**
11 | * StringRowProcessor implementations convert ResultSet rows into various other objects. Implementations can extend BasicStringRowProcessor to protect themselves from changes to this interface.
12 | *
13 | * @see BasicStringRowProcessor
14 | */
15 | public interface StringRowProcessor {
16 |
17 | /**
18 | * Create an String[] from the column values in one ResultSet row. The ResultSet should be positioned on a valid row before passing it to this method. Implementations of this method must not alter the row position of the ResultSet.
19 | *
20 | * @param rs
21 | * ResultSet that supplies the array data
22 | * @throws java.sql.SQLException
23 | * if a database access error occurs
24 | * @return the newly created array
25 | */
26 | String[] toArray(ResultSet rs) throws SQLException;
27 |
28 | /**
29 | * Create a Map from the column values in one ResultSet row. The ResultSet should be positioned on a valid row before passing it to this method. Implementations of this method must not alter the row position of the ResultSet.
30 | *
31 | * @param rs
32 | * ResultSet that supplies the map data
33 | * @throws java.sql.SQLException
34 | * if a database access error occurs
35 | * @return the newly created Map
36 | */
37 | Map toMap(ResultSet rs) throws SQLException;
38 |
39 | }
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/handlers/AbstractListHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 | package com.opensource.dbhelp.dbutils.handlers;
5 |
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | import com.opensource.dbhelp.dbutils.ResultSetHandler;
12 |
13 | /**
14 | * Abstract class that simplify development of ResultSetHandler classes that convert ResultSet into List.
15 | *
16 | * @param
17 | * the target List generic type
18 | * @see com.opensource.dbhelp.dbutils.ResultSetHandler
19 | */
20 | public abstract class AbstractListHandler implements ResultSetHandler> {
21 |
22 | /**
23 | * Whole ResultSet handler. It produce List as result. To convert individual rows into Java objects it uses handleRow(ResultSet) method.
24 | *
25 | * @see #handleRow(java.sql.ResultSet)
26 | * @param rs
27 | * ResultSet to process.
28 | * @return a list of all rows in the result set
29 | * @throws java.sql.SQLException
30 | * error occurs
31 | */
32 | @Override
33 | public List handle(ResultSet rs) throws SQLException {
34 | List rows = new ArrayList();
35 | while (rs.next()) {
36 | rows.add(this.handleRow(rs));
37 | }
38 | return rows;
39 | }
40 |
41 | /**
42 | * Row handler. Method converts current row into some Java object.
43 | *
44 | * @param rs
45 | * ResultSet to process.
46 | * @return row processing result
47 | * @throws java.sql.SQLException
48 | * error occurs
49 | */
50 | protected abstract T handleRow(ResultSet rs) throws SQLException;
51 | }
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/handlers/ArrayListHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 | package com.opensource.dbhelp.dbutils.handlers;
5 |
6 | import java.sql.ResultSet;
7 | import java.sql.SQLException;
8 |
9 | import com.opensource.dbhelp.dbutils.RowProcessor;
10 |
11 | /**
12 | * ResultSetHandler implementation that converts the ResultSet into a List of Object[]s. This class is thread safe.
13 | *
14 | * @see com.opensource.dbhelp.dbutils.ResultSetHandler
15 | */
16 | public class ArrayListHandler extends AbstractListHandler
119 | */
120 | private final Map lowerCaseMap = new HashMap();
121 |
122 | /**
123 | * Required for serialization support.
124 | *
125 | * @see java.io.Serializable
126 | */
127 | private static final long serialVersionUID = -2848101435296897392L;
128 |
129 | /** {@inheritDoc} */
130 | @Override
131 | public boolean containsKey(Object key) {
132 | Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
133 | return super.containsKey(realKey);
134 | // Possible optimisation here:
135 | // Since the lowerCaseMap contains a mapping for all the keys,
136 | // we could just do this:
137 | // return lowerCaseMap.containsKey(key.toString().toLowerCase());
138 | }
139 |
140 | /** {@inheritDoc} */
141 | @Override
142 | public String get(Object key) {
143 | Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
144 | return super.get(realKey);
145 | }
146 |
147 | /** {@inheritDoc} */
148 | @Override
149 | public String put(String key, String value) {
150 | /*
151 | * 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))
152 | */
153 | Object oldKey = lowerCaseMap.put(key.toLowerCase(Locale.ENGLISH), key);
154 | String oldValue = super.remove(oldKey);
155 | super.put(key, value);
156 | return oldValue;
157 | }
158 |
159 | /** {@inheritDoc} */
160 | @Override
161 | public void putAll(Map extends String, ? extends String> m) {
162 | for (Map.Entry extends String, ? extends String> entry : m.entrySet()) {
163 | String key = entry.getKey();
164 | String value = entry.getValue();
165 | this.put(key, value);
166 | }
167 | }
168 |
169 | /** {@inheritDoc} */
170 | @Override
171 | public String remove(Object key) {
172 | Object realKey = lowerCaseMap.remove(key.toString().toLowerCase(Locale.ENGLISH));
173 | return super.remove(realKey);
174 | }
175 | }
176 |
177 | }
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/BasicRowProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 | package com.opensource.dbhelp.dbutils;
5 |
6 | import java.sql.ResultSet;
7 | import java.sql.ResultSetMetaData;
8 | import java.sql.SQLException;
9 | import java.util.HashMap;
10 | import java.util.List;
11 | import java.util.Locale;
12 | import java.util.Map;
13 |
14 | /**
15 | * Basic implementation of the RowProcessor interface.
16 | *
17 | * This class is thread-safe.
18 | *
19 | *
20 | * @see RowProcessor
21 | */
22 | public class BasicRowProcessor implements RowProcessor {
23 |
24 | /**
25 | * The default BeanProcessor instance to use if not supplied in the constructor.
26 | */
27 | private static final BeanProcessor defaultConvert = new BeanProcessor();
28 |
29 | /**
30 | * The Singleton instance of this class.
31 | */
32 | private static final BasicRowProcessor instance = new BasicRowProcessor();
33 |
34 | /**
35 | * Returns the Singleton instance of this class.
36 | *
37 | * @return The single instance of this class.
38 | * @deprecated Create instances with the constructors instead. This will be removed after DbUtils 1.1.
39 | */
40 | @Deprecated
41 | public static BasicRowProcessor instance() {
42 | return instance;
43 | }
44 |
45 | /**
46 | * Use this to process beans.
47 | */
48 | private final BeanProcessor convert;
49 |
50 | /**
51 | * BasicRowProcessor constructor. Bean processing defaults to a BeanProcessor instance.
52 | */
53 | public BasicRowProcessor() {
54 | this(defaultConvert);
55 | }
56 |
57 | /**
58 | * BasicRowProcessor constructor.
59 | *
60 | * @param convert
61 | * The BeanProcessor to use when converting columns to bean properties.
62 | * @since DbUtils 1.1
63 | */
64 | public BasicRowProcessor(BeanProcessor convert) {
65 | super();
66 | this.convert = convert;
67 | }
68 |
69 | /**
70 | * Convert a ResultSet row into an Object[]. This implementation copies column values into the array in the same order they're returned from the ResultSet. Array elements will be set to null if the column was SQL NULL.
71 | *
72 | * @see com.cplatform.dbhelp.dbutils.RowProcessor#toArray(java.sql.ResultSet)
73 | * @param rs
74 | * ResultSet that supplies the array data
75 | * @throws java.sql.SQLException
76 | * if a database access error occurs
77 | * @return the newly created array
78 | */
79 | @Override
80 | public Object[] toArray(ResultSet rs) throws SQLException {
81 | ResultSetMetaData meta = rs.getMetaData();
82 | int cols = meta.getColumnCount();
83 | Object[] result = new Object[cols];
84 |
85 | for (int i = 0; i < cols; i++) {
86 | result[i] = rs.getObject(i + 1);
87 | }
88 |
89 | return result;
90 | }
91 |
92 | /**
93 | * Convert a ResultSet row into a JavaBean. This implementation delegates to a BeanProcessor instance.
94 | *
95 | * @see com.cplatform.dbhelp.dbutils.RowProcessor#toBean(java.sql.ResultSet, Class)
96 | * @see com.cplatform.dbhelp.dbutils.BeanProcessor#toBean(java.sql.ResultSet, Class)
97 | * @param
98 | * The type of bean to create
99 | * @param rs
100 | * ResultSet that supplies the bean data
101 | * @param type
102 | * Class from which to create the bean instance
103 | * @throws java.sql.SQLException
104 | * if a database access error occurs
105 | * @return the newly created bean
106 | */
107 | @Override
108 | public T toBean(ResultSet rs, Class type) throws SQLException {
109 | return this.convert.toBean(rs, type);
110 | }
111 |
112 | /**
113 | * Convert a ResultSet into a List of JavaBeans. This implementation delegates to a BeanProcessor instance.
114 | *
115 | * @see com.cplatform.dbhelp.dbutils.RowProcessor#toBeanList(java.sql.ResultSet, Class)
116 | * @see com.cplatform.dbhelp.dbutils.BeanProcessor#toBeanList(java.sql.ResultSet, Class)
117 | * @param
118 | * The type of bean to create
119 | * @param rs
120 | * ResultSet that supplies the bean data
121 | * @param type
122 | * Class from which to create the bean instance
123 | * @throws java.sql.SQLException
124 | * if a database access error occurs
125 | * @return A List of beans with the given type in the order they were returned by the ResultSet.
126 | */
127 | @Override
128 | public List toBeanList(ResultSet rs, Class type) throws SQLException {
129 | return this.convert.toBeanList(rs, type);
130 | }
131 |
132 | /**
133 | * Convert a ResultSet row into a Map. This implementation returns a Map with case insensitive column names as keys. Calls to map.get("COL") and map.get("col") return the same value.
134 | *
135 | * @see com.cplatform.dbhelp.dbutils.RowProcessor#toMap(java.sql.ResultSet)
136 | * @param rs
137 | * ResultSet that supplies the map data
138 | * @throws java.sql.SQLException
139 | * if a database access error occurs
140 | * @return the newly created Map
141 | */
142 | @Override
143 | public Map toMap(ResultSet rs) throws SQLException {
144 | Map result = new CaseInsensitiveHashMap();
145 | ResultSetMetaData rsmd = rs.getMetaData();
146 | int cols = rsmd.getColumnCount();
147 |
148 | for (int i = 1; i <= cols; i++) {
149 | result.put(rsmd.getColumnName(i), rs.getObject(i));
150 | }
151 |
152 | return result;
153 | }
154 |
155 | /**
156 | * 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.
157 | *
158 | * 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.
159 | *
160 | * Note: This implementation does not allow null for key, whereas {@link java.util.HashMap} does, because of the code:
161 | *
162 | *
163 | * key.toString().toLowerCase()
164 | *
165 | */
166 | private static class CaseInsensitiveHashMap extends HashMap {
167 |
168 | /**
169 | * The internal mapping from lowercase keys to the real keys.
170 | *
171 | * Any query operation using the key ({@link #get(Object)}, {@link #containsKey(Object)}) is done in three steps:
172 | *
173 | *
convert the parameter key to lower case
174 | *
get the actual key that corresponds to the lower case key
175 | *
query the map with the actual key
176 | *
177 | *
178 | */
179 | private final Map lowerCaseMap = new HashMap();
180 |
181 | /**
182 | * Required for serialization support.
183 | *
184 | * @see java.io.Serializable
185 | */
186 | private static final long serialVersionUID = -2848100435296897392L;
187 |
188 | /** {@inheritDoc} */
189 | @Override
190 | public boolean containsKey(Object key) {
191 | Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
192 | return super.containsKey(realKey);
193 | // Possible optimisation here:
194 | // Since the lowerCaseMap contains a mapping for all the keys,
195 | // we could just do this:
196 | // return lowerCaseMap.containsKey(key.toString().toLowerCase());
197 | }
198 |
199 | /** {@inheritDoc} */
200 | @Override
201 | public Object get(Object key) {
202 | Object realKey = lowerCaseMap.get(key.toString().toLowerCase(Locale.ENGLISH));
203 | return super.get(realKey);
204 | }
205 |
206 | /** {@inheritDoc} */
207 | @Override
208 | public Object put(String key, Object value) {
209 | /*
210 | * 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))
211 | */
212 | Object oldKey = lowerCaseMap.put(key.toLowerCase(Locale.ENGLISH), key);
213 | Object oldValue = super.remove(oldKey);
214 | super.put(key, value);
215 | return oldValue;
216 | }
217 |
218 | /** {@inheritDoc} */
219 | @Override
220 | public void putAll(Map extends String, ?> m) {
221 | for (Map.Entry extends String, ?> entry : m.entrySet()) {
222 | String key = entry.getKey();
223 | Object value = entry.getValue();
224 | this.put(key, value);
225 | }
226 | }
227 |
228 | /** {@inheritDoc} */
229 | @Override
230 | public Object remove(Object key) {
231 | Object realKey = lowerCaseMap.remove(key.toString().toLowerCase(Locale.ENGLISH));
232 | return super.remove(realKey);
233 | }
234 | }
235 |
236 | }
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/DbUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 | package com.opensource.dbhelp.dbutils;
5 |
6 | import java.io.PrintWriter;
7 | import java.sql.Connection;
8 | import java.sql.ResultSet;
9 | import java.sql.SQLException;
10 | import java.sql.Statement;
11 |
12 | /**
13 | * A collection of JDBC helper methods. This class is thread safe.
14 | */
15 | public final class DbUtils {
16 |
17 | /**
18 | * Default constructor. Utility classes should not have a public or default constructor, but this one preserves retro-compatibility.
19 | *
20 | * @since 1.4
21 | */
22 | public DbUtils() {
23 | // do nothing
24 | }
25 |
26 | /**
27 | * Close a Connection, avoid closing if null.
28 | *
29 | * @param conn
30 | * Connection to close.
31 | * @throws java.sql.SQLException
32 | * if a database access error occurs
33 | */
34 | public static void close(Connection conn) throws SQLException {
35 | if (conn != null) {
36 | conn.close();
37 | }
38 | }
39 |
40 | /**
41 | * Close a ResultSet, avoid closing if null.
42 | *
43 | * @param rs
44 | * ResultSet to close.
45 | * @throws java.sql.SQLException
46 | * if a database access error occurs
47 | */
48 | public static void close(ResultSet rs) throws SQLException {
49 | if (rs != null) {
50 | rs.close();
51 | }
52 | }
53 |
54 | /**
55 | * Close a Statement, avoid closing if null.
56 | *
57 | * @param stmt
58 | * Statement to close.
59 | * @throws java.sql.SQLException
60 | * if a database access error occurs
61 | */
62 | public static void close(Statement stmt) throws SQLException {
63 | if (stmt != null) {
64 | stmt.close();
65 | }
66 | }
67 |
68 | /**
69 | * Close a Connection, avoid closing if null and hide any SQLExceptions that occur.
70 | *
71 | * @param conn
72 | * Connection to close.
73 | */
74 | public static void closeQuietly(Connection conn) {
75 | try {
76 | close(conn);
77 | }
78 | catch (SQLException e) { // NOPMD
79 | // quiet
80 | }
81 | }
82 |
83 | /**
84 | * Close a Connection, Statement and ResultSet. Avoid closing if null and hide any SQLExceptions that occur.
85 | *
86 | * @param conn
87 | * Connection to close.
88 | * @param stmt
89 | * Statement to close.
90 | * @param rs
91 | * ResultSet to close.
92 | */
93 | public static void closeQuietly(Connection conn, Statement stmt, ResultSet rs) {
94 |
95 | try {
96 | closeQuietly(rs);
97 | }
98 | finally {
99 | try {
100 | closeQuietly(stmt);
101 | }
102 | finally {
103 | closeQuietly(conn);
104 | }
105 | }
106 |
107 | }
108 |
109 | /**
110 | * Close a ResultSet, avoid closing if null and hide any SQLExceptions that occur.
111 | *
112 | * @param rs
113 | * ResultSet to close.
114 | */
115 | public static void closeQuietly(ResultSet rs) {
116 | try {
117 | close(rs);
118 | }
119 | catch (SQLException e) { // NOPMD
120 | // quiet
121 | }
122 | }
123 |
124 | /**
125 | * Close a Statement, avoid closing if null and hide any SQLExceptions that occur.
126 | *
127 | * @param stmt
128 | * Statement to close.
129 | */
130 | public static void closeQuietly(Statement stmt) {
131 | try {
132 | close(stmt);
133 | }
134 | catch (SQLException e) { // NOPMD
135 | // quiet
136 | }
137 | }
138 |
139 | /**
140 | * Commits a Connection then closes it, avoid closing if null.
141 | *
142 | * @param conn
143 | * Connection to close.
144 | * @throws java.sql.SQLException
145 | * if a database access error occurs
146 | */
147 | public static void commitAndClose(Connection conn) throws SQLException {
148 | if (conn != null) {
149 | try {
150 | conn.commit();
151 | }
152 | finally {
153 | conn.close();
154 | }
155 | }
156 | }
157 |
158 | /**
159 | * Commits a Connection then closes it, avoid closing if null and hide any SQLExceptions that occur.
160 | *
161 | * @param conn
162 | * Connection to close.
163 | */
164 | public static void commitAndCloseQuietly(Connection conn) {
165 | try {
166 | commitAndClose(conn);
167 | }
168 | catch (SQLException e) { // NOPMD
169 | // quiet
170 | }
171 | }
172 |
173 | /**
174 | * Loads and registers a database driver class. If this succeeds, it returns true, else it returns false.
175 | *
176 | * @param driverClassName
177 | * of driver to load
178 | * @return boolean true if the driver was found, otherwise false
179 | */
180 | public static boolean loadDriver(String driverClassName) {
181 | return loadDriver(DbUtils.class.getClassLoader(), driverClassName);
182 | }
183 |
184 | /**
185 | * Loads and registers a database driver class. If this succeeds, it returns true, else it returns false.
186 | *
187 | * @param classLoader
188 | * the class loader used to load the driver class
189 | * @param driverClassName
190 | * of driver to load
191 | * @return boolean true if the driver was found, otherwise false
192 | * @since 1.4
193 | */
194 | public static boolean loadDriver(ClassLoader classLoader, String driverClassName) {
195 | try {
196 | classLoader.loadClass(driverClassName).newInstance();
197 | return true;
198 |
199 | }
200 | catch (IllegalAccessException e) {
201 | // Constructor is private, OK for DriverManager contract
202 | return true;
203 |
204 | }
205 | catch (Exception e) {
206 | return false;
207 |
208 | }
209 | }
210 |
211 | /**
212 | * Print the stack trace for a SQLException to STDERR.
213 | *
214 | * @param e
215 | * SQLException to print stack trace of
216 | */
217 | public static void printStackTrace(SQLException e) {
218 | printStackTrace(e, new PrintWriter(System.err));
219 | }
220 |
221 | /**
222 | * Print the stack trace for a SQLException to a specified PrintWriter.
223 | *
224 | * @param e
225 | * SQLException to print stack trace of
226 | * @param pw
227 | * PrintWriter to print to
228 | */
229 | public static void printStackTrace(SQLException e, PrintWriter pw) {
230 |
231 | SQLException next = e;
232 | while (next != null) {
233 | next.printStackTrace(pw);
234 | next = next.getNextException();
235 | if (next != null) {
236 | pw.println("Next SQLException:");
237 | }
238 | }
239 | }
240 |
241 | /**
242 | * Print warnings on a Connection to STDERR.
243 | *
244 | * @param conn
245 | * Connection to print warnings from
246 | */
247 | public static void printWarnings(Connection conn) {
248 | printWarnings(conn, new PrintWriter(System.err));
249 | }
250 |
251 | /**
252 | * Print warnings on a Connection to a specified PrintWriter.
253 | *
254 | * @param conn
255 | * Connection to print warnings from
256 | * @param pw
257 | * PrintWriter to print to
258 | */
259 | public static void printWarnings(Connection conn, PrintWriter pw) {
260 | if (conn != null) {
261 | try {
262 | printStackTrace(conn.getWarnings(), pw);
263 | }
264 | catch (SQLException e) {
265 | printStackTrace(e, pw);
266 | }
267 | }
268 | }
269 |
270 | /**
271 | * Rollback any changes made on the given connection.
272 | *
273 | * @param conn
274 | * Connection to rollback. A null value is legal.
275 | * @throws java.sql.SQLException
276 | * if a database access error occurs
277 | */
278 | public static void rollback(Connection conn) throws SQLException {
279 | if (conn != null) {
280 | conn.rollback();
281 | }
282 | }
283 |
284 | /**
285 | * Performs a rollback on the Connection then closes it, avoid closing if null.
286 | *
287 | * @param conn
288 | * Connection to rollback. A null value is legal.
289 | * @throws java.sql.SQLException
290 | * if a database access error occurs
291 | * @since DbUtils 1.1
292 | */
293 | public static void rollbackAndClose(Connection conn) throws SQLException {
294 | if (conn != null) {
295 | try {
296 | conn.rollback();
297 | }
298 | finally {
299 | conn.close();
300 | }
301 | }
302 | }
303 |
304 | /**
305 | * Performs a rollback on the Connection then closes it, avoid closing if null and hide any SQLExceptions that occur.
306 | *
307 | * @param conn
308 | * Connection to rollback. A null value is legal.
309 | * @since DbUtils 1.1
310 | */
311 | public static void rollbackAndCloseQuietly(Connection conn) {
312 | try {
313 | rollbackAndClose(conn);
314 | }
315 | catch (SQLException e) { // NOPMD
316 | // quiet
317 | }
318 | }
319 |
320 | }
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/DbTransaction.java:
--------------------------------------------------------------------------------
1 | package com.opensource.dbhelp;
2 |
3 | import java.sql.Connection;
4 | import java.sql.SQLException;
5 | import java.util.List;
6 |
7 | import javax.sql.DataSource;
8 |
9 | import org.apache.commons.logging.Log;
10 | import org.apache.commons.logging.LogFactory;
11 |
12 | import com.opensource.dbhelp.dbutils.DbUtils;
13 | import com.opensource.dbhelp.dbutils.QueryRunner;
14 | import com.opensource.dbhelp.dbutils.handlers.BeanHandler;
15 | import com.opensource.dbhelp.dbutils.handlers.BeanListHandler;
16 | import com.opensource.dbhelp.dbutils.handlers.StringArrayHandler;
17 | import com.opensource.dbhelp.dbutils.handlers.StringArrayListHandler;
18 |
19 | /**
20 | * 数据库事务处理帮助类。
21 | *
22 | * 典型的调用方法如下:
23 | *
24 | *
317 | *
318 | * @param rs
319 | * The ResultSet to decorate; never null.
320 | * @return The ResultSet wrapped in some decorator.
321 | */
322 | protected ResultSet wrap(ResultSet rs) {
323 | return rs;
324 | }
325 |
326 | /**
327 | * Close a Connection. This implementation avoids closing if null and does not suppress any exceptions. Subclasses can override to provide special handling like logging.
328 | *
329 | * @param conn
330 | * Connection to close
331 | * @throws java.sql.SQLException
332 | * if a database access error occurs
333 | * @since DbUtils 1.1
334 | */
335 | protected void close(Connection conn) throws SQLException {
336 | DbUtils.close(conn);
337 | }
338 |
339 | /**
340 | * Close a Statement. This implementation avoids closing if null and does not suppress any exceptions. Subclasses can override to provide special handling like logging.
341 | *
342 | * @param stmt
343 | * Statement to close
344 | * @throws java.sql.SQLException
345 | * if a database access error occurs
346 | * @since DbUtils 1.1
347 | */
348 | protected void close(Statement stmt) throws SQLException {
349 | DbUtils.close(stmt);
350 | }
351 |
352 | /**
353 | * Close a ResultSet. This implementation avoids closing if null and does not suppress any exceptions. Subclasses can override to provide special handling like logging.
354 | *
355 | * @param rs
356 | * ResultSet to close
357 | * @throws java.sql.SQLException
358 | * if a database access error occurs
359 | * @since DbUtils 1.1
360 | */
361 | protected void close(ResultSet rs) throws SQLException {
362 | DbUtils.close(rs);
363 | }
364 |
365 | }
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/BeanProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 | package com.opensource.dbhelp.dbutils;
5 |
6 | import java.beans.BeanInfo;
7 | import java.beans.IntrospectionException;
8 | import java.beans.Introspector;
9 | import java.beans.PropertyDescriptor;
10 | import java.lang.reflect.InvocationTargetException;
11 | import java.lang.reflect.Method;
12 | import java.sql.ResultSet;
13 | import java.sql.ResultSetMetaData;
14 | import java.sql.SQLException;
15 | import java.sql.SQLXML;
16 | import java.sql.Timestamp;
17 | import java.util.ArrayList;
18 | import java.util.Arrays;
19 | import java.util.HashMap;
20 | import java.util.List;
21 | import java.util.Map;
22 |
23 | /**
24 | *
25 | * BeanProcessor matches column names to bean property names and converts ResultSet columns into objects for those bean properties. Subclasses should override the methods in the processing chain to customize behavior.
26 | *
27 | *
28 | * This class is thread-safe.
29 | *
30 | *
31 | * @see BasicRowProcessor
32 | * @since DbUtils 1.1
33 | */
34 | public class BeanProcessor {
35 |
36 | /**
37 | * Special array value used by mapColumnsToProperties that indicates there is no bean property that matches a column from a ResultSet.
38 | */
39 | protected static final int PROPERTY_NOT_FOUND = -1;
40 |
41 | /**
42 | * 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.
43 | */
44 | private static final Map, Object> primitiveDefaults = new HashMap, Object>();
45 |
46 | /**
47 | * ResultSet column to bean property name overrides.
48 | */
49 | private final Map columnToPropertyOverrides;
50 |
51 | static {
52 | primitiveDefaults.put(Integer.TYPE, Integer.valueOf(0));
53 | primitiveDefaults.put(Short.TYPE, Short.valueOf((short) 0));
54 | primitiveDefaults.put(Byte.TYPE, Byte.valueOf((byte) 0));
55 | primitiveDefaults.put(Float.TYPE, Float.valueOf(0f));
56 | primitiveDefaults.put(Double.TYPE, Double.valueOf(0d));
57 | primitiveDefaults.put(Long.TYPE, Long.valueOf(0L));
58 | primitiveDefaults.put(Boolean.TYPE, Boolean.FALSE);
59 | primitiveDefaults.put(Character.TYPE, Character.valueOf((char) 0));
60 | }
61 |
62 | /**
63 | * Constructor for BeanProcessor.
64 | */
65 | public BeanProcessor() {
66 | this(new HashMap());
67 | }
68 |
69 | /**
70 | * Constructor for BeanProcessor configured with column to property name overrides.
71 | *
72 | * @param columnToPropertyOverrides
73 | * ResultSet column to bean property name overrides
74 | * @since 1.5
75 | */
76 | public BeanProcessor(Map columnToPropertyOverrides) {
77 | super();
78 | if (columnToPropertyOverrides == null) {
79 | throw new IllegalArgumentException("columnToPropertyOverrides map cannot be null");
80 | }
81 | this.columnToPropertyOverrides = columnToPropertyOverrides;
82 | }
83 |
84 | /**
85 | * Convert a ResultSet row into a JavaBean. This implementation uses reflection and BeanInfo classes to match column names to bean property names. Properties are matched to columns based on several factors:
86 | *
87 | *
The class has a writable property with the same name as a column. The name comparison is case insensitive.
88 | *
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.
89 | *
90 | *
91 | * Primitive bean properties are set to their defaults when SQL NULL is returned from the ResultSet. Numeric fields are set to 0 and booleans are set to false. Object bean properties are set to null when SQL NULL is returned. This is the same behavior as the ResultSet get* methods.
92 | *
93 | *
94 | * @param
95 | * The type of bean to create
96 | * @param rs
97 | * ResultSet that supplies the bean data
98 | * @param type
99 | * Class from which to create the bean instance
100 | * @throws java.sql.SQLException
101 | * if a database access error occurs
102 | * @return the newly created bean
103 | */
104 | public T toBean(ResultSet rs, Class type) throws SQLException {
105 |
106 | PropertyDescriptor[] props = this.propertyDescriptors(type);
107 |
108 | ResultSetMetaData rsmd = rs.getMetaData();
109 | int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
110 |
111 | return this.createBean(rs, type, props, columnToProperty);
112 | }
113 |
114 | /**
115 | * Convert a ResultSet into a List of JavaBeans. This implementation uses reflection and BeanInfo classes to match column names to bean property names. Properties are matched to columns based on several factors:
116 | *
117 | *
The class has a writable property with the same name as a column. The name comparison is case insensitive.
118 | *
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.
119 | *
120 | *
121 | * Primitive bean properties are set to their defaults when SQL NULL is returned from the ResultSet. Numeric fields are set to 0 and booleans are set to false. Object bean properties are set to null when SQL NULL is returned. This is the same behavior as the ResultSet get* methods.
122 | *
123 | *
124 | * @param
125 | * The type of bean to create
126 | * @param rs
127 | * ResultSet that supplies the bean data
128 | * @param type
129 | * Class from which to create the bean instance
130 | * @throws java.sql.SQLException
131 | * if a database access error occurs
132 | * @return the newly created List of beans
133 | */
134 | public List toBeanList(ResultSet rs, Class type) throws SQLException {
135 | List results = new ArrayList();
136 |
137 | if (!rs.next()) {
138 | return results;
139 | }
140 |
141 | PropertyDescriptor[] props = this.propertyDescriptors(type);
142 | ResultSetMetaData rsmd = rs.getMetaData();
143 | int[] columnToProperty = this.mapColumnsToProperties(rsmd, props);
144 |
145 | do {
146 | results.add(this.createBean(rs, type, props, columnToProperty));
147 | }
148 | while (rs.next());
149 |
150 | return results;
151 | }
152 |
153 | /**
154 | * Creates a new object and initializes its fields from the ResultSet.
155 | *
156 | * @param
157 | * The type of bean to create
158 | * @param rs
159 | * The result set.
160 | * @param type
161 | * The bean type (the return type of the object).
162 | * @param props
163 | * The property descriptors.
164 | * @param columnToProperty
165 | * The column indices in the result set.
166 | * @return An initialized object.
167 | * @throws java.sql.SQLException
168 | * if a database error occurs.
169 | */
170 | private T createBean(ResultSet rs, Class type, PropertyDescriptor[] props, int[] columnToProperty) throws SQLException {
171 |
172 | T bean = this.newInstance(type);
173 |
174 | for (int i = 1; i < columnToProperty.length; i++) {
175 |
176 | if (columnToProperty[i] == PROPERTY_NOT_FOUND) {
177 | continue;
178 | }
179 |
180 | PropertyDescriptor prop = props[columnToProperty[i]];
181 | Class> propType = prop.getPropertyType();
182 |
183 | Object value = this.processColumn(rs, i, propType);
184 |
185 | if (propType != null && value == null && propType.isPrimitive()) {
186 | value = primitiveDefaults.get(propType);
187 | }
188 |
189 | this.callSetter(bean, prop, value);
190 | }
191 |
192 | return bean;
193 | }
194 |
195 | /**
196 | * Calls the setter method on the target object for the given property. If no setter method exists for the property, this method does nothing.
197 | *
198 | * @param target
199 | * The object to set the property on.
200 | * @param prop
201 | * The property to set.
202 | * @param value
203 | * The value to pass into the setter.
204 | * @throws java.sql.SQLException
205 | * if an error occurs setting the property.
206 | */
207 | private void callSetter(Object target, PropertyDescriptor prop, Object value) throws SQLException {
208 |
209 | Method setter = prop.getWriteMethod();
210 |
211 | if (setter == null) {
212 | return;
213 | }
214 |
215 | Class>[] params = setter.getParameterTypes();
216 | try {
217 | // convert types for some popular ones
218 | if (value instanceof java.util.Date) {
219 | final String targetType = params[0].getName();
220 | if ("java.sql.Date".equals(targetType)) {
221 | value = new java.sql.Date(((java.util.Date) value).getTime());
222 | } else if ("java.sql.Time".equals(targetType)) {
223 | value = new java.sql.Time(((java.util.Date) value).getTime());
224 | } else if ("java.sql.Timestamp".equals(targetType)) {
225 | value = new Timestamp(((java.util.Date) value).getTime());
226 | }
227 | }
228 |
229 | // Don't call setter if the value object isn't the right type
230 | if (this.isCompatibleType(value, params[0])) {
231 | setter.invoke(target, new Object[] { value });
232 | } else {
233 | throw new SQLException("Cannot set " + prop.getName() + ": incompatible types, cannot convert " + value.getClass().getName() + " to " + params[0].getName());
234 | // value cannot be null here because isCompatibleType allows null
235 | }
236 |
237 | }
238 | catch (IllegalArgumentException e) {
239 | throw new SQLException("Cannot set " + prop.getName() + ": " + e.getMessage());
240 |
241 | }
242 | catch (IllegalAccessException e) {
243 | throw new SQLException("Cannot set " + prop.getName() + ": " + e.getMessage());
244 |
245 | }
246 | catch (InvocationTargetException e) {
247 | throw new SQLException("Cannot set " + prop.getName() + ": " + e.getMessage());
248 | }
249 | }
250 |
251 | /**
252 | * 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.
253 | *
254 | * @param value
255 | * The value to be passed into the setter method.
256 | * @param type
257 | * The setter's parameter type (non-null)
258 | * @return boolean True if the value is compatible (null => true)
259 | */
260 | private boolean isCompatibleType(Object value, Class> type) {
261 | // Do object check first, then primitives
262 | if (value == null || type.isInstance(value)) {
263 | return true;
264 |
265 | } else if (type.equals(Integer.TYPE) && Integer.class.isInstance(value)) {
266 | return true;
267 |
268 | } else if (type.equals(Long.TYPE) && Long.class.isInstance(value)) {
269 | return true;
270 |
271 | } else if (type.equals(Double.TYPE) && Double.class.isInstance(value)) {
272 | return true;
273 |
274 | } else if (type.equals(Float.TYPE) && Float.class.isInstance(value)) {
275 | return true;
276 |
277 | } else if (type.equals(Short.TYPE) && Short.class.isInstance(value)) {
278 | return true;
279 |
280 | } else if (type.equals(Byte.TYPE) && Byte.class.isInstance(value)) {
281 | return true;
282 |
283 | } else if (type.equals(Character.TYPE) && Character.class.isInstance(value)) {
284 | return true;
285 |
286 | } else if (type.equals(Boolean.TYPE) && Boolean.class.isInstance(value)) {
287 | return true;
288 |
289 | }
290 | return false;
291 |
292 | }
293 |
294 | /**
295 | * 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.
296 | *
297 | * @param
298 | * The type of object to create
299 | * @param c
300 | * The Class to create an object from.
301 | * @return A newly created object of the Class.
302 | * @throws java.sql.SQLException
303 | * if creation failed.
304 | */
305 | protected T newInstance(Class c) throws SQLException {
306 | try {
307 | return c.newInstance();
308 |
309 | }
310 | catch (InstantiationException e) {
311 | throw new SQLException("Cannot create " + c.getName() + ": " + e.getMessage());
312 |
313 | }
314 | catch (IllegalAccessException e) {
315 | throw new SQLException("Cannot create " + c.getName() + ": " + e.getMessage());
316 | }
317 | }
318 |
319 | /**
320 | * Returns a PropertyDescriptor[] for the given Class.
321 | *
322 | * @param c
323 | * The Class to retrieve PropertyDescriptors for.
324 | * @return A PropertyDescriptor[] describing the Class.
325 | * @throws java.sql.SQLException
326 | * if introspection failed.
327 | */
328 | private PropertyDescriptor[] propertyDescriptors(Class> c) throws SQLException {
329 | // Introspector caches BeanInfo classes for better performance
330 | BeanInfo beanInfo = null;
331 | try {
332 | beanInfo = Introspector.getBeanInfo(c);
333 |
334 | }
335 | catch (IntrospectionException e) {
336 | throw new SQLException("Bean introspection failed: " + e.getMessage());
337 | }
338 |
339 | return beanInfo.getPropertyDescriptors();
340 | }
341 |
342 | /**
343 | * 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.
344 | *
345 | * @param rsmd
346 | * The ResultSetMetaData containing column information.
347 | * @param props
348 | * The bean property descriptors.
349 | * @throws java.sql.SQLException
350 | * if a database access error occurs
351 | * @return An int[] with column index to property index mappings. The 0th element is meaningless because JDBC column indexing starts at 1.
352 | */
353 | protected int[] mapColumnsToProperties(ResultSetMetaData rsmd, PropertyDescriptor[] props) throws SQLException {
354 |
355 | int cols = rsmd.getColumnCount();
356 | int[] columnToProperty = new int[cols + 1];
357 | Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
358 |
359 | for (int col = 1; col <= cols; col++) {
360 | String columnName = rsmd.getColumnLabel(col);
361 | if (null == columnName || 0 == columnName.length()) {
362 | columnName = rsmd.getColumnName(col);
363 | }
364 | String propertyName = columnToPropertyOverrides.get(columnName);
365 | if (propertyName == null) {
366 | propertyName = columnName;
367 | }
368 | for (int i = 0; i < props.length; i++) {
369 |
370 | if (propertyName.equalsIgnoreCase(props[i].getName())) {
371 | columnToProperty[col] = i;
372 | break;
373 | }
374 | }
375 | }
376 |
377 | return columnToProperty;
378 | }
379 |
380 | /**
381 | * Convert a ResultSet column into an object. Simple implementations could just call rs.getObject(index) while more complex implementations could perform type manipulation to match the column's type to the bean property type.
382 | *
383 | * This implementation calls the appropriate ResultSet getter method for the given property type to perform the type conversion. If the property type doesn't match one of the supported ResultSet types, getObject is called.
384 | *
385 | *
386 | * @param rs
387 | * The ResultSet currently being processed. It is positioned on a valid row before being passed into this method.
388 | * @param index
389 | * The current column index being processed.
390 | * @param propType
391 | * The bean property type that this column needs to be converted into.
392 | * @throws java.sql.SQLException
393 | * if a database access error occurs
394 | * @return The object from the ResultSet at the given column index after optional type processing or null if the column value was SQL NULL.
395 | */
396 | protected Object processColumn(ResultSet rs, int index, Class> propType) throws SQLException {
397 |
398 | if (!propType.isPrimitive() && rs.getObject(index) == null) {
399 | return null;
400 | }
401 |
402 | if (propType.equals(String.class)) {
403 | return rs.getString(index);
404 |
405 | } else if (propType.equals(Integer.TYPE) || propType.equals(Integer.class)) {
406 | return Integer.valueOf(rs.getInt(index));
407 |
408 | } else if (propType.equals(Boolean.TYPE) || propType.equals(Boolean.class)) {
409 | return Boolean.valueOf(rs.getBoolean(index));
410 |
411 | } else if (propType.equals(Long.TYPE) || propType.equals(Long.class)) {
412 | return Long.valueOf(rs.getLong(index));
413 |
414 | } else if (propType.equals(Double.TYPE) || propType.equals(Double.class)) {
415 | return Double.valueOf(rs.getDouble(index));
416 |
417 | } else if (propType.equals(Float.TYPE) || propType.equals(Float.class)) {
418 | return Float.valueOf(rs.getFloat(index));
419 |
420 | } else if (propType.equals(Short.TYPE) || propType.equals(Short.class)) {
421 | return Short.valueOf(rs.getShort(index));
422 |
423 | } else if (propType.equals(Byte.TYPE) || propType.equals(Byte.class)) {
424 | return Byte.valueOf(rs.getByte(index));
425 |
426 | } else if (propType.equals(Timestamp.class)) {
427 | return rs.getTimestamp(index);
428 |
429 | } else if (propType.equals(SQLXML.class)) {
430 | return rs.getSQLXML(index);
431 |
432 | } else {
433 | return rs.getObject(index);
434 | }
435 |
436 | }
437 |
438 | }
--------------------------------------------------------------------------------
/DbHelper/src/main/java/com/opensource/dbhelp/dbutils/wrappers/SqlNullCheckedResultSet.java:
--------------------------------------------------------------------------------
1 | /*
2 | * 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.
3 | */
4 | package com.opensource.dbhelp.dbutils.wrappers;
5 |
6 | import java.io.InputStream;
7 | import java.io.Reader;
8 | import java.lang.reflect.InvocationHandler;
9 | import java.lang.reflect.Method;
10 | import java.math.BigDecimal;
11 | import java.net.URL;
12 | import java.sql.Blob;
13 | import java.sql.Clob;
14 | import java.sql.Date;
15 | import java.sql.Ref;
16 | import java.sql.ResultSet;
17 | import java.sql.Time;
18 | import java.sql.Timestamp;
19 | import java.util.HashMap;
20 | import java.util.Map;
21 |
22 | import com.opensource.dbhelp.dbutils.ProxyFactory;
23 |
24 | /**
25 | * Decorates a ResultSet with checks for a SQL NULL value on each getXXX method. If a column value obtained by a getXXX method is not SQL NULL, the column value is returned. If the column value is SQL null, an alternate value is returned. The alternate value defaults to the Java null value, which can be overridden for instances of the class.
26 | *
27 | * Usage example:
28 | *
29 | *
30 | * Connection conn = // somehow get a connection
31 | * Statement stmt = conn.createStatement();
32 | * ResultSet rs = stmt.executeQuery("SELECT col1, col2 FROM table1");
33 | *
34 | * // Wrap the result set for SQL NULL checking
35 | * SqlNullCheckedResultSet wrapper = new SqlNullCheckedResultSet(rs);
36 | * wrapper.setNullString("---N/A---"); // Set null string
37 | * wrapper.setNullInt(-999); // Set null integer
38 | * rs = ProxyFactory.instance().createResultSet(wrapper);
39 | *
40 | * while (rs.next()) {
41 | * // If col1 is SQL NULL, value returned will be "---N/A---"
42 | * String col1 = rs.getString("col1");
43 | * // If col2 is SQL NULL, value returned will be -999
44 | * int col2 = rs.getInt("col2");
45 | * }
46 | * rs.close();
47 | *
48 | *
49 | *
50 | *
51 | *
52 | * Unlike some other classes in DbUtils, this class is NOT thread-safe.
53 | *
54 | */
55 | public class SqlNullCheckedResultSet implements InvocationHandler {
56 |
57 | /**
58 | * Maps normal method names (ie. "getBigDecimal") to the corresponding null Method object (ie. getNullBigDecimal).
59 | */
60 | private static final Map nullMethods = new HashMap();
61 |
62 | /**
63 | * The {@code getNull} string prefix.
64 | *
65 | * @since 1.4
66 | */
67 | private static final String GET_NULL_PREFIX = "getNull";
68 |
69 | static {
70 | Method[] methods = SqlNullCheckedResultSet.class.getMethods();
71 | for (int i = 0; i < methods.length; i++) {
72 | String methodName = methods[i].getName();
73 |
74 | if (methodName.startsWith(GET_NULL_PREFIX)) {
75 | String normalName = "get" + methodName.substring(GET_NULL_PREFIX.length());
76 | nullMethods.put(normalName, methods[i]);
77 | }
78 | }
79 | }
80 |
81 | /**
82 | * The factory to create proxies with.
83 | */
84 | private static final ProxyFactory factory = ProxyFactory.instance();
85 |
86 | /**
87 | * Wraps the ResultSet in an instance of this class. This is equivalent to:
88 | *
89 | *
92 | *
93 | * @param rs
94 | * The ResultSet to wrap.
95 | * @return wrapped ResultSet
96 | */
97 | public static ResultSet wrap(ResultSet rs) {
98 | return factory.createResultSet(new SqlNullCheckedResultSet(rs));
99 | }
100 |
101 | private InputStream nullAsciiStream = null;
102 |
103 | private BigDecimal nullBigDecimal = null;
104 |
105 | private InputStream nullBinaryStream = null;
106 |
107 | private Blob nullBlob = null;
108 |
109 | private boolean nullBoolean = false;
110 |
111 | private byte nullByte = 0;
112 |
113 | private byte[] nullBytes = null;
114 |
115 | private Reader nullCharacterStream = null;
116 |
117 | private Clob nullClob = null;
118 |
119 | private Date nullDate = null;
120 |
121 | private double nullDouble = 0.0;
122 |
123 | private float nullFloat = 0.0f;
124 |
125 | private int nullInt = 0;
126 |
127 | private long nullLong = 0;
128 |
129 | private Object nullObject = null;
130 |
131 | private Ref nullRef = null;
132 |
133 | private short nullShort = 0;
134 |
135 | private String nullString = null;
136 |
137 | private Time nullTime = null;
138 |
139 | private Timestamp nullTimestamp = null;
140 |
141 | private URL nullURL = null;
142 |
143 | /**
144 | * The wrapped result.
145 | */
146 | private final ResultSet rs;
147 |
148 | /**
149 | * Constructs a new instance of SqlNullCheckedResultSet to wrap the specified ResultSet.
150 | *
151 | * @param rs
152 | * ResultSet to wrap
153 | */
154 | public SqlNullCheckedResultSet(ResultSet rs) {
155 | super();
156 | this.rs = rs;
157 | }
158 |
159 | /**
160 | * Returns the value when a SQL null is encountered as the result of invoking a getAsciiStream method.
161 | *
162 | * @return the value
163 | */
164 | public InputStream getNullAsciiStream() {
165 | return this.nullAsciiStream;
166 | }
167 |
168 | /**
169 | * Returns the value when a SQL null is encountered as the result of invoking a getBigDecimal method.
170 | *
171 | * @return the value
172 | */
173 | public BigDecimal getNullBigDecimal() {
174 | return this.nullBigDecimal;
175 | }
176 |
177 | /**
178 | * Returns the value when a SQL null is encountered as the result of invoking a getBinaryStream method.
179 | *
180 | * @return the value
181 | */
182 | public InputStream getNullBinaryStream() {
183 | return this.nullBinaryStream;
184 | }
185 |
186 | /**
187 | * Returns the value when a SQL null is encountered as the result of invoking a getBlob method.
188 | *
189 | * @return the value
190 | */
191 | public Blob getNullBlob() {
192 | return this.nullBlob;
193 | }
194 |
195 | /**
196 | * Returns the value when a SQL null is encountered as the result of invoking a getBoolean method.
197 | *
198 | * @return the value
199 | */
200 | public boolean getNullBoolean() {
201 | return this.nullBoolean;
202 | }
203 |
204 | /**
205 | * Returns the value when a SQL null is encountered as the result of invoking a getByte method.
206 | *
207 | * @return the value
208 | */
209 | public byte getNullByte() {
210 | return this.nullByte;
211 | }
212 |
213 | /**
214 | * Returns the value when a SQL null is encountered as the result of invoking a getBytes method.
215 | *
216 | * @return the value
217 | */
218 | public byte[] getNullBytes() {
219 | if (this.nullBytes == null) {
220 | return null;
221 | }
222 | byte[] copy = new byte[this.nullBytes.length];
223 | System.arraycopy(this.nullBytes, 0, copy, 0, this.nullBytes.length);
224 | return copy;
225 | }
226 |
227 | /**
228 | * Returns the value when a SQL null is encountered as the result of invoking a getCharacterStream method.
229 | *
230 | * @return the value
231 | */
232 | public Reader getNullCharacterStream() {
233 | return this.nullCharacterStream;
234 | }
235 |
236 | /**
237 | * Returns the value when a SQL null is encountered as the result of invoking a getClob method.
238 | *
239 | * @return the value
240 | */
241 | public Clob getNullClob() {
242 | return this.nullClob;
243 | }
244 |
245 | /**
246 | * Returns the value when a SQL null is encountered as the result of invoking a getDate method.
247 | *
248 | * @return the value
249 | */
250 | public Date getNullDate() {
251 | return this.nullDate;
252 | }
253 |
254 | /**
255 | * Returns the value when a SQL null is encountered as the result of invoking a getDouble method.
256 | *
257 | * @return the value
258 | */
259 | public double getNullDouble() {
260 | return this.nullDouble;
261 | }
262 |
263 | /**
264 | * Returns the value when a SQL null is encountered as the result of invoking a getFloat method.
265 | *
266 | * @return the value
267 | */
268 | public float getNullFloat() {
269 | return this.nullFloat;
270 | }
271 |
272 | /**
273 | * Returns the value when a SQL null is encountered as the result of invoking a getInt method.
274 | *
275 | * @return the value
276 | */
277 | public int getNullInt() {
278 | return this.nullInt;
279 | }
280 |
281 | /**
282 | * Returns the value when a SQL null is encountered as the result of invoking a getLong method.
283 | *
284 | * @return the value
285 | */
286 | public long getNullLong() {
287 | return this.nullLong;
288 | }
289 |
290 | /**
291 | * Returns the value when a SQL null is encountered as the result of invoking a getObject method.
292 | *
293 | * @return the value
294 | */
295 | public Object getNullObject() {
296 | return this.nullObject;
297 | }
298 |
299 | /**
300 | * Returns the value when a SQL null is encountered as the result of invoking a getRef method.
301 | *
302 | * @return the value
303 | */
304 | public Ref getNullRef() {
305 | return this.nullRef;
306 | }
307 |
308 | /**
309 | * Returns the value when a SQL null is encountered as the result of invoking a getShort method.
310 | *
311 | * @return the value
312 | */
313 | public short getNullShort() {
314 | return this.nullShort;
315 | }
316 |
317 | /**
318 | * Returns the value when a SQL null is encountered as the result of invoking a getString method.
319 | *
320 | * @return the value
321 | */
322 | public String getNullString() {
323 | return this.nullString;
324 | }
325 |
326 | /**
327 | * Returns the value when a SQL null is encountered as the result of invoking a getTime method.
328 | *
329 | * @return the value
330 | */
331 | public Time getNullTime() {
332 | return this.nullTime;
333 | }
334 |
335 | /**
336 | * Returns the value when a SQL null is encountered as the result of invoking a getTimestamp method.
337 | *
338 | * @return the value
339 | */
340 | public Timestamp getNullTimestamp() {
341 | return this.nullTimestamp;
342 | }
343 |
344 | /**
345 | * Returns the value when a SQL null is encountered as the result of invoking a getURL method.
346 | *
347 | * @return the value
348 | */
349 | public URL getNullURL() {
350 | return this.nullURL;
351 | }
352 |
353 | /**
354 | * Intercepts calls to get* methods and calls the appropriate getNull* method if the ResultSet returned null.
355 | *
356 | * @see java.lang.reflect.InvocationHandler#invoke(Object, java.lang.reflect.Method, Object[])
357 | * @param proxy
358 | * Not used; all method calls go to the internal result set
359 | * @param method
360 | * The method to invoke on the result set
361 | * @param args
362 | * The arguments to pass to the result set
363 | * @return null checked result
364 | * @throws Throwable
365 | * error
366 | */
367 | @Override
368 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
369 |
370 | Object result = method.invoke(this.rs, args);
371 |
372 | Method nullMethod = nullMethods.get(method.getName());
373 |
374 | // Check nullMethod != null first so that we don't call wasNull()
375 | // before a true getter method was invoked on the ResultSet.
376 | return (nullMethod != null && this.rs.wasNull()) ? nullMethod.invoke(this, (Object[]) null) : result;
377 | }
378 |
379 | /**
380 | * Sets the value to return when a SQL null is encountered as the result of invoking a getAsciiStream method.
381 | *
382 | * @param nullAsciiStream
383 | * the value
384 | */
385 | public void setNullAsciiStream(InputStream nullAsciiStream) {
386 | this.nullAsciiStream = nullAsciiStream;
387 | }
388 |
389 | /**
390 | * Sets the value to return when a SQL null is encountered as the result of invoking a getBigDecimal method.
391 | *
392 | * @param nullBigDecimal
393 | * the value
394 | */
395 | public void setNullBigDecimal(BigDecimal nullBigDecimal) {
396 | this.nullBigDecimal = nullBigDecimal;
397 | }
398 |
399 | /**
400 | * Sets the value to return when a SQL null is encountered as the result of invoking a getBinaryStream method.
401 | *
402 | * @param nullBinaryStream
403 | * the value
404 | */
405 | public void setNullBinaryStream(InputStream nullBinaryStream) {
406 | this.nullBinaryStream = nullBinaryStream;
407 | }
408 |
409 | /**
410 | * Sets the value to return when a SQL null is encountered as the result of invoking a getBlob method.
411 | *
412 | * @param nullBlob
413 | * the value
414 | */
415 | public void setNullBlob(Blob nullBlob) {
416 | this.nullBlob = nullBlob;
417 | }
418 |
419 | /**
420 | * Sets the value to return when a SQL null is encountered as the result of invoking a getBoolean method.
421 | *
422 | * @param nullBoolean
423 | * the value
424 | */
425 | public void setNullBoolean(boolean nullBoolean) {
426 | this.nullBoolean = nullBoolean;
427 | }
428 |
429 | /**
430 | * Sets the value to return when a SQL null is encountered as the result of invoking a getByte method.
431 | *
432 | * @param nullByte
433 | * the value
434 | */
435 | public void setNullByte(byte nullByte) {
436 | this.nullByte = nullByte;
437 | }
438 |
439 | /**
440 | * Sets the value to return when a SQL null is encountered as the result of invoking a getBytes method.
441 | *
442 | * @param nullBytes
443 | * the value
444 | */
445 | public void setNullBytes(byte[] nullBytes) {
446 | byte[] copy = new byte[nullBytes.length];
447 | System.arraycopy(nullBytes, 0, copy, 0, nullBytes.length);
448 | this.nullBytes = copy;
449 | }
450 |
451 | /**
452 | * Sets the value to return when a SQL null is encountered as the result of invoking a getCharacterStream method.
453 | *
454 | * @param nullCharacterStream
455 | * the value
456 | */
457 | public void setNullCharacterStream(Reader nullCharacterStream) {
458 | this.nullCharacterStream = nullCharacterStream;
459 | }
460 |
461 | /**
462 | * Sets the value to return when a SQL null is encountered as the result of invoking a getClob method.
463 | *
464 | * @param nullClob
465 | * the value
466 | */
467 | public void setNullClob(Clob nullClob) {
468 | this.nullClob = nullClob;
469 | }
470 |
471 | /**
472 | * Sets the value to return when a SQL null is encountered as the result of invoking a getDate method.
473 | *
474 | * @param nullDate
475 | * the value
476 | */
477 | public void setNullDate(Date nullDate) {
478 | this.nullDate = nullDate;
479 | }
480 |
481 | /**
482 | * Sets the value to return when a SQL null is encountered as the result of invoking a getDouble method.
483 | *
484 | * @param nullDouble
485 | * the value
486 | */
487 | public void setNullDouble(double nullDouble) {
488 | this.nullDouble = nullDouble;
489 | }
490 |
491 | /**
492 | * Sets the value to return when a SQL null is encountered as the result of invoking a getFloat method.
493 | *
494 | * @param nullFloat
495 | * the value
496 | */
497 | public void setNullFloat(float nullFloat) {
498 | this.nullFloat = nullFloat;
499 | }
500 |
501 | /**
502 | * Sets the value to return when a SQL null is encountered as the result of invoking a getInt method.
503 | *
504 | * @param nullInt
505 | * the value
506 | */
507 | public void setNullInt(int nullInt) {
508 | this.nullInt = nullInt;
509 | }
510 |
511 | /**
512 | * Sets the value to return when a SQL null is encountered as the result of invoking a getLong method.
513 | *
514 | * @param nullLong
515 | * the value
516 | */
517 | public void setNullLong(long nullLong) {
518 | this.nullLong = nullLong;
519 | }
520 |
521 | /**
522 | * Sets the value to return when a SQL null is encountered as the result of invoking a getObject method.
523 | *
524 | * @param nullObject
525 | * the value
526 | */
527 | public void setNullObject(Object nullObject) {
528 | this.nullObject = nullObject;
529 | }
530 |
531 | /**
532 | * Sets the value to return when a SQL null is encountered as the result of invoking a getRef method.
533 | *
534 | * @param nullRef
535 | * the value
536 | */
537 | public void setNullRef(Ref nullRef) {
538 | this.nullRef = nullRef;
539 | }
540 |
541 | /**
542 | * Sets the value to return when a SQL null is encountered as the result of invoking a getShort method.
543 | *
544 | * @param nullShort
545 | * the value
546 | */
547 | public void setNullShort(short nullShort) {
548 | this.nullShort = nullShort;
549 | }
550 |
551 | /**
552 | * Sets the value to return when a SQL null is encountered as the result of invoking a getString method.
553 | *
554 | * @param nullString
555 | * the value
556 | */
557 | public void setNullString(String nullString) {
558 | this.nullString = nullString;
559 | }
560 |
561 | /**
562 | * Sets the value to return when a SQL null is encountered as the result of invoking a getTime method.
563 | *
564 | * @param nullTime
565 | * the value
566 | */
567 | public void setNullTime(Time nullTime) {
568 | this.nullTime = nullTime;
569 | }
570 |
571 | /**
572 | * Sets the value to return when a SQL null is encountered as the result of invoking a getTimestamp method.
573 | *
574 | * @param nullTimestamp
575 | * the value
576 | */
577 | public void setNullTimestamp(Timestamp nullTimestamp) {
578 | this.nullTimestamp = nullTimestamp;
579 | }
580 |
581 | /**
582 | * Sets the value to return when a SQL null is encountered as the result of invoking a getURL method.
583 | *
584 | * @param nullURL
585 | * the value
586 | */
587 | public void setNullURL(URL nullURL) {
588 | this.nullURL = nullURL;
589 | }
590 |
591 | }
--------------------------------------------------------------------------------