RowSetDynaClass.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.beanutils2.sql;
- import java.sql.ResultSet;
- import java.sql.SQLException;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Objects;
- import org.apache.commons.beanutils2.BasicDynaBean;
- import org.apache.commons.beanutils2.DynaBean;
- import org.apache.commons.beanutils2.DynaClass;
- import org.apache.commons.beanutils2.DynaProperty;
- /**
- * <p>
- * Implements {@link DynaClass} to create an in-memory collection of {@link DynaBean}s representing the results of an SQL query. Once the {@link DynaClass}
- * instance has been created, the JDBC {@code ResultSet} and {@code Statement} on which it is based can be closed, and the underlying {@code Connection} can be
- * returned to its connection pool (if you are using one).
- * </p>
- *
- * <p>
- * The normal usage pattern is something like:
- * </p>
- *
- * <pre>
- * Connection conn = ...; // Acquire connection from pool
- * Statement stmt = conn.createStatement();
- * ResultSet rs = stmt.executeQuery("SELECT ...");
- * RowSetDynaClass rsdc = new RowSetDynaClass(rs);
- * rs.close();
- * stmt.close();
- * ...; // Return connection to pool
- * List rows = rsdc.getRows();
- * ...; // Process the rows as desired
- * </pre>
- *
- * <p>
- * Each column in the result set will be represented as a {@link DynaBean} property of the corresponding name (optionally forced to lower case for portability).
- * There will be one {@link DynaBean} in the {@code List</code> returned by <code>getRows()} for each row in the original {@code ResultSet}.
- * </p>
- *
- * <p>
- * In general, instances of {@link RowSetDynaClass} can be serialized and deserialized, which will automatically include the list of {@link DynaBean}s
- * representing the data content. The only exception to this rule would be when the underlying property values that were copied from the {@code ResultSet}
- * originally cannot themselves be serialized. Therefore, a {@link RowSetDynaClass} makes a very convenient mechanism for transporting data sets to remote
- * Java-based application components.
- * </p>
- */
- public class RowSetDynaClass extends AbstractJdbcDynaClass {
- /**
- * <p>
- * Limits the size of the returned list. The call to {@code getRows()} will return at most limit number of rows. If less than or equal to 0, does not limit
- * the size of the result.
- */
- protected int limit = -1;
- /**
- * <p>
- * The list of {@link DynaBean}s representing the contents of the original {@code ResultSet} on which this {@link RowSetDynaClass} was based.
- * </p>
- */
- protected List<DynaBean> rows = new ArrayList<>();
- /**
- * <p>
- * Constructs a new {@link RowSetDynaClass} for the specified {@code ResultSet}. The property names corresponding to column names in the result set will be
- * lower cased.
- * </p>
- *
- * @param resultSet The result set to be wrapped
- * @throws NullPointerException if {@code resultSet} is {@code null}
- * @throws SQLException if the metadata for this result set cannot be introspected
- */
- public RowSetDynaClass(final ResultSet resultSet) throws SQLException {
- this(resultSet, true, -1);
- }
- /**
- * <p>
- * Constructs a new {@link RowSetDynaClass} for the specified {@code ResultSet}. The property names corresponding to the column names in the result set will
- * be lower cased or not, depending on the specified {@code lowerCase} value.
- * </p>
- *
- * If {@code limit</code> is not less than 0, max <code>limit} number of rows will be copied into the resultset.
- *
- *
- * @param resultSet The result set to be wrapped
- * @param lowerCase Should property names be lower cased?
- * @throws NullPointerException if {@code resultSet} is {@code null}
- * @throws SQLException if the metadata for this result set cannot be introspected
- */
- public RowSetDynaClass(final ResultSet resultSet, final boolean lowerCase) throws SQLException {
- this(resultSet, lowerCase, -1);
- }
- /**
- * <p>
- * Constructs a new {@link RowSetDynaClass} for the specified {@code ResultSet}. The property names corresponding to the column names in the result set will
- * be lower cased or not, depending on the specified {@code lowerCase} value.
- * </p>
- *
- * <p>
- * <strong>WARNING</strong> - If you specify {@code false} for {@code lowerCase}, the returned property names will exactly match the column names returned
- * by your JDBC driver. Because different drivers might return column names in different cases, the property names seen by your application will vary
- * depending on which JDBC driver you are using.
- * </p>
- *
- * @param resultSet The result set to be wrapped
- * @param lowerCase Should property names be lower cased?
- * @param useColumnLabel true if the column label should be used, otherwise false
- * @throws NullPointerException if {@code resultSet} is {@code null}
- * @throws SQLException if the metadata for this result set cannot be introspected
- * @since 1.8.3
- */
- public RowSetDynaClass(final ResultSet resultSet, final boolean lowerCase, final boolean useColumnLabel) throws SQLException {
- this(resultSet, lowerCase, -1, useColumnLabel);
- }
- /**
- * <p>
- * Constructs a new {@link RowSetDynaClass} for the specified {@code ResultSet}. The property names corresponding to the column names in the result set will
- * be lower cased or not, depending on the specified {@code lowerCase} value.
- * </p>
- *
- * <p>
- * <strong>WARNING</strong> - If you specify {@code false} for {@code lowerCase}, the returned property names will exactly match the column names returned
- * by your JDBC driver. Because different drivers might return column names in different cases, the property names seen by your application will vary
- * depending on which JDBC driver you are using.
- * </p>
- *
- * @param resultSet The result set to be wrapped
- * @param lowerCase Should property names be lower cased?
- * @param limit Maximum limit for the {@code List} of {@link DynaBean}
- * @throws NullPointerException if {@code resultSet} is {@code null}
- * @throws SQLException if the metadata for this result set cannot be introspected
- */
- public RowSetDynaClass(final ResultSet resultSet, final boolean lowerCase, final int limit) throws SQLException {
- this(resultSet, lowerCase, limit, false);
- }
- /**
- * <p>
- * Constructs a new {@link RowSetDynaClass} for the specified {@code ResultSet}. The property names corresponding to the column names in the result set will
- * be lower cased or not, depending on the specified {@code lowerCase} value.
- * </p>
- *
- * <p>
- * <strong>WARNING</strong> - If you specify {@code false} for {@code lowerCase}, the returned property names will exactly match the column names returned
- * by your JDBC driver. Because different drivers might return column names in different cases, the property names seen by your application will vary
- * depending on which JDBC driver you are using.
- * </p>
- *
- * @param resultSet The result set to be wrapped
- * @param lowerCase Should property names be lower cased?
- * @param limit Maximum limit for the {@code List} of {@link DynaBean}
- * @param useColumnLabel true if the column label should be used, otherwise false
- * @throws NullPointerException if {@code resultSet} is {@code null}
- * @throws SQLException if the metadata for this result set cannot be introspected
- * @since 1.8.3
- */
- @SuppressWarnings("resource") // resultSet is not allocated here
- public RowSetDynaClass(final ResultSet resultSet, final boolean lowerCase, final int limit, final boolean useColumnLabel) throws SQLException {
- Objects.requireNonNull(resultSet, "resultSet");
- this.lowerCase = lowerCase;
- this.limit = limit;
- setUseColumnLabel(useColumnLabel);
- introspect(resultSet);
- copy(resultSet);
- }
- /**
- * <p>
- * Constructs a new {@link RowSetDynaClass} for the specified {@code ResultSet}. The property names corresponding to column names in the result set will be
- * lower cased.
- * </p>
- *
- * If {@code limit</code> is not less than 0, max <code>limit} number of rows will be copied into the list.
- *
- * @param resultSet The result set to be wrapped
- * @param limit The maximum for the size of the result.
- * @throws NullPointerException if {@code resultSet} is {@code null}
- * @throws SQLException if the metadata for this result set cannot be introspected
- */
- public RowSetDynaClass(final ResultSet resultSet, final int limit) throws SQLException {
- this(resultSet, true, limit);
- }
- /**
- * <p>
- * Copy the column values for each row in the specified {@code ResultSet} into a newly created {@link DynaBean}, and add this bean to the list of
- * {@link DynaBean}s that will later by returned by a call to {@code getRows()}.
- * </p>
- *
- * @param resultSet The {@code ResultSet} whose data is to be copied
- * @throws SQLException if an error is encountered copying the data
- */
- protected void copy(final ResultSet resultSet) throws SQLException {
- int cnt = 0;
- while (resultSet.next() && (limit < 0 || cnt++ < limit)) {
- final DynaBean bean = createDynaBean();
- for (final DynaProperty property : properties) {
- final String name = property.getName();
- final Object value = getObject(resultSet, name);
- bean.set(name, value);
- }
- rows.add(bean);
- }
- }
- /**
- * <p>
- * Create and return a new {@link DynaBean} instance to be used for representing a row in the underlying result set.
- * </p>
- *
- * @return A new {@code DynaBean} instance
- */
- protected DynaBean createDynaBean() {
- return new BasicDynaBean(this);
- }
- /**
- * <p>
- * Gets a {@code List} containing the {@link DynaBean}s that represent the contents of each {@code Row} from the {@code ResultSet} that was the basis of
- * this {@link RowSetDynaClass} instance. These {@link DynaBean}s are disconnected from the database itself, so there is no problem with modifying the
- * contents of the list, or the values of the properties of these {@link DynaBean}s. However, it is the application's responsibility to persist any such
- * changes back to the database, if it so desires.
- * </p>
- *
- * @return A {@code List} of {@link DynaBean} instances
- */
- public List<DynaBean> getRows() {
- return this.rows;
- }
- }