001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 019 package org.apache.commons.beanutils; 020 021 022 import java.sql.ResultSet; 023 import java.sql.SQLException; 024 import java.util.Iterator; 025 026 027 /** 028 * <p>Implementation of <code>DynaClass</code> for DynaBeans that wrap the 029 * <code>java.sql.Row</code> objects of a <code>java.sql.ResultSet</code>. 030 * The normal usage pattern is something like:</p> 031 * <pre> 032 * ResultSet rs = ...; 033 * ResultSetDynaClass rsdc = new ResultSetDynaClass(rs); 034 * Iterator rows = rsdc.iterator(); 035 * while (rows.hasNext()) { 036 * DynaBean row = (DynaBean) rows.next(); 037 * ... process this row ... 038 * } 039 * rs.close(); 040 * </pre> 041 * 042 * <p>Each column in the result set will be represented as a DynaBean 043 * property of the corresponding name (optionally forced to lower case 044 * for portability).</p> 045 * 046 * <p><strong>WARNING</strong> - Any {@link DynaBean} instance returned by 047 * this class, or from the <code>Iterator</code> returned by the 048 * <code>iterator()</code> method, is directly linked to the row that the 049 * underlying result set is currently positioned at. This has the following 050 * implications:</p> 051 * <ul> 052 * <li>Once you retrieve a different {@link DynaBean} instance, you should 053 * no longer use any previous instance.</li> 054 * <li>Changing the position of the underlying result set will change the 055 * data that the {@link DynaBean} references.</li> 056 * <li>Once the underlying result set is closed, the {@link DynaBean} 057 * instance may no longer be used.</li> 058 * </ul> 059 * 060 * <p>Any database data that you wish to utilize outside the context of the 061 * current row of an open result set must be copied. For example, you could 062 * use the following code to create standalone copies of the information in 063 * a result set:</p> 064 * <pre> 065 * ArrayList results = new ArrayList(); // To hold copied list 066 * ResultSetDynaClass rsdc = ...; 067 * DynaProperty[] properties = rsdc.getDynaProperties(); 068 * BasicDynaClass bdc = 069 * new BasicDynaClass("foo", BasicDynaBean.class, 070 * rsdc.getDynaProperties()); 071 * Iterator rows = rsdc.iterator(); 072 * while (rows.hasNext()) { 073 * DynaBean oldRow = (DynaBean) rows.next(); 074 * DynaBean newRow = bdc.newInstance(); 075 * PropertyUtils.copyProperties(newRow, oldRow); 076 * results.add(newRow); 077 * } 078 * </pre> 079 * 080 * @author Craig R. McClanahan 081 * @version $Revision: 926685 $ $Date: 2010-03-23 17:59:08 +0000 (Tue, 23 Mar 2010) $ 082 */ 083 084 public class ResultSetDynaClass extends JDBCDynaClass implements DynaClass { 085 086 087 // ----------------------------------------------------------- Constructors 088 089 090 /** 091 * <p>Construct a new ResultSetDynaClass for the specified 092 * <code>ResultSet</code>. The property names corresponding 093 * to column names in the result set will be lower cased.</p> 094 * 095 * @param resultSet The result set to be wrapped 096 * 097 * @exception NullPointerException if <code>resultSet</code> 098 * is <code>null</code> 099 * @exception SQLException if the metadata for this result set 100 * cannot be introspected 101 */ 102 public ResultSetDynaClass(ResultSet resultSet) throws SQLException { 103 104 this(resultSet, true); 105 106 } 107 108 109 /** 110 * <p>Construct a new ResultSetDynaClass for the specified 111 * <code>ResultSet</code>. The property names corresponding 112 * to the column names in the result set will be lower cased or not, 113 * depending on the specified <code>lowerCase</code> value.</p> 114 * 115 * <p><strong>WARNING</strong> - If you specify <code>false</code> 116 * for <code>lowerCase</code>, the returned property names will 117 * exactly match the column names returned by your JDBC driver. 118 * Because different drivers might return column names in different 119 * cases, the property names seen by your application will vary 120 * depending on which JDBC driver you are using.</p> 121 * 122 * @param resultSet The result set to be wrapped 123 * @param lowerCase Should property names be lower cased? 124 * 125 * @exception NullPointerException if <code>resultSet</code> 126 * is <code>null</code> 127 * @exception SQLException if the metadata for this result set 128 * cannot be introspected 129 */ 130 public ResultSetDynaClass(ResultSet resultSet, boolean lowerCase) 131 throws SQLException { 132 133 this(resultSet, lowerCase, false); 134 135 } 136 137 138 /** 139 * <p>Construct a new ResultSetDynaClass for the specified 140 * <code>ResultSet</code>. The property names corresponding 141 * to the column names in the result set will be lower cased or not, 142 * depending on the specified <code>lowerCase</code> value.</p> 143 * 144 * <p><strong>WARNING</strong> - If you specify <code>false</code> 145 * for <code>lowerCase</code>, the returned property names will 146 * exactly match the column names returned by your JDBC driver. 147 * Because different drivers might return column names in different 148 * cases, the property names seen by your application will vary 149 * depending on which JDBC driver you are using.</p> 150 * 151 * @param resultSet The result set to be wrapped 152 * @param lowerCase Should property names be lower cased? 153 * @param useColumnLabel true if the column label should be used, otherwise false 154 * 155 * @exception NullPointerException if <code>resultSet</code> 156 * is <code>null</code> 157 * @exception SQLException if the metadata for this result set 158 * cannot be introspected 159 * @since 1.8.3 160 */ 161 public ResultSetDynaClass(ResultSet resultSet, boolean lowerCase, boolean useColumnLabel) 162 throws SQLException { 163 164 if (resultSet == null) { 165 throw new NullPointerException(); 166 } 167 this.resultSet = resultSet; 168 this.lowerCase = lowerCase; 169 setUseColumnLabel(useColumnLabel); 170 introspect(resultSet); 171 172 } 173 174 175 // ----------------------------------------------------- Instance Variables 176 177 178 /** 179 * <p>The <code>ResultSet</code> we are wrapping.</p> 180 */ 181 protected ResultSet resultSet = null; 182 183 184 // --------------------------------------------------------- Public Methods 185 186 187 /** 188 * <p>Return an <code>Iterator</code> of {@link DynaBean} instances for 189 * each row of the wrapped <code>ResultSet</code>, in "forward" order. 190 * Unless the underlying result set supports scrolling, this method 191 * should be called only once.</p> 192 * @return An <code>Iterator</code> of {@link DynaBean} instances 193 */ 194 public Iterator iterator() { 195 196 return (new ResultSetIterator(this)); 197 198 } 199 200 201 /** 202 * Get a value from the {@link ResultSet} for the specified 203 * property name. 204 * 205 * @param name The property name 206 * @return The value 207 * @throws SQLException if an error occurs 208 * @since 1.8.0 209 */ 210 public Object getObjectFromResultSet(String name) throws SQLException { 211 return getObject(getResultSet(), name); 212 } 213 214 // -------------------------------------------------------- Package Methods 215 216 217 /** 218 * <p>Return the result set we are wrapping.</p> 219 */ 220 ResultSet getResultSet() { 221 222 return (this.resultSet); 223 224 } 225 226 227 // ------------------------------------------------------ Protected Methods 228 229 /** 230 * <p>Loads the class of the given name which by default uses the class loader used 231 * to load this library. 232 * Dervations of this class could implement alternative class loading policies such as 233 * using custom ClassLoader or using the Threads's context class loader etc. 234 * </p> 235 * @param className The name of the class to load 236 * @return The loaded class 237 * @throws SQLException if the class cannot be loaded 238 */ 239 protected Class loadClass(String className) throws SQLException { 240 241 try { 242 return getClass().getClassLoader().loadClass(className); 243 } 244 catch (Exception e) { 245 throw new SQLException("Cannot load column class '" + 246 className + "': " + e); 247 } 248 } 249 }